aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:01:31 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:01:31 +0000
commit176892ed88d3814500a0c610325b13af8a9f4b15 (patch)
treec527ec0940e792db8cf6d839c2c6525d2e3a325a
parent859e5f9beab0d02c324a1f6bdf869d281bdb0673 (diff)
parentcd3b5ac62e070c8a3bccc1a0495eaa742438c252 (diff)
downloaddagger2-android14-mainline-permission-release.tar.gz
Change-Id: I2717e250d4383323ce44e8584258ecce15e65adf
-rw-r--r--.github/actions/artifact-android-emulator-tests/action.yml39
-rw-r--r--.github/actions/artifact-android-local-tests/action.yml36
-rw-r--r--.github/actions/artifact-java-local-tests/action.yml25
-rw-r--r--.github/actions/bazel-build/action.yml39
-rw-r--r--.github/actions/bazel-test/action.yml55
-rw-r--r--.github/actions/build-gradle-plugin/action.yml56
-rw-r--r--.github/actions/prechecks/action.yml20
-rw-r--r--.github/actions/test-gradle-plugin/action.yml54
-rw-r--r--.github/workflows/ci.yml255
-rw-r--r--.github/workflows/release.yml142
-rw-r--r--Android.bp65
-rw-r--r--BUILD4
-rw-r--r--CONTRIBUTING.md4
l---------LICENSE1
-rw-r--r--METADATA4
-rw-r--r--NOTICE202
-rw-r--r--OWNERS2
-rw-r--r--README.md4
-rw-r--r--WORKSPACE147
-rwxr-xr-xandroid-annotation-stubs/gen_annotations.sh7
-rw-r--r--android-annotation-stubs/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessorType.java7
-rw-r--r--examples/bazel/WORKSPACE4
-rw-r--r--jarjar-rules.txt3
-rw-r--r--java/dagger/BUILD6
-rw-r--r--java/dagger/Component.java46
-rw-r--r--java/dagger/Module.java11
-rw-r--r--java/dagger/Provides.java18
-rw-r--r--java/dagger/android/BUILD16
-rw-r--r--java/dagger/android/internal/proguard/BUILD2
-rw-r--r--java/dagger/android/processor/AndroidInjectorDescriptor.java38
-rw-r--r--java/dagger/android/processor/AndroidMapKeyValidator.java64
-rw-r--r--java/dagger/android/processor/AndroidMapKeys.java3
-rw-r--r--java/dagger/android/processor/AndroidProcessor.java2
-rw-r--r--java/dagger/android/processor/BUILD35
-rw-r--r--java/dagger/android/processor/ContributesAndroidInjectorGenerator.java55
-rw-r--r--java/dagger/android/processor/DuplicateAndroidInjectorsChecker.java11
-rw-r--r--java/dagger/android/processor/MoreDaggerElements.java61
-rw-r--r--java/dagger/android/processor/MoreDaggerTypes.java114
-rw-r--r--java/dagger/android/processor/TypeNames.java54
-rw-r--r--java/dagger/android/support/BUILD4
-rw-r--r--java/dagger/errorprone/BUILD4
-rw-r--r--java/dagger/example/gradle/android/simple/app/build.gradle41
-rw-r--r--java/dagger/example/gradle/android/simple/app/src/main/AndroidManifest.xml30
-rw-r--r--java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/SimpleActivity.java73
-rw-r--r--java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/SimpleApplication.java61
-rw-r--r--java/dagger/example/gradle/android/simple/app/src/main/res/layout/activity_main.xml30
-rw-r--r--java/dagger/example/gradle/android/simple/app/src/main/res/values/strings.xml5
-rw-r--r--java/dagger/example/gradle/android/simple/gradle.properties1
-rw-r--r--java/dagger/example/gradle/android/simple/settings.gradle2
-rw-r--r--java/dagger/example/spi/BUILD12
-rw-r--r--java/dagger/grpc/server/BUILD20
-rw-r--r--java/dagger/grpc/server/processor/BUILD16
-rw-r--r--java/dagger/hilt/BUILD6
-rw-r--r--java/dagger/hilt/android/BUILD49
-rw-r--r--java/dagger/hilt/android/EarlyEntryPoints.java10
-rw-r--r--java/dagger/hilt/android/EntryPointAccessors.java67
-rw-r--r--java/dagger/hilt/android/EntryPointAccessors.kt88
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/build.gradle76
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SettingsActivityEmulatorTest.java60
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SimpleActivityEmulatorTest.java59
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SimpleEmulatorTestRunner.java32
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/debug/AndroidManifest.xml33
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/main/AndroidManifest.xml35
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SettingsActivity.java40
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SettingsGreeter.java38
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleActivity.java51
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/UserName.java29
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/UserNameModule.java34
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/main/res/layout/activity_main.xml46
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/main/res/layout/activity_settings.xml12
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/main/res/values/strings.xml17
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/ActivityScenarioRuleTest.java65
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/BindValueTest.java155
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/Injection1Test.java100
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/Injection2Test.java90
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/ModuleTest.java157
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/test/java/dagger/hilt/android/example/gradle/simple/SettingsActivityTest.java76
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/test/java/dagger/hilt/android/example/gradle/simple/SimpleActivityTest.java63
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/app/src/test/resources/dagger/hilt/android/example/gradle/simple/robolectric.properties2
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/build.gradle41
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/feature/src/main/AndroidManifest.xml9
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureActivity.kt46
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureModule.kt31
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/feature/src/main/res/layout/activity_feature.xml38
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/gradle.properties2
-rw-r--r--java/dagger/hilt/android/example/gradle/simple/settings.gradle3
-rw-r--r--java/dagger/hilt/android/example/gradle/simpleKotlin/app/build.gradle58
-rw-r--r--java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/AndroidManifest.xml35
-rw-r--r--java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/ActivityModule.kt31
-rw-r--r--java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/ApplicationModule.kt33
-rw-r--r--java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/MainActivity.kt46
-rw-r--r--java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/res/layout/activity_main.xml30
-rw-r--r--java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/test/java/dagger/hilt/android/example/gradle/simpleKotlin/SimpleTest.kt71
-rw-r--r--java/dagger/hilt/android/example/gradle/simpleKotlin/gradle.properties2
-rw-r--r--java/dagger/hilt/android/example/gradle/simpleKotlin/gradle/wrapper/gradle-wrapper.jarbin55616 -> 0 bytes
-rw-r--r--java/dagger/hilt/android/example/gradle/simpleKotlin/gradle/wrapper/gradle-wrapper.properties5
-rwxr-xr-xjava/dagger/hilt/android/example/gradle/simpleKotlin/gradlew188
-rw-r--r--java/dagger/hilt/android/example/gradle/simpleKotlin/settings.gradle2
-rw-r--r--java/dagger/hilt/android/flags/BUILD40
-rw-r--r--java/dagger/hilt/android/flags/FragmentGetContextFix.java99
-rw-r--r--java/dagger/hilt/android/flags/package-info.java27
-rw-r--r--java/dagger/hilt/android/internal/BUILD5
-rw-r--r--java/dagger/hilt/android/internal/Contexts.java47
-rw-r--r--java/dagger/hilt/android/internal/legacy/AggregatedElementProxy.java (renamed from java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/Model.java)25
-rw-r--r--java/dagger/hilt/android/internal/legacy/BUILD23
-rw-r--r--java/dagger/hilt/android/internal/lifecycle/DefaultViewModelFactories.java4
-rw-r--r--java/dagger/hilt/android/internal/lifecycle/HiltViewModelFactory.java6
-rw-r--r--java/dagger/hilt/android/internal/managers/ActivityRetainedComponentManager.java17
-rw-r--r--java/dagger/hilt/android/internal/managers/BUILD1
-rw-r--r--java/dagger/hilt/android/internal/managers/BroadcastReceiverComponentManager.java5
-rw-r--r--java/dagger/hilt/android/internal/managers/ViewComponentManager.java11
-rw-r--r--java/dagger/hilt/android/internal/migration/BUILD5
-rw-r--r--java/dagger/hilt/android/internal/migration/HasCustomInject.java (renamed from java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/UserName.kt)15
-rw-r--r--java/dagger/hilt/android/internal/modules/ApplicationContextModule.java3
-rw-r--r--java/dagger/hilt/android/internal/modules/BUILD1
-rw-r--r--java/dagger/hilt/android/internal/testing/BUILD1
-rw-r--r--java/dagger/hilt/android/internal/testing/EarlySingletonComponentCreator.java28
-rw-r--r--java/dagger/hilt/android/internal/testing/MarkThatRulesRanRule.java23
-rw-r--r--java/dagger/hilt/android/internal/testing/TestApplicationComponentManager.java10
-rw-r--r--java/dagger/hilt/android/internal/testing/TestComponentDataSupplier.java35
-rw-r--r--java/dagger/hilt/android/lifecycle/proguard-rules.pro2
-rw-r--r--java/dagger/hilt/android/migration/BUILD19
-rw-r--r--java/dagger/hilt/android/migration/CustomInject.java55
-rw-r--r--java/dagger/hilt/android/migration/CustomInjection.java43
-rw-r--r--java/dagger/hilt/android/migration/OptionalInjectCheck.java2
-rw-r--r--java/dagger/hilt/android/plugin/BUILD8
-rw-r--r--java/dagger/hilt/android/plugin/build.gradle231
-rw-r--r--java/dagger/hilt/android/plugin/gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassTransformer.kt6
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassVisitor.kt50
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointTransform.kt2
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltExtension.kt23
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt345
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/AggregatedAnnotation.kt63
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/AggregatedElementProxyGenerator.kt49
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/Aggregator.kt419
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/ComponentTreeDepsGenerator.kt70
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/ProcessedRootSentinelGenerator.kt53
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/task/AggregateDepsTask.kt134
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/task/HiltTransformTestClassesTask.kt (renamed from java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltTransformTestClassesTask.kt)27
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/AggregatedPackagesTransform.kt98
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidGradleCompat.kt225
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/CopyTransform.kt7
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/Files.kt55
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/SimpleAGPVersion.kt6
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/Strings.kt (renamed from java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/Model.kt)15
-rw-r--r--java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/Tasks.kt16
-rw-r--r--java/dagger/hilt/android/plugin/src/main/resources/META-INF/gradle-plugins/com.google.dagger.hilt.android.properties1
-rw-r--r--java/dagger/hilt/android/plugin/src/test/data/flavored-project/app/build.gradle66
-rw-r--r--java/dagger/hilt/android/plugin/src/test/data/flavored-project/app/src/main/AndroidManifest.xml (renamed from java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/res/values/strings.xml)15
-rw-r--r--java/dagger/hilt/android/plugin/src/test/data/flavored-project/app/src/main/java/simple/app/SimpleApp.java (renamed from javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/App.kt)12
-rw-r--r--java/dagger/hilt/android/plugin/src/test/data/flavored-project/build.gradle (renamed from java/dagger/example/gradle/android/simple/build.gradle)17
-rw-r--r--java/dagger/hilt/android/plugin/src/test/data/flavored-project/feature/build.gradle60
-rw-r--r--java/dagger/hilt/android/plugin/src/test/data/flavored-project/feature/src/main/AndroidManifest.xml (renamed from javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/res/values/strings.xml)10
-rw-r--r--java/dagger/hilt/android/plugin/src/test/data/flavored-project/feature/src/main/java/simple/library/LibraryCode.java (renamed from java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureCounter.kt)8
-rw-r--r--java/dagger/hilt/android/plugin/src/test/data/flavored-project/gradle.properties1
-rw-r--r--java/dagger/hilt/android/plugin/src/test/data/flavored-project/settings.gradle3
-rw-r--r--java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity1.java4
-rw-r--r--java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity2.java4
-rw-r--r--java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/SimpleApp.java4
-rw-r--r--java/dagger/hilt/android/plugin/src/test/data/simple-project/src/test/java/simple/Test1.java58
-rw-r--r--java/dagger/hilt/android/plugin/src/test/data/simple-project/src/test/java/simple/Test2.java55
-rw-r--r--java/dagger/hilt/android/plugin/src/test/kotlin/BuildCacheTest.kt123
-rw-r--r--java/dagger/hilt/android/plugin/src/test/kotlin/CompileClasspathTest.kt25
-rw-r--r--java/dagger/hilt/android/plugin/src/test/kotlin/CrossCompilationRootValidationTest.kt116
-rw-r--r--java/dagger/hilt/android/plugin/src/test/kotlin/GradleTestRunner.kt24
-rw-r--r--java/dagger/hilt/android/plugin/src/test/kotlin/IncrementalProcessorTest.kt1032
-rw-r--r--java/dagger/hilt/android/plugin/src/test/kotlin/NoTransformTest.kt52
-rw-r--r--java/dagger/hilt/android/plugin/src/test/kotlin/TransformTest.kt96
-rw-r--r--java/dagger/hilt/android/plugin/src/test/kotlin/VariantsConfigurationTest.kt63
-rw-r--r--java/dagger/hilt/android/processor/BUILD11
-rw-r--r--java/dagger/hilt/android/processor/internal/AndroidClassNames.java9
-rw-r--r--java/dagger/hilt/android/processor/internal/BUILD6
-rw-r--r--java/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGenerator.java14
-rw-r--r--java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java3
-rw-r--r--java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessor.java26
-rw-r--r--java/dagger/hilt/android/processor/internal/androidentrypoint/ApplicationGenerator.java86
-rw-r--r--java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD28
-rw-r--r--java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java1
-rw-r--r--java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java86
-rw-r--r--java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java101
-rw-r--r--java/dagger/hilt/android/processor/internal/androidentrypoint/InjectorEntryPointGenerator.java1
-rw-r--r--java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java1
-rw-r--r--java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java6
-rw-r--r--java/dagger/hilt/android/processor/internal/bindvalue/BUILD18
-rw-r--r--java/dagger/hilt/android/processor/internal/bindvalue/BindValueMetadata.java3
-rw-r--r--java/dagger/hilt/android/processor/internal/customtestapplication/BUILD14
-rw-r--r--java/dagger/hilt/android/processor/internal/viewmodel/BUILD18
-rw-r--r--java/dagger/hilt/android/qualifiers/BUILD2
-rw-r--r--java/dagger/hilt/android/scopes/BUILD2
-rw-r--r--java/dagger/hilt/android/testing/BUILD14
-rw-r--r--java/dagger/hilt/android/testing/OnComponentReadyRunner.java3
-rw-r--r--java/dagger/hilt/android/testing/compile/BUILD (renamed from javatests/dagger/hilt/android/processor/BUILD)13
-rw-r--r--java/dagger/hilt/android/testing/compile/HiltCompilerTests.java (renamed from javatests/dagger/hilt/android/processor/AndroidCompilers.java)24
-rw-r--r--java/dagger/hilt/components/BUILD2
-rw-r--r--java/dagger/hilt/internal/aggregatedroot/AggregatedRoot.java2
-rw-r--r--java/dagger/hilt/internal/aliasof/AliasOfPropagatedData.java2
-rw-r--r--java/dagger/hilt/internal/componenttreedeps/BUILD (renamed from java/dagger/hilt/android/example/BUILD)17
-rw-r--r--java/dagger/hilt/internal/componenttreedeps/ComponentTreeDeps.java55
-rw-r--r--java/dagger/hilt/migration/AliasOf.java4
-rw-r--r--java/dagger/hilt/migration/BUILD2
-rw-r--r--java/dagger/hilt/processor/BUILD14
-rw-r--r--java/dagger/hilt/processor/internal/AggregatedElements.java34
-rw-r--r--java/dagger/hilt/processor/internal/BUILD65
-rw-r--r--java/dagger/hilt/processor/internal/BaseProcessor.java12
-rw-r--r--java/dagger/hilt/processor/internal/ClassNames.java10
-rw-r--r--java/dagger/hilt/processor/internal/ComponentNames.java141
-rw-r--r--java/dagger/hilt/processor/internal/HiltCompilerOptions.java62
-rw-r--r--java/dagger/hilt/processor/internal/Processors.java18
-rw-r--r--java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java59
-rw-r--r--java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java18
-rw-r--r--java/dagger/hilt/processor/internal/aggregateddeps/BUILD25
-rw-r--r--java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java229
-rw-r--r--java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java12
-rw-r--r--java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java13
-rw-r--r--java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java21
-rw-r--r--java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataMetadata.java55
-rw-r--r--java/dagger/hilt/processor/internal/aliasof/AliasOfs.java45
-rw-r--r--java/dagger/hilt/processor/internal/aliasof/BUILD18
-rw-r--r--java/dagger/hilt/processor/internal/definecomponent/BUILD20
-rw-r--r--java/dagger/hilt/processor/internal/definecomponent/DefineComponentClassesMetadata.java32
-rw-r--r--java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java7
-rw-r--r--java/dagger/hilt/processor/internal/disableinstallincheck/BUILD6
-rw-r--r--java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointMetadata.java29
-rw-r--r--java/dagger/hilt/processor/internal/earlyentrypoint/BUILD16
-rw-r--r--java/dagger/hilt/processor/internal/generatesrootinput/BUILD14
-rw-r--r--java/dagger/hilt/processor/internal/originatingelement/BUILD8
-rw-r--r--java/dagger/hilt/processor/internal/root/AggregatedRootGenerator.java8
-rw-r--r--java/dagger/hilt/processor/internal/root/AggregatedRootMetadata.java63
-rw-r--r--java/dagger/hilt/processor/internal/root/BUILD94
-rw-r--r--java/dagger/hilt/processor/internal/root/ComponentTreeDepsGenerator.java117
-rw-r--r--java/dagger/hilt/processor/internal/root/ComponentTreeDepsMetadata.java127
-rw-r--r--java/dagger/hilt/processor/internal/root/ComponentTreeDepsProcessor.java204
-rw-r--r--java/dagger/hilt/processor/internal/root/EarlySingletonComponentCreatorGenerator.java4
-rw-r--r--java/dagger/hilt/processor/internal/root/ProcessedRootSentinelMetadata.java14
-rw-r--r--java/dagger/hilt/processor/internal/root/Root.java20
-rw-r--r--java/dagger/hilt/processor/internal/root/RootGenerator.java26
-rw-r--r--java/dagger/hilt/processor/internal/root/RootMetadata.java79
-rw-r--r--java/dagger/hilt/processor/internal/root/RootProcessor.java317
-rw-r--r--java/dagger/hilt/processor/internal/root/RootType.java10
-rw-r--r--java/dagger/hilt/processor/internal/root/TestComponentDataGenerator.java19
-rw-r--r--java/dagger/hilt/processor/internal/root/ir/AggregatedRootIrValidator.kt82
-rw-r--r--java/dagger/hilt/processor/internal/root/ir/BUILD52
-rw-r--r--java/dagger/hilt/processor/internal/root/ir/ComponentTreeDepsIrCreator.kt260
-rw-r--r--java/dagger/hilt/processor/internal/root/ir/MetadataIr.kt102
-rw-r--r--java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesMetadata.java31
-rw-r--r--java/dagger/hilt/processor/internal/uninstallmodules/BUILD16
-rw-r--r--java/dagger/hilt/testing/BUILD2
-rw-r--r--java/dagger/internal/DoubleCheck.java7
-rw-r--r--java/dagger/internal/QualifierMetadata.java40
-rw-r--r--java/dagger/internal/ScopeMetadata.java (renamed from java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/Model.java)22
-rw-r--r--java/dagger/internal/codegen/AssistedFactoryProcessingStep.java126
-rw-r--r--java/dagger/internal/codegen/AssistedInjectProcessingStep.java53
-rw-r--r--java/dagger/internal/codegen/AssistedProcessingStep.java79
-rw-r--r--java/dagger/internal/codegen/BUILD33
-rw-r--r--java/dagger/internal/codegen/ComponentHjarProcessingStep.java30
-rw-r--r--java/dagger/internal/codegen/ComponentProcessingStep.java41
-rw-r--r--java/dagger/internal/codegen/ComponentProcessor.java71
-rw-r--r--java/dagger/internal/codegen/InjectProcessingStep.java66
-rw-r--r--java/dagger/internal/codegen/MapKeyProcessingStep.java51
-rw-r--r--java/dagger/internal/codegen/ModuleProcessingStep.java90
-rw-r--r--java/dagger/internal/codegen/ProcessingEnvironmentModule.java53
-rw-r--r--java/dagger/internal/codegen/ProcessingRoundCacheModule.java5
-rw-r--r--java/dagger/internal/codegen/ServiceLoaders.java37
-rw-r--r--java/dagger/internal/codegen/SourceFileGeneratorsModule.java4
-rw-r--r--java/dagger/internal/codegen/SpiModule.java61
-rw-r--r--java/dagger/internal/codegen/base/BUILD24
-rw-r--r--java/dagger/internal/codegen/base/ComponentAnnotation.java326
-rw-r--r--java/dagger/internal/codegen/base/ComponentCreatorAnnotation.java (renamed from java/dagger/internal/codegen/binding/ComponentCreatorAnnotation.java)70
-rw-r--r--java/dagger/internal/codegen/base/ComponentCreatorKind.java (renamed from java/dagger/internal/codegen/binding/ComponentCreatorKind.java)2
-rw-r--r--java/dagger/internal/codegen/base/ComponentKind.java100
-rw-r--r--java/dagger/internal/codegen/base/ContributionType.java13
-rw-r--r--java/dagger/internal/codegen/base/DaggerSuperficialValidation.java823
-rw-r--r--java/dagger/internal/codegen/base/ElementFormatter.java13
-rw-r--r--java/dagger/internal/codegen/base/FrameworkTypes.java38
-rw-r--r--java/dagger/internal/codegen/base/Keys.java86
-rw-r--r--java/dagger/internal/codegen/base/MapType.java106
-rw-r--r--java/dagger/internal/codegen/base/ModuleAnnotation.java95
-rw-r--r--java/dagger/internal/codegen/base/ModuleKind.java (renamed from java/dagger/internal/codegen/binding/ModuleKind.java)47
-rw-r--r--java/dagger/internal/codegen/base/MoreAnnotationMirrors.java25
-rw-r--r--java/dagger/internal/codegen/base/MoreAnnotationValues.java23
-rw-r--r--java/dagger/internal/codegen/base/MultibindingAnnotations.java36
-rw-r--r--java/dagger/internal/codegen/base/OptionalType.java105
-rw-r--r--java/dagger/internal/codegen/base/ProducerAnnotations.java67
-rw-r--r--java/dagger/internal/codegen/base/RequestKinds.java85
-rw-r--r--java/dagger/internal/codegen/base/Scopes.java51
-rw-r--r--java/dagger/internal/codegen/base/SetType.java99
-rw-r--r--java/dagger/internal/codegen/base/SimpleAnnotationMirror.java107
-rw-r--r--java/dagger/internal/codegen/base/SimpleTypeAnnotationValue.java45
-rw-r--r--java/dagger/internal/codegen/base/SourceFileGenerationException.java10
-rw-r--r--java/dagger/internal/codegen/base/SourceFileGenerator.java27
-rw-r--r--java/dagger/internal/codegen/base/TarjanSCCs.java110
-rw-r--r--java/dagger/internal/codegen/binding/AnnotationExpression.java51
-rw-r--r--java/dagger/internal/codegen/binding/AssistedInjectionAnnotations.java210
-rw-r--r--java/dagger/internal/codegen/binding/BUILD19
-rw-r--r--java/dagger/internal/codegen/binding/Binding.java66
-rw-r--r--java/dagger/internal/codegen/binding/BindingDeclaration.java27
-rw-r--r--java/dagger/internal/codegen/binding/BindingDeclarationFormatter.java58
-rw-r--r--java/dagger/internal/codegen/binding/BindingFactory.java357
-rw-r--r--java/dagger/internal/codegen/binding/BindingGraph.java241
-rw-r--r--java/dagger/internal/codegen/binding/BindingGraphConverter.java69
-rw-r--r--java/dagger/internal/codegen/binding/BindingGraphFactory.java80
-rw-r--r--java/dagger/internal/codegen/binding/BindingNode.java34
-rw-r--r--java/dagger/internal/codegen/binding/BindingRequest.java39
-rw-r--r--java/dagger/internal/codegen/binding/BindsTypeChecker.java25
-rw-r--r--java/dagger/internal/codegen/binding/ChildFactoryMethodEdgeImpl.java12
-rw-r--r--java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java123
-rw-r--r--java/dagger/internal/codegen/binding/ComponentDescriptor.java113
-rw-r--r--java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java164
-rw-r--r--java/dagger/internal/codegen/binding/ComponentKind.java171
-rw-r--r--java/dagger/internal/codegen/binding/ComponentNodeImpl.java8
-rw-r--r--java/dagger/internal/codegen/binding/ComponentRequirement.java200
-rw-r--r--java/dagger/internal/codegen/binding/ConfigurationAnnotations.java132
-rw-r--r--java/dagger/internal/codegen/binding/ContributionBinding.java123
-rw-r--r--java/dagger/internal/codegen/binding/DelegateDeclaration.java31
-rw-r--r--java/dagger/internal/codegen/binding/DependencyEdgeImpl.java6
-rw-r--r--java/dagger/internal/codegen/binding/DependencyRequestFactory.java91
-rw-r--r--java/dagger/internal/codegen/binding/DependencyRequestFormatter.java11
-rw-r--r--java/dagger/internal/codegen/binding/DependencyVariableNamer.java6
-rw-r--r--java/dagger/internal/codegen/binding/ErrorMessages.java24
-rw-r--r--java/dagger/internal/codegen/binding/FrameworkField.java19
-rw-r--r--java/dagger/internal/codegen/binding/FrameworkType.java95
-rw-r--r--java/dagger/internal/codegen/binding/FrameworkTypeMapper.java2
-rw-r--r--java/dagger/internal/codegen/binding/InjectBindingRegistry.java14
-rw-r--r--java/dagger/internal/codegen/binding/InjectionAnnotations.java358
-rw-r--r--java/dagger/internal/codegen/binding/InjectionSiteFactory.java14
-rw-r--r--java/dagger/internal/codegen/binding/KeyFactory.java292
-rw-r--r--java/dagger/internal/codegen/binding/KeyVariableNamer.java89
-rw-r--r--java/dagger/internal/codegen/binding/LegacyBindingGraph.java8
-rw-r--r--java/dagger/internal/codegen/binding/MapKeys.java110
-rw-r--r--java/dagger/internal/codegen/binding/MembersInjectionBinding.java37
-rw-r--r--java/dagger/internal/codegen/binding/MethodSignature.java52
-rw-r--r--java/dagger/internal/codegen/binding/MethodSignatureFormatter.java96
-rw-r--r--java/dagger/internal/codegen/binding/ModuleDescriptor.java189
-rw-r--r--java/dagger/internal/codegen/binding/MultibindingDeclaration.java40
-rw-r--r--java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java15
-rw-r--r--java/dagger/internal/codegen/binding/ProductionBinding.java16
-rw-r--r--java/dagger/internal/codegen/binding/ProvisionBinding.java12
-rw-r--r--java/dagger/internal/codegen/binding/ResolvedBindings.java7
-rw-r--r--java/dagger/internal/codegen/binding/SourceFiles.java86
-rw-r--r--java/dagger/internal/codegen/binding/SubcomponentCreatorBindingEdgeImpl.java14
-rw-r--r--java/dagger/internal/codegen/binding/SubcomponentDeclaration.java33
-rw-r--r--java/dagger/internal/codegen/bindinggraphvalidation/BUILD16
-rw-r--r--java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java8
-rw-r--r--java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java47
-rw-r--r--java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java13
-rw-r--r--java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java38
-rw-r--r--java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java47
-rw-r--r--java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java26
-rw-r--r--java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java63
-rw-r--r--java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java144
-rw-r--r--java/dagger/internal/codegen/bindinggraphvalidation/NullableBindingValidator.java15
-rw-r--r--java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java20
-rw-r--r--java/dagger/internal/codegen/bindinggraphvalidation/SetMultibindingValidator.java99
-rw-r--r--java/dagger/internal/codegen/bindinggraphvalidation/SubcomponentFactoryMethodValidator.java64
-rw-r--r--java/dagger/internal/codegen/bootstrap/bootstrap_compiler_deploy.jarbin7279147 -> 10401292 bytes
-rw-r--r--java/dagger/internal/codegen/compileroption/BUILD12
-rw-r--r--java/dagger/internal/codegen/compileroption/CompilerOptions.java46
-rw-r--r--java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java130
-rw-r--r--java/dagger/internal/codegen/componentgenerator/BUILD16
-rw-r--r--java/dagger/internal/codegen/componentgenerator/ComponentGenerator.java40
-rw-r--r--java/dagger/internal/codegen/componentgenerator/ComponentHjarGenerator.java107
-rw-r--r--java/dagger/internal/codegen/componentgenerator/ComponentImplementationBuilder.java524
-rw-r--r--java/dagger/internal/codegen/componentgenerator/ComponentImplementationFactory.java72
-rw-r--r--java/dagger/internal/codegen/componentgenerator/CurrentImplementationSubcomponent.java41
-rw-r--r--java/dagger/internal/codegen/componentgenerator/MethodSignature.java56
-rw-r--r--java/dagger/internal/codegen/componentgenerator/TopLevelImplementationComponent.java9
-rw-r--r--java/dagger/internal/codegen/extension/BUILD8
-rw-r--r--java/dagger/internal/codegen/javac/BUILD2
-rw-r--r--java/dagger/internal/codegen/javac/JavacPluginCompilerOptions.java (renamed from java/dagger/internal/codegen/compileroption/JavacPluginCompilerOptions.java)27
-rw-r--r--java/dagger/internal/codegen/javac/JavacPluginModule.java79
-rw-r--r--java/dagger/internal/codegen/javac/JavacPluginProcessingEnvironment.java141
-rw-r--r--java/dagger/internal/codegen/javapoet/BUILD12
-rw-r--r--java/dagger/internal/codegen/javapoet/CodeBlocks.java5
-rw-r--r--java/dagger/internal/codegen/javapoet/Expression.java23
-rw-r--r--java/dagger/internal/codegen/javapoet/TypeNames.java207
-rw-r--r--java/dagger/internal/codegen/javapoet/TypeSpecs.java23
-rw-r--r--java/dagger/internal/codegen/kotlin/BUILD13
-rw-r--r--java/dagger/internal/codegen/kotlin/KotlinMetadata.java4
-rw-r--r--java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java25
-rw-r--r--java/dagger/internal/codegen/kythe/BUILD8
-rw-r--r--java/dagger/internal/codegen/kythe/DaggerKythePlugin.java43
-rw-r--r--java/dagger/internal/codegen/langmodel/Accessibility.java119
-rw-r--r--java/dagger/internal/codegen/langmodel/BUILD14
-rw-r--r--java/dagger/internal/codegen/langmodel/DaggerElements.java213
-rw-r--r--java/dagger/internal/codegen/langmodel/DaggerTypes.java207
-rw-r--r--java/dagger/internal/codegen/validation/AnyBindingMethodValidator.java44
-rw-r--r--java/dagger/internal/codegen/validation/BUILD25
-rw-r--r--java/dagger/internal/codegen/validation/BindingElementValidator.java162
-rw-r--r--java/dagger/internal/codegen/validation/BindingGraphValidator.java55
-rw-r--r--java/dagger/internal/codegen/validation/BindingMethodProcessingStep.java21
-rw-r--r--java/dagger/internal/codegen/validation/BindingMethodValidator.java109
-rw-r--r--java/dagger/internal/codegen/validation/BindingMethodValidatorsModule.java4
-rw-r--r--java/dagger/internal/codegen/validation/BindsInstanceElementValidator.java7
-rw-r--r--java/dagger/internal/codegen/validation/BindsInstanceMethodValidator.java51
-rw-r--r--java/dagger/internal/codegen/validation/BindsInstanceParameterValidator.java49
-rw-r--r--java/dagger/internal/codegen/validation/BindsInstanceProcessingStep.java43
-rw-r--r--java/dagger/internal/codegen/validation/BindsMethodValidator.java67
-rw-r--r--java/dagger/internal/codegen/validation/BindsOptionalOfMethodValidator.java44
-rw-r--r--java/dagger/internal/codegen/validation/ComponentCreatorValidator.java194
-rw-r--r--java/dagger/internal/codegen/validation/ComponentDescriptorValidator.java172
-rw-r--r--java/dagger/internal/codegen/validation/ComponentHierarchyValidator.java59
-rw-r--r--java/dagger/internal/codegen/validation/ComponentValidator.java406
-rw-r--r--java/dagger/internal/codegen/validation/CompositeBindingGraphPlugin.java26
-rw-r--r--java/dagger/internal/codegen/validation/DependencyRequestValidator.java125
-rw-r--r--java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java44
-rw-r--r--java/dagger/internal/codegen/validation/DiagnosticReporterFactory.java56
-rw-r--r--java/dagger/internal/codegen/validation/ExternalBindingGraphConverter.java432
-rw-r--r--java/dagger/internal/codegen/validation/ExternalBindingGraphPlugins.java (renamed from java/dagger/internal/codegen/validation/BindingGraphPlugins.java)45
-rw-r--r--java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java170
-rw-r--r--java/dagger/internal/codegen/validation/InjectValidator.java349
-rw-r--r--java/dagger/internal/codegen/validation/MapKeyValidator.java31
-rw-r--r--java/dagger/internal/codegen/validation/MembersInjectionValidator.java140
-rw-r--r--java/dagger/internal/codegen/validation/ModuleValidator.java632
-rw-r--r--java/dagger/internal/codegen/validation/MonitoringModuleGenerator.java35
-rw-r--r--java/dagger/internal/codegen/validation/MonitoringModuleProcessingStep.java29
-rw-r--r--java/dagger/internal/codegen/validation/MultibindingAnnotationsProcessingStep.java34
-rw-r--r--java/dagger/internal/codegen/validation/MultibindsMethodValidator.java48
-rw-r--r--java/dagger/internal/codegen/validation/ProducesMethodValidator.java67
-rw-r--r--java/dagger/internal/codegen/validation/ProvidesMethodValidator.java36
-rw-r--r--java/dagger/internal/codegen/validation/SuperficialValidator.java69
-rw-r--r--java/dagger/internal/codegen/validation/TypeCheckingProcessingStep.java165
-rw-r--r--java/dagger/internal/codegen/validation/TypeHierarchyValidator.java56
-rw-r--r--java/dagger/internal/codegen/validation/Validation.java4
-rw-r--r--java/dagger/internal/codegen/validation/ValidationBindingGraphPlugins.java106
-rw-r--r--java/dagger/internal/codegen/validation/ValidationReport.java150
-rw-r--r--java/dagger/internal/codegen/writing/AnnotationCreatorGenerator.java68
-rw-r--r--java/dagger/internal/codegen/writing/AnonymousProviderCreationExpression.java28
-rw-r--r--java/dagger/internal/codegen/writing/AssistedFactoryBindingExpression.java111
-rw-r--r--java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java121
-rw-r--r--java/dagger/internal/codegen/writing/AssistedInjectionParameters.java102
-rw-r--r--java/dagger/internal/codegen/writing/BUILD17
-rw-r--r--java/dagger/internal/codegen/writing/BindingRepresentation.java (renamed from java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/BuildModule.java)19
-rw-r--r--java/dagger/internal/codegen/writing/BindingRepresentations.java38
-rw-r--r--java/dagger/internal/codegen/writing/ComponentBindingExpressions.java707
-rw-r--r--java/dagger/internal/codegen/writing/ComponentCreatorImplementationFactory.java (renamed from java/dagger/internal/codegen/componentgenerator/ComponentCreatorImplementationFactory.java)165
-rw-r--r--java/dagger/internal/codegen/writing/ComponentImplementation.java1155
-rw-r--r--java/dagger/internal/codegen/writing/ComponentInstanceRequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/ComponentInstanceBindingExpression.java)25
-rw-r--r--java/dagger/internal/codegen/writing/ComponentMethodRequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/ComponentMethodBindingExpression.java)65
-rw-r--r--java/dagger/internal/codegen/writing/ComponentNames.java204
-rw-r--r--java/dagger/internal/codegen/writing/ComponentProvisionRequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/ComponentProvisionBindingExpression.java)42
-rw-r--r--java/dagger/internal/codegen/writing/ComponentRequestRepresentations.java259
-rw-r--r--java/dagger/internal/codegen/writing/ComponentRequirementExpression.java4
-rw-r--r--java/dagger/internal/codegen/writing/ComponentRequirementExpressions.java124
-rw-r--r--java/dagger/internal/codegen/writing/ComponentRequirementRequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/ComponentRequirementBindingExpression.java)23
-rw-r--r--java/dagger/internal/codegen/writing/DelegateRequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/DelegateBindingExpression.java)58
-rw-r--r--java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java29
-rw-r--r--java/dagger/internal/codegen/writing/DependencyMethodProducerCreationExpression.java25
-rw-r--r--java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java80
-rw-r--r--java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceBindingExpression.java69
-rw-r--r--java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceRequestRepresentation.java101
-rw-r--r--java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java170
-rw-r--r--java/dagger/internal/codegen/writing/ExperimentalSwitchingProviderDependencyRepresentation.java124
-rw-r--r--java/dagger/internal/codegen/writing/ExperimentalSwitchingProviders.java290
-rw-r--r--java/dagger/internal/codegen/writing/FactoryGenerator.java143
-rw-r--r--java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java55
-rw-r--r--java/dagger/internal/codegen/writing/FrameworkInstanceBindingRepresentation.java114
-rw-r--r--java/dagger/internal/codegen/writing/FrameworkInstanceKind.java111
-rw-r--r--java/dagger/internal/codegen/writing/FrameworkInstanceRequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/FrameworkInstanceBindingExpression.java)16
-rw-r--r--java/dagger/internal/codegen/writing/GwtCompatibility.java3
-rw-r--r--java/dagger/internal/codegen/writing/HjarSourceFileGenerator.java4
-rw-r--r--java/dagger/internal/codegen/writing/ImmediateFutureRequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/ImmediateFutureBindingExpression.java)42
-rw-r--r--java/dagger/internal/codegen/writing/InaccessibleMapKeyProxyGenerator.java21
-rw-r--r--java/dagger/internal/codegen/writing/InjectionMethods.java79
-rw-r--r--java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java28
-rw-r--r--java/dagger/internal/codegen/writing/InnerSwitchingProviders.java107
-rw-r--r--java/dagger/internal/codegen/writing/InstanceFactoryCreationExpression.java5
-rw-r--r--java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java60
-rw-r--r--java/dagger/internal/codegen/writing/MapRequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/MapBindingExpression.java)93
-rw-r--r--java/dagger/internal/codegen/writing/MemberSelect.java202
-rw-r--r--java/dagger/internal/codegen/writing/MembersInjectionBindingRepresentation.java55
-rw-r--r--java/dagger/internal/codegen/writing/MembersInjectionMethods.java111
-rw-r--r--java/dagger/internal/codegen/writing/MembersInjectionRequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/MembersInjectionBindingExpression.java)42
-rw-r--r--java/dagger/internal/codegen/writing/MembersInjectorGenerator.java52
-rw-r--r--java/dagger/internal/codegen/writing/MembersInjectorProviderCreationExpression.java42
-rw-r--r--java/dagger/internal/codegen/writing/MethodBindingExpression.java294
-rw-r--r--java/dagger/internal/codegen/writing/MethodRequestRepresentation.java61
-rw-r--r--java/dagger/internal/codegen/writing/ModuleProxies.java60
-rw-r--r--java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java26
-rw-r--r--java/dagger/internal/codegen/writing/OptionalFactories.java98
-rw-r--r--java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java26
-rw-r--r--java/dagger/internal/codegen/writing/OptionalRequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/OptionalBindingExpression.java)57
-rw-r--r--java/dagger/internal/codegen/writing/PrivateMethodRequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/PrivateMethodBindingExpression.java)85
-rw-r--r--java/dagger/internal/codegen/writing/ProducerCreationExpression.java23
-rw-r--r--java/dagger/internal/codegen/writing/ProducerEntryPointView.java55
-rw-r--r--java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java50
-rw-r--r--java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java36
-rw-r--r--java/dagger/internal/codegen/writing/ProducerNodeInstanceRequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/ProducerNodeInstanceBindingExpression.java)43
-rw-r--r--java/dagger/internal/codegen/writing/ProductionBindingRepresentation.java111
-rw-r--r--java/dagger/internal/codegen/writing/ProviderInstanceRequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/ProviderInstanceBindingExpression.java)24
-rw-r--r--java/dagger/internal/codegen/writing/ProviderInstanceSupplier.java58
-rw-r--r--java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java145
-rw-r--r--java/dagger/internal/codegen/writing/RequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/BindingExpression.java)7
-rw-r--r--java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java27
-rw-r--r--java/dagger/internal/codegen/writing/SetRequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/SetBindingExpression.java)76
-rw-r--r--java/dagger/internal/codegen/writing/SimpleInvocationBindingExpression.java35
-rw-r--r--java/dagger/internal/codegen/writing/SimpleMethodRequestRepresentation.java (renamed from java/dagger/internal/codegen/writing/SimpleMethodBindingExpression.java)105
-rw-r--r--java/dagger/internal/codegen/writing/StaticFactoryInstanceSupplier.java65
-rw-r--r--java/dagger/internal/codegen/writing/StaticMemberSelects.java155
-rw-r--r--java/dagger/internal/codegen/writing/SubcomponentCreatorBindingExpression.java40
-rw-r--r--java/dagger/internal/codegen/writing/SubcomponentCreatorRequestRepresentation.java80
-rw-r--r--java/dagger/internal/codegen/writing/SubcomponentNames.java156
-rw-r--r--java/dagger/internal/codegen/writing/SwitchingProviderInstanceSupplier.java84
-rw-r--r--java/dagger/internal/codegen/writing/SwitchingProviders.java133
-rw-r--r--java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java131
-rw-r--r--java/dagger/internal/codegen/writing/UnscopedFrameworkInstanceCreationExpressionFactory.java164
-rw-r--r--java/dagger/internal/codegen/writing/UnwrappedMapKeyGenerator.java10
-rw-r--r--java/dagger/internal/codegen/xprocessing/BUILD51
-rw-r--r--java/dagger/internal/codegen/xprocessing/MethodSpecs.java58
-rw-r--r--java/dagger/internal/codegen/xprocessing/XAnnotations.java40
-rw-r--r--java/dagger/internal/codegen/xprocessing/XElements.java177
-rw-r--r--java/dagger/internal/codegen/xprocessing/XMethodElements.java40
-rw-r--r--java/dagger/internal/codegen/xprocessing/XTypeElements.java96
-rw-r--r--java/dagger/internal/codegen/xprocessing/XTypes.java81
-rw-r--r--java/dagger/internal/codegen/xprocessing/xprocessing.jarbin0 -> 875642 bytes
-rw-r--r--java/dagger/internal/guava/BUILD68
-rw-r--r--java/dagger/lint/BUILD2
-rw-r--r--java/dagger/lint/DaggerIssueRegistry.kt9
-rw-r--r--java/dagger/lint/DaggerKotlinIssueDetector.kt11
-rw-r--r--java/dagger/model/BUILD32
-rw-r--r--java/dagger/model/BindingGraphProxies.java66
-rw-r--r--java/dagger/model/Key.java2
-rw-r--r--java/dagger/model/Scope.java23
-rw-r--r--java/dagger/model/testing/BUILD10
-rw-r--r--java/dagger/multibindings/ClassKey.java8
-rw-r--r--java/dagger/multibindings/IntKey.java8
-rw-r--r--java/dagger/multibindings/LongKey.java8
-rw-r--r--java/dagger/multibindings/StringKey.java8
-rw-r--r--java/dagger/producers/BUILD18
-rw-r--r--java/dagger/producers/internal/AnnotationUsages.java39
-rw-r--r--java/dagger/spi/BUILD23
-rw-r--r--java/dagger/spi/model/BUILD60
-rw-r--r--java/dagger/spi/model/Binding.java87
-rw-r--r--java/dagger/spi/model/BindingGraph.java442
-rw-r--r--java/dagger/spi/model/BindingGraphPlugin.java94
-rw-r--r--java/dagger/spi/model/BindingKind.java126
-rw-r--r--java/dagger/spi/model/CompilerEnvironment.java23
-rw-r--r--java/dagger/spi/model/ComponentPath.java105
-rw-r--r--java/dagger/spi/model/DaggerAnnotation.java66
-rw-r--r--java/dagger/spi/model/DaggerElement.java42
-rw-r--r--java/dagger/spi/model/DaggerExecutableElement.java43
-rw-r--r--java/dagger/spi/model/DaggerType.java54
-rw-r--r--java/dagger/spi/model/DaggerTypeElement.java47
-rw-r--r--java/dagger/spi/model/DependencyRequest.java76
-rw-r--r--java/dagger/spi/model/DiagnosticReporter.java103
-rw-r--r--java/dagger/spi/model/Key.java176
-rw-r--r--java/dagger/spi/model/MoreAnnotationMirrors.java102
-rw-r--r--java/dagger/spi/model/RequestKind.java85
-rw-r--r--java/dagger/spi/model/Scope.java94
-rw-r--r--java/dagger/spi/model/package-info.java31
-rw-r--r--java/dagger/spi/model/testing/BUILD39
-rw-r--r--java/dagger/spi/model/testing/BindingGraphSubject.java150
-rw-r--r--java/dagger/testing/compile/BUILD10
-rw-r--r--java/dagger/testing/compile/CompilerTests.java18
-rw-r--r--javatests/artifacts/dagger-android/simple/build.gradle5
-rw-r--r--javatests/artifacts/dagger-android/simple/gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--javatests/artifacts/dagger/build-tests/build.gradle (renamed from java/dagger/example/gradle/simple/build.gradle)25
-rw-r--r--javatests/artifacts/dagger/build-tests/src/main/java/buildtests/GradleFile.java41
-rw-r--r--javatests/artifacts/dagger/build-tests/src/main/java/buildtests/GradleModule.java96
-rw-r--r--javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveBindsQualifierTest.java228
-rw-r--r--javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveBindsScopeTest.java232
-rw-r--r--javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveComponentDependenciesTest.java208
-rw-r--r--javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveMapKeyTest.java157
-rw-r--r--javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveProvidesParameterizedTypeTest.java215
-rw-r--r--javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveProvidesQualifierTest.java215
-rw-r--r--javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveProvidesScopeTest.java228
-rw-r--r--javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveQualifierTest.java354
-rw-r--r--javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveScopeTest.java200
-rw-r--r--javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentModulesTest.java230
-rw-r--r--javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentQualifierTest.java374
-rw-r--r--javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentScopeTest.java214
-rw-r--r--javatests/artifacts/dagger/build.gradle (renamed from java/dagger/hilt/android/example/gradle/simpleKotlin/build.gradle)40
-rw-r--r--javatests/artifacts/dagger/gradle/wrapper/gradle-wrapper.jar (renamed from java/dagger/example/gradle/android/simple/gradle/wrapper/gradle-wrapper.jar)bin55616 -> 55616 bytes
-rw-r--r--javatests/artifacts/dagger/gradle/wrapper/gradle-wrapper.properties (renamed from java/dagger/example/gradle/android/simple/gradle/wrapper/gradle-wrapper.properties)2
-rwxr-xr-xjavatests/artifacts/dagger/gradlew (renamed from java/dagger/example/gradle/android/simple/gradlew)0
-rw-r--r--javatests/artifacts/dagger/java-app/build.gradle (renamed from javatests/artifacts/dagger/simple/build.gradle)11
-rw-r--r--javatests/artifacts/dagger/java-app/src/main/java/app/AssistedInjects.java (renamed from javatests/artifacts/dagger/simple/src/main/java/dagger/simple/AssistedInjects.java)2
-rw-r--r--javatests/artifacts/dagger/java-app/src/main/java/app/SimpleApplication.java (renamed from javatests/artifacts/dagger/simple/src/main/java/dagger/simple/SimpleApplication.java)5
-rw-r--r--javatests/artifacts/dagger/kotlin-app/build.gradle45
-rw-r--r--javatests/artifacts/dagger/kotlin-app/kotlin-library/build.gradle38
-rw-r--r--javatests/artifacts/dagger/kotlin-app/kotlin-library/src/main/kotlin/library/MySubcomponent.kt (renamed from java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/ModelModule.java)33
-rw-r--r--javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/AssistedInjects.kt60
-rw-r--r--javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/SimpleApplication.kt57
-rw-r--r--javatests/artifacts/dagger/kotlin-app/src/test/kotlin/app/ComponentProcessorBuildTest.kt (renamed from java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleGreeter.java)30
-rw-r--r--javatests/artifacts/dagger/settings.gradle8
-rw-r--r--javatests/artifacts/dagger/simple/gradle/wrapper/gradle-wrapper.jarbin55616 -> 0 bytes
-rw-r--r--javatests/artifacts/dagger/simple/gradle/wrapper/gradle-wrapper.properties5
-rwxr-xr-xjavatests/artifacts/dagger/simple/gradlew188
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/build.gradle34
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/build.gradle31
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/AssistedFoo.java114
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/Dep.java (renamed from java/dagger/internal/MemoizedSentinel.java)7
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/Foo.java93
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/FooBase.java79
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyAnnotation.java22
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyBaseComponent.java133
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyComponentDependency.java88
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyComponentDependencyBinding.java20
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyComponentModule.java218
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyOtherAnnotation.java22
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyQualifier.java22
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentBinding.java20
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentModule.java37
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentScope.java23
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentWithBuilder.java158
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentWithFactory.java148
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library2/build.gradle25
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveAnnotation.java20
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveBaseAnnotation.java20
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveType.java23
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/src/main/java/app/MyComponent.java73
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/src/test/java/app/MyComponentTest.java102
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/src/test/java/app/MySubcomponentWithBuilderTest.java54
-rw-r--r--javatests/artifacts/dagger/transitive-annotation-app/src/test/java/app/MySubcomponentWithFactoryTest.java54
-rw-r--r--javatests/artifacts/hilt-android/gradleConfigCache/app/build.gradle73
-rw-r--r--javatests/artifacts/hilt-android/gradleConfigCache/app/src/androidTest/java/dagger/hilt/android/gradleConfigCache/EmulatorTest.kt43
-rw-r--r--javatests/artifacts/hilt-android/gradleConfigCache/app/src/androidTest/java/dagger/hilt/android/gradleConfigCache/TestRunner.kt28
-rw-r--r--javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/AndroidManifest.xml34
-rw-r--r--javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/Foo.kt5
-rw-r--r--javatests/artifacts/hilt-android/gradleConfigCache/app/src/test/java/dagger/hilt/android/gradleConfigCache/LocalTest.kt46
-rw-r--r--javatests/artifacts/hilt-android/gradleConfigCache/build.gradle57
-rw-r--r--javatests/artifacts/hilt-android/gradleConfigCache/gradle.properties8
-rw-r--r--javatests/artifacts/hilt-android/gradleConfigCache/gradle/wrapper/gradle-wrapper.jarbin58910 -> 0 bytes
-rw-r--r--javatests/artifacts/hilt-android/gradleConfigCache/gradle/wrapper/gradle-wrapper.properties5
-rwxr-xr-xjavatests/artifacts/hilt-android/gradleConfigCache/gradlew185
-rw-r--r--javatests/artifacts/hilt-android/gradleConfigCache/gradlew.bat104
-rw-r--r--javatests/artifacts/hilt-android/gradleConfigCache/settings.gradle2
-rw-r--r--javatests/artifacts/hilt-android/pluginMarker/app/build.gradle (renamed from java/dagger/hilt/android/example/gradle/simple/feature/build.gradle)29
-rw-r--r--javatests/artifacts/hilt-android/pluginMarker/app/src/main/AndroidManifest.xml (renamed from javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/res/layout/activity_main.xml)12
-rw-r--r--javatests/artifacts/hilt-android/pluginMarker/gradle.properties1
-rw-r--r--javatests/artifacts/hilt-android/pluginMarker/gradle/wrapper/gradle-wrapper.jar (renamed from java/dagger/example/gradle/simple/gradle/wrapper/gradle-wrapper.jar)bin55616 -> 55616 bytes
-rw-r--r--javatests/artifacts/hilt-android/pluginMarker/gradle/wrapper/gradle-wrapper.properties (renamed from java/dagger/example/gradle/simple/gradle/wrapper/gradle-wrapper.properties)2
-rwxr-xr-xjavatests/artifacts/hilt-android/pluginMarker/gradlew (renamed from java/dagger/example/gradle/simple/gradlew)0
-rw-r--r--javatests/artifacts/hilt-android/pluginMarker/settings.gradle18
-rw-r--r--javatests/artifacts/hilt-android/simple/app-java-only/build.gradle69
-rw-r--r--javatests/artifacts/hilt-android/simple/app-java-only/src/main/AndroidManifest.xml24
-rw-r--r--javatests/artifacts/hilt-android/simple/app-java-only/src/main/java/dagger/hilt/android/simple/SimpleApplication.java52
-rw-r--r--javatests/artifacts/hilt-android/simple/app-java-only/src/test/java/dagger/hilt/android/simple/BuildTest.java43
-rw-r--r--javatests/artifacts/hilt-android/simple/app/build.gradle40
-rw-r--r--javatests/artifacts/hilt-android/simple/app/src/androidTest-agp-4.2.0/java/dagger/hilt/android/simple/BroadcastReceiverTest.java (renamed from java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/BroadcastReceiverTest.java)10
-rw-r--r--javatests/artifacts/hilt-android/simple/app/src/debug/AndroidManifest.xml8
-rw-r--r--javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/AliasOfMultipleScopesTest.java184
-rw-r--r--javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/InvokeSpecialTransformTest.java77
-rw-r--r--javatests/artifacts/hilt-android/simple/build.gradle7
-rw-r--r--javatests/artifacts/hilt-android/simple/earlyentrypoint/build.gradle68
-rw-r--r--javatests/artifacts/hilt-android/simple/earlyentrypoint/src/main/AndroidManifest.xml (renamed from java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/debug/AndroidManifest.xml)5
-rw-r--r--javatests/artifacts/hilt-android/simple/earlyentrypoint/src/test/java/dagger/hilt/android/simple/earlyentrypoint/EarlyEntryPointWithBindValueObjects.java (renamed from java/dagger/example/gradle/simple/SimpleApplication.java)39
-rw-r--r--javatests/artifacts/hilt-android/simple/earlyentrypoint/src/test/java/dagger/hilt/android/simple/earlyentrypoint/EarlyEntryPointWithBindValueTest.java84
-rw-r--r--javatests/artifacts/hilt-android/simple/gradle.properties7
-rw-r--r--javatests/artifacts/hilt-android/simple/gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--javatests/artifacts/hilt-android/simple/settings.gradle4
-rw-r--r--javatests/artifacts/hilt-android/simpleKotlin/android-library/build.gradle1
-rw-r--r--javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle2
-rw-r--r--javatests/artifacts/hilt-android/simpleKotlin/app/src/sharedTest/java/dagger/hilt/android/simpleKotlin/KotlinSuppressClasses.kt (renamed from javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/MainActivity.kt)27
-rw-r--r--javatests/artifacts/hilt-android/simpleKotlin/build.gradle7
-rw-r--r--javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle4
-rw-r--r--javatests/artifacts/hilt-android/simpleKotlin/gradle.properties7
-rw-r--r--javatests/artifacts/hilt-android/simpleKotlin/gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--javatests/dagger/BUILD10
-rw-r--r--javatests/dagger/android/BUILD6
-rw-r--r--javatests/dagger/android/processor/BUILD10
-rw-r--r--javatests/dagger/android/support/BUILD10
-rw-r--r--javatests/dagger/android/support/functional/BUILD4
-rw-r--r--javatests/dagger/functional/BUILD18
-rw-r--r--javatests/dagger/functional/ComponentNestedTypeTest.java61
-rw-r--r--javatests/dagger/functional/assisted/AssistedFactoryDuplicatedParamNamesTest.java82
-rw-r--r--javatests/dagger/functional/assisted/AssistedFactoryTest.java25
-rw-r--r--javatests/dagger/functional/assisted/AssistedFactoryWithMultibindingsTest.java109
-rw-r--r--javatests/dagger/functional/assisted/BUILD18
-rw-r--r--javatests/dagger/functional/assisted/kotlin/BUILD5
-rw-r--r--javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionClasses.kt17
-rw-r--r--javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionTest.java14
-rw-r--r--javatests/dagger/functional/assisted/subpackage/BUILD2
-rw-r--r--javatests/dagger/functional/binds/AccessesExposedComponent.java2
-rw-r--r--javatests/dagger/functional/binds/BindsTest.java1
-rw-r--r--javatests/dagger/functional/binds/ScopedBindsTest.java61
-rw-r--r--javatests/dagger/functional/binds/TestComponent.java5
-rw-r--r--javatests/dagger/functional/binds/subpackage/ExposedModule.java26
-rw-r--r--javatests/dagger/functional/guava/BUILD14
-rw-r--r--javatests/dagger/functional/jakarta/BUILD34
-rw-r--r--javatests/dagger/functional/jakarta/SimpleJakartaTest.java67
-rw-r--r--javatests/dagger/functional/jdk8/BUILD50
-rw-r--r--javatests/dagger/functional/jdk8/a/BUILD41
-rw-r--r--javatests/dagger/functional/kotlin/BUILD9
-rw-r--r--javatests/dagger/functional/kotlin/DependsOnGeneratedCodeClasses.kt35
-rw-r--r--javatests/dagger/functional/kotlin/DependsOnGeneratedCodeTest.java (renamed from java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleApplication.java)26
-rw-r--r--javatests/dagger/functional/kotlin/processor/BUILD4
-rw-r--r--javatests/dagger/functional/names/BUILD33
-rw-r--r--javatests/dagger/functional/names/ComponentFactoryNameConflictsTest.java88
-rw-r--r--javatests/dagger/functional/producers/BUILD18
-rw-r--r--javatests/dagger/functional/spi/BUILD14
-rw-r--r--javatests/dagger/functional/sub/NestedType.java21
-rw-r--r--javatests/dagger/functional/tck/BUILD6
-rw-r--r--javatests/dagger/hilt/android/ActivityInjectedSavedStateViewModelTest.java6
-rw-r--r--javatests/dagger/hilt/android/ActivityInjectedViewModelTest.java4
-rw-r--r--javatests/dagger/hilt/android/ActivityRetainedClearedListenerTest.java2
-rw-r--r--javatests/dagger/hilt/android/AliasOfMultipleScopesTest.java187
-rw-r--r--javatests/dagger/hilt/android/AndroidManifest.xml56
-rw-r--r--javatests/dagger/hilt/android/BUILD214
-rw-r--r--javatests/dagger/hilt/android/CustomInjectClasses.java54
-rw-r--r--javatests/dagger/hilt/android/CustomInjectTest.java45
-rw-r--r--javatests/dagger/hilt/android/DefaultViewModelFactoryTest.java4
-rw-r--r--javatests/dagger/hilt/android/EntryPointAccessorsTest.kt193
-rw-r--r--javatests/dagger/hilt/android/FragmentContextOnAttachTest.java104
-rw-r--r--javatests/dagger/hilt/android/ModuleTest.java2
-rw-r--r--javatests/dagger/hilt/android/MultiTestRoot1Test.java15
-rw-r--r--javatests/dagger/hilt/android/MultiTestRoot2Test.java15
-rw-r--r--javatests/dagger/hilt/android/OptionalInjectTestClasses.java170
-rw-r--r--javatests/dagger/hilt/android/OptionalInjectWithHiltTest.java230
-rw-r--r--javatests/dagger/hilt/android/OptionalInjectWithoutHiltTest.java157
-rw-r--r--javatests/dagger/hilt/android/ViewModelScopedTest.java4
-rw-r--r--javatests/dagger/hilt/android/ViewModelWithBaseTest.java6
-rw-r--r--javatests/dagger/hilt/android/internal/managers/BUILD4
-rw-r--r--javatests/dagger/hilt/android/internal/managers/FragmentContextWrapperLeakTest.java2
-rw-r--r--javatests/dagger/hilt/android/processor/internal/BUILD8
-rw-r--r--javatests/dagger/hilt/android/processor/internal/GeneratorsTest.java193
-rw-r--r--javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD16
-rw-r--r--javatests/dagger/hilt/android/processor/internal/aggregateddeps/EarlyEntryPointProcessorTest.java2
-rw-r--r--javatests/dagger/hilt/android/processor/internal/aggregateddeps/TestInstallInTest.java2
-rw-r--r--javatests/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGeneratorTest.java2
-rw-r--r--javatests/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessorTest.java2
-rw-r--r--javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD24
-rw-r--r--javatests/dagger/hilt/android/processor/internal/androidentrypoint/KotlinAndroidEntryPointProcessorTest.java2
-rw-r--r--javatests/dagger/hilt/android/processor/internal/customtestapplication/BUILD8
-rw-r--r--javatests/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessorTest.java2
-rw-r--r--javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD34
-rw-r--r--javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelGeneratorTest.kt102
-rw-r--r--javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPluginTest.kt2
-rw-r--r--javatests/dagger/hilt/android/testing/BUILD31
-rw-r--r--javatests/dagger/hilt/android/testing/HiltAndroidRuleTestApp.java2
-rw-r--r--javatests/dagger/hilt/android/testing/testinstallin/BUILD6
-rw-r--r--javatests/dagger/hilt/processor/internal/BUILD6
-rw-r--r--javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD10
-rw-r--r--javatests/dagger/hilt/processor/internal/aliasof/AliasOfProcessorTest.java121
-rw-r--r--javatests/dagger/hilt/processor/internal/aliasof/BUILD40
-rw-r--r--javatests/dagger/hilt/processor/internal/definecomponent/BUILD6
-rw-r--r--javatests/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessorTest.java11
-rw-r--r--javatests/dagger/hilt/processor/internal/disableinstallincheck/BUILD8
-rw-r--r--javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD10
-rw-r--r--javatests/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessorTest.java2
-rw-r--r--javatests/dagger/hilt/processor/internal/originatingelement/BUILD8
-rw-r--r--javatests/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessorTest.java2
-rw-r--r--javatests/dagger/hilt/processor/internal/root/BUILD40
-rw-r--r--javatests/dagger/hilt/processor/internal/root/MyAppPreviousCompilationTest.java12
-rw-r--r--javatests/dagger/hilt/processor/internal/root/MyTestPreviousCompilationTest.java16
-rw-r--r--javatests/dagger/hilt/processor/internal/root/RootFileFormatterTest.java3
-rw-r--r--javatests/dagger/hilt/processor/internal/root/RootProcessorErrorsTest.java10
-rw-r--r--javatests/dagger/hilt/processor/internal/uninstallmodules/BUILD8
-rw-r--r--javatests/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessorTest.java2
-rw-r--r--javatests/dagger/hilt/testmodules/BUILD2
-rw-r--r--javatests/dagger/internal/codegen/AssistedFactoryErrorsTest.java8
-rw-r--r--javatests/dagger/internal/codegen/AssistedFactoryTest.java410
-rw-r--r--javatests/dagger/internal/codegen/BUILD71
-rw-r--r--javatests/dagger/internal/codegen/BindsMethodValidationTest.java116
-rw-r--r--javatests/dagger/internal/codegen/Compilers.java3
-rw-r--r--javatests/dagger/internal/codegen/ComponentBuilderTest.java2
-rw-r--r--javatests/dagger/internal/codegen/ComponentCreatorTest.java16
-rw-r--r--javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java8
-rw-r--r--javatests/dagger/internal/codegen/ComponentFactoryTest.java2
-rw-r--r--javatests/dagger/internal/codegen/ComponentProcessorTest.java488
-rw-r--r--javatests/dagger/internal/codegen/ComponentProtectedTypeTest.java111
-rw-r--r--javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java197
-rw-r--r--javatests/dagger/internal/codegen/ComponentShardTest.java478
-rw-r--r--javatests/dagger/internal/codegen/ComponentValidationKtTest.java106
-rw-r--r--javatests/dagger/internal/codegen/ComponentValidationTest.java112
-rw-r--r--javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java615
-rw-r--r--javatests/dagger/internal/codegen/DelegateRequestRepresentationTest.java (renamed from javatests/dagger/internal/codegen/DelegateBindingExpressionTest.java)356
-rw-r--r--javatests/dagger/internal/codegen/DependencyCycleValidationTest.java53
-rw-r--r--javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java70
-rw-r--r--javatests/dagger/internal/codegen/ElidedFactoriesTest.java365
-rw-r--r--javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java10
-rw-r--r--javatests/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java527
-rw-r--r--javatests/dagger/internal/codegen/InvalidInjectConstructor.java (renamed from java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/KotlinApplication.kt)25
-rw-r--r--javatests/dagger/internal/codegen/InvalidInjectConstructorTest.java97
-rw-r--r--javatests/dagger/internal/codegen/KeyFactoryTest.java66
-rw-r--r--javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java878
-rw-r--r--javatests/dagger/internal/codegen/MapRequestRepresentationTest.java (renamed from javatests/dagger/internal/codegen/MapBindingExpressionTest.java)108
-rw-r--r--javatests/dagger/internal/codegen/MapRequestRepresentationWithGuavaTest.java (renamed from javatests/dagger/internal/codegen/MapBindingExpressionWithGuavaTest.java)227
-rw-r--r--javatests/dagger/internal/codegen/MembersInjectionTest.java332
-rw-r--r--javatests/dagger/internal/codegen/MethodSignatureFormatterTest.java112
-rw-r--r--javatests/dagger/internal/codegen/MissingBindingSuggestionsTest.java18
-rw-r--r--javatests/dagger/internal/codegen/MissingBindingValidationTest.java237
-rw-r--r--javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java305
-rw-r--r--javatests/dagger/internal/codegen/OptionalBindingRequestFulfillmentTest.java61
-rw-r--r--javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java442
-rw-r--r--javatests/dagger/internal/codegen/RawTypeInjectionTest.java204
-rw-r--r--javatests/dagger/internal/codegen/ScopingValidationTest.java9
-rw-r--r--javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java14
-rw-r--r--javatests/dagger/internal/codegen/SetBindingRequestFulfillmentWithGuavaTest.java8
-rw-r--r--javatests/dagger/internal/codegen/SubcomponentBuilderValidationTest.java2
-rw-r--r--javatests/dagger/internal/codegen/SubcomponentCreatorRequestFulfillmentTest.java20
-rw-r--r--javatests/dagger/internal/codegen/SubcomponentCreatorValidationTest.java63
-rw-r--r--javatests/dagger/internal/codegen/SubcomponentValidationTest.java212
-rw-r--r--javatests/dagger/internal/codegen/SwitchingProviderTest.java93
-rw-r--r--javatests/dagger/internal/codegen/UnresolvableDependencyTest.java231
-rw-r--r--javatests/dagger/internal/codegen/ValidationReportTest.java103
-rw-r--r--javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD10
-rw-r--r--javatests/dagger/internal/codegen/bindinggraphvalidation/SetMultibindingValidationTest.java291
-rw-r--r--javatests/dagger/internal/codegen/javapoet/BUILD10
-rw-r--r--javatests/dagger/internal/codegen/javapoet/ExpressionTest.java8
-rw-r--r--javatests/dagger/internal/codegen/validation/BUILD4
-rw-r--r--javatests/dagger/lint/BUILD2
-rw-r--r--javatests/dagger/lint/DaggerKotlinIssueDetectorTest.kt3
-rw-r--r--javatests/dagger/producers/BUILD12
-rw-r--r--javatests/dagger/spi/BUILD14
-rw-r--r--test_defs.bzl3
-rw-r--r--third_party/java/asm/BUILD32
-rw-r--r--third_party/java/auto/BUILD113
-rw-r--r--third_party/java/byte_buddy/BUILD23
-rw-r--r--third_party/java/byte_buddy_agent/BUILD23
-rw-r--r--third_party/java/checker_framework/BUILD28
-rw-r--r--third_party/java/checker_framework_annotations/BUILD22
-rw-r--r--third_party/java/compile_testing/BUILD34
-rw-r--r--third_party/java/diffutils/BUILD22
-rw-r--r--third_party/java/error_prone/BUILD47
-rw-r--r--third_party/java/google_java_format/BUILD30
-rw-r--r--third_party/java/grpc/BUILD37
-rw-r--r--third_party/java/guava/BUILD41
-rw-r--r--third_party/java/guava/base/BUILD22
-rw-r--r--third_party/java/guava/cache/BUILD22
-rw-r--r--third_party/java/guava/collect/BUILD22
-rw-r--r--third_party/java/guava/graph/BUILD22
-rw-r--r--third_party/java/guava/io/BUILD22
-rw-r--r--third_party/java/guava/util/concurrent/BUILD22
-rw-r--r--third_party/java/hamcrest/BUILD23
-rw-r--r--third_party/java/incap/BUILD35
-rw-r--r--third_party/java/javapoet/BUILD22
-rw-r--r--third_party/java/jsr250_annotations/BUILD22
-rw-r--r--third_party/java/jsr305_annotations/BUILD22
-rw-r--r--third_party/java/jsr330_inject/BUILD27
-rw-r--r--third_party/java/junit/BUILD26
-rw-r--r--third_party/java/mockito/BUILD31
-rw-r--r--third_party/java/objenesis/BUILD23
-rw-r--r--third_party/java/protobuf/BUILD22
-rw-r--r--third_party/java/truth/BUILD33
-rw-r--r--tools/bazel_compat.bzl65
-rw-r--r--tools/maven.bzl6
-rw-r--r--tools/shader/build.gradle100
-rw-r--r--tools/shader/gradle/wrapper/gradle-wrapper.jar (renamed from java/dagger/hilt/android/example/gradle/simple/gradle/wrapper/gradle-wrapper.jar)bin55616 -> 55616 bytes
-rw-r--r--tools/shader/gradle/wrapper/gradle-wrapper.properties (renamed from java/dagger/hilt/android/example/gradle/simple/gradle/wrapper/gradle-wrapper.properties)2
-rwxr-xr-xtools/shader/gradlew (renamed from java/dagger/hilt/android/example/gradle/simple/gradlew)0
-rwxr-xr-xutil/deploy-all.sh9
-rwxr-xr-xutil/deploy-dagger.sh77
-rwxr-xr-xutil/deploy-hilt-gradle-plugin.sh41
-rwxr-xr-xutil/deploy-hilt.sh62
-rwxr-xr-xutil/deploy-library.sh51
-rwxr-xr-xutil/deploy-to-maven-central.sh50
-rwxr-xr-xutil/install-local-snapshot.sh6
-rwxr-xr-xutil/latest-dagger-version.sh55
-rwxr-xr-xutil/publish-snapshot-on-commit.sh27
-rwxr-xr-xutil/publish-tagged-docs.sh33
-rwxr-xr-xutil/publish-tagged-release.sh23
-rwxr-xr-xutil/run-local-emulator-tests.sh8
-rwxr-xr-xutil/run-local-gradle-android-tests.sh19
-rwxr-xr-xutil/run-local-gradle-tests.sh5
-rwxr-xr-xutil/run-local-tests.sh4
-rw-r--r--util/settings.xml9
-rw-r--r--util/shade-library.sh20
-rwxr-xr-xutil/shasum.sh18
-rwxr-xr-xutil/validate-dagger-version.sh20
-rw-r--r--workspace_defs.bzl62
861 files changed, 38802 insertions, 18413 deletions
diff --git a/.github/actions/artifact-android-emulator-tests/action.yml b/.github/actions/artifact-android-emulator-tests/action.yml
new file mode 100644
index 000000000..a57fd08a4
--- /dev/null
+++ b/.github/actions/artifact-android-emulator-tests/action.yml
@@ -0,0 +1,39 @@
+name: 'Artifact Android emulator tests'
+description: 'Runs Android emulator tests on the Dagger LOCAL-SNAPSHOT artifacts.'
+
+inputs:
+ api-level:
+ description: 'The version of Android emulator API to test with.'
+ required: true
+
+runs:
+ using: "composite"
+ steps:
+ - name: 'Check out repository'
+ uses: actions/checkout@v2
+ - name: 'Cache Gradle files'
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: 'Download local snapshot for tests'
+ uses: actions/download-artifact@v2
+ with:
+ name: local-snapshot
+ path: ~/.m2/repository/com/google/dagger
+ - name: 'Gradle Android emulator tests (API ${{ inputs.api-level }})'
+ uses: reactivecircus/android-emulator-runner@v2
+ with:
+ api-level: ${{ inputs.api-level }}
+ target: google_apis
+ script: ./util/run-local-emulator-tests.sh
+ - name: 'Upload test reports (API ${{ inputs.api-level }})'
+ if: ${{ always() }}
+ uses: actions/upload-artifact@v2
+ with:
+ name: androidTests-report-api-${{ inputs.api-level }}
+ path: ${{ github.workspace }}/**/build/reports/androidTests/connected/*
diff --git a/.github/actions/artifact-android-local-tests/action.yml b/.github/actions/artifact-android-local-tests/action.yml
new file mode 100644
index 000000000..090bbb5bd
--- /dev/null
+++ b/.github/actions/artifact-android-local-tests/action.yml
@@ -0,0 +1,36 @@
+name: 'Artifact Android local tests'
+description: 'Runs Android local tests on the Dagger LOCAL-SNAPSHOT artifacts.'
+
+inputs:
+ agp:
+ description: 'The version of AGP to test with.'
+ required: true
+
+runs:
+ using: "composite"
+ steps:
+ - name: 'Check out repository'
+ uses: actions/checkout@v2
+ - name: 'Cache Gradle files'
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: 'Download local snapshot for tests'
+ uses: actions/download-artifact@v2
+ with:
+ name: local-snapshot
+ path: ~/.m2/repository/com/google/dagger
+ - name: 'Gradle Android local tests (AGP ${{ inputs.agp }})'
+ run: ./util/run-local-gradle-android-tests.sh "${{ inputs.agp }}"
+ shell: bash
+ - name: 'Upload test reports (AGP ${{ inputs.agp }})'
+ if: ${{ always() }}
+ uses: actions/upload-artifact@v2
+ with:
+ name: tests-reports-agp-${{ inputs.agp }}
+ path: ${{ github.workspace }}/**/build/reports/tests/*
diff --git a/.github/actions/artifact-java-local-tests/action.yml b/.github/actions/artifact-java-local-tests/action.yml
new file mode 100644
index 000000000..eb31897cd
--- /dev/null
+++ b/.github/actions/artifact-java-local-tests/action.yml
@@ -0,0 +1,25 @@
+name: 'Artifact Java local tests'
+description: 'Runs java local tests on the Dagger LOCAL-SNAPSHOT artifacts.'
+
+runs:
+ using: "composite"
+ steps:
+ - name: 'Check out repository'
+ uses: actions/checkout@v2
+ - name: 'Cache Gradle files'
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: 'Download local snapshot for tests'
+ uses: actions/download-artifact@v2
+ with:
+ name: local-snapshot
+ path: ~/.m2/repository/com/google/dagger
+ - name: 'Gradle Java local tests'
+ run: ./util/run-local-gradle-tests.sh
+ shell: bash
diff --git a/.github/actions/bazel-build/action.yml b/.github/actions/bazel-build/action.yml
new file mode 100644
index 000000000..bc875c73e
--- /dev/null
+++ b/.github/actions/bazel-build/action.yml
@@ -0,0 +1,39 @@
+name: 'Bazel build'
+description: 'Builds artifacts and creates the Dagger local snapshots.'
+
+runs:
+ using: "composite"
+ steps:
+ - name: 'Install Java ${{ env.USE_JAVA_VERSION }}'
+ uses: actions/setup-java@v2
+ with:
+ distribution: '${{ env.USE_JAVA_DISTRIBUTION }}'
+ java-version: '${{ env.USE_JAVA_VERSION }}'
+ - name: 'Check out repository'
+ uses: actions/checkout@v2
+ - name: 'Cache Bazel files'
+ uses: actions/cache@v2
+ with:
+ path: ~/.cache/bazel
+ key: ${{ runner.os }}-bazel-build-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.os }}-bazel-build-
+ - name: 'Java build'
+ run: bazel build //java/...
+ shell: bash
+ - name: 'Install local snapshot'
+ run: ./util/install-local-snapshot.sh
+ shell: bash
+ - name: 'Upload local snapshot for tests'
+ uses: actions/upload-artifact@v2
+ with:
+ name: local-snapshot
+ path: ~/.m2/repository/com/google/dagger
+ - name: 'Clean bazel cache'
+ # According to the documentation, we should be able to exclude these via
+ # the actions/cache path, e.g. "!~/.cache/bazel/*/*/external/" but that
+ # doesn't seem to work.
+ run: |
+ rm -rf $(bazel info repository_cache)
+ rm -rf ~/.cache/bazel/*/*/external/
+ shell: bash
diff --git a/.github/actions/bazel-test/action.yml b/.github/actions/bazel-test/action.yml
new file mode 100644
index 000000000..0fc5a1c3e
--- /dev/null
+++ b/.github/actions/bazel-test/action.yml
@@ -0,0 +1,55 @@
+name: 'Bazel test'
+description: 'Runs Bazel tests.'
+
+runs:
+ using: "composite"
+ steps:
+ - name: 'Install Java ${{ env.USE_JAVA_VERSION }}'
+ uses: actions/setup-java@v2
+ with:
+ distribution: '${{ env.USE_JAVA_DISTRIBUTION }}'
+ java-version: '${{ env.USE_JAVA_VERSION }}'
+ - name: 'Check out repository'
+ uses: actions/checkout@v2
+ - name: 'Cache local Maven repository'
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.m2/repository
+ !~/.m2/repository/com/google/dagger
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+ - name: 'Cache Bazel files'
+ uses: actions/cache@v2
+ with:
+ path: ~/.cache/bazel
+ # Note: we could use the same key as bazel-build, but we separate them
+ # so that bazel-build's cache is smaller (~200Mb vs ~900Mb) and faster
+ # to load than this cache since it's the bottleneck of all other steps
+ key: ${{ runner.os }}-bazel-test-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.os }}-bazel-test-
+ - name: 'Cache Gradle files'
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: 'Run Bazel tests'
+ run: bazel test --test_output=errors //...
+ shell: bash
+ - name: 'Run Bazel examples'
+ run: cd examples/bazel; bazel test --test_output=errors //...
+ shell: bash
+ - name: 'Clean bazel cache'
+ # According to the documentation, we should be able to exclude these via
+ # the actions/cache path, e.g. "!~/.cache/bazel/*/*/external/" but that
+ # doesn't seem to work.
+ run: |
+ rm -rf $(bazel info repository_cache)
+ rm -rf ~/.cache/bazel/*/*/external/
+ shell: bash
diff --git a/.github/actions/build-gradle-plugin/action.yml b/.github/actions/build-gradle-plugin/action.yml
new file mode 100644
index 000000000..6a388d445
--- /dev/null
+++ b/.github/actions/build-gradle-plugin/action.yml
@@ -0,0 +1,56 @@
+name: 'Build Hilt Gradle plugin'
+description: 'Builds the Hilt Gradle plugin.'
+
+inputs:
+ agp:
+ description: 'The version of AGP to build with.'
+ required: true
+
+runs:
+ using: "composite"
+ steps:
+ - name: 'Install Java ${{ env.USE_JAVA_VERSION }}'
+ uses: actions/setup-java@v2
+ with:
+ distribution: '${{ env.USE_JAVA_DISTRIBUTION }}'
+ java-version: '${{ env.USE_JAVA_VERSION }}'
+ - name: 'Check out repository'
+ uses: actions/checkout@v2
+ - name: 'Cache local Maven repository'
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.m2/repository
+ !~/.m2/repository/com/google/dagger
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+ - name: 'Cache Bazel files'
+ uses: actions/cache@v2
+ with:
+ path: ~/.cache/bazel
+ key: ${{ runner.os }}-bazel-build-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.os }}-bazel-build-
+ - name: 'Cache Gradle files'
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: 'Build and install Hilt Gradle plugin local snapshot'
+ run: ./util/deploy-hilt-gradle-plugin.sh "install:install-file" "LOCAL-SNAPSHOT"
+ shell: bash
+ env:
+ AGP_VERSION: '${{ inputs.agp }}'
+ - name: 'Clean bazel cache'
+ # According to the documentation, we should be able to exclude these via
+ # the actions/cache path, e.g. "!~/.cache/bazel/*/*/external/" but that
+ # doesn't seem to work.
+ run: |
+ rm -rf $(bazel info repository_cache)
+ rm -rf ~/.cache/bazel/*/*/external/
+ shell: bash
diff --git a/.github/actions/prechecks/action.yml b/.github/actions/prechecks/action.yml
new file mode 100644
index 000000000..1365184ae
--- /dev/null
+++ b/.github/actions/prechecks/action.yml
@@ -0,0 +1,20 @@
+name: 'Performs prechecks before running other actions.'
+description: 'Validates that the Dagger version in the config.yml file is the latest version of Dagger released.'
+
+runs:
+ using: "composite"
+ steps:
+ # Cancel previous runs on the same branch to avoid unnecessary parallel
+ # runs of the same job. See https://github.com/google/go-github/pull/1821
+ - name: Cancel previous
+ uses: styfle/cancel-workflow-action@0.8.0
+ with:
+ access_token: ${{ github.token }}
+ - name: 'Check out gh-pages repository'
+ uses: actions/checkout@v2
+ with:
+ ref: 'refs/heads/gh-pages'
+ path: gh-pages
+ - name: 'Validate latest Dagger version'
+ run: ./gh-pages/.github/scripts/validate-latest-dagger-version.sh gh-pages/_config.yml
+ shell: bash
diff --git a/.github/actions/test-gradle-plugin/action.yml b/.github/actions/test-gradle-plugin/action.yml
new file mode 100644
index 000000000..93c6af7f6
--- /dev/null
+++ b/.github/actions/test-gradle-plugin/action.yml
@@ -0,0 +1,54 @@
+name: 'Test Hilt Gradle plugin'
+description: 'Tests the Hilt Gradle plugin.'
+
+runs:
+ using: "composite"
+ steps:
+ - name: 'Install Java ${{ env.USE_JAVA_VERSION }}'
+ uses: actions/setup-java@v2
+ with:
+ distribution: '${{ env.USE_JAVA_DISTRIBUTION }}'
+ java-version: '${{ env.USE_JAVA_VERSION }}'
+ - name: 'Check out repository'
+ uses: actions/checkout@v2
+ - name: 'Cache local Maven repository'
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.m2/repository
+ !~/.m2/repository/com/google/dagger
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+ - name: 'Cache Bazel files'
+ uses: actions/cache@v2
+ with:
+ path: ~/.cache/bazel
+ key: ${{ runner.os }}-bazel-build-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.os }}-bazel-build-
+ - name: 'Cache Gradle files'
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: 'Download local snapshot for tests'
+ uses: actions/download-artifact@v2
+ with:
+ name: local-snapshot
+ path: ~/.m2/repository/com/google/dagger
+ - name: 'Build and test Hilt Gradle plugin'
+ run: ./java/dagger/hilt/android/plugin/gradlew -p java/dagger/hilt/android/plugin clean test --continue --no-daemon --stacktrace
+ shell: bash
+ - name: 'Clean bazel cache'
+ # According to the documentation, we should be able to exclude these via
+ # the actions/cache path, e.g. "!~/.cache/bazel/*/*/external/" but that
+ # doesn't seem to work.
+ run: |
+ rm -rf $(bazel info repository_cache)
+ rm -rf ~/.cache/bazel/*/*/external/
+ shell: bash
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6c818cc98..d5c35d611 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -9,182 +9,106 @@ on:
- master
env:
+ USE_JAVA_DISTRIBUTION: 'zulu'
# Our Bazel builds currently rely on JDK 8.
USE_JAVA_VERSION: '8'
- # Our Bazel builds currently rely on 3.7.1. The version is set via
+ # Our Bazel builds currently rely on 4.2.1. The version is set via
# baselisk by USE_BAZEL_VERSION: https://github.com/bazelbuild/bazelisk.
- USE_BAZEL_VERSION: '3.7.1'
+ USE_BAZEL_VERSION: '4.2.1'
jobs:
validate-latest-dagger-version:
name: 'Validate Dagger version'
runs-on: ubuntu-latest
steps:
- # Cancel previous runs on the same branch to avoid unnecessary parallel
- # runs of the same job. See https://github.com/google/go-github/pull/1821
- - name: Cancel previous
- uses: styfle/cancel-workflow-action@0.8.0
- with:
- access_token: ${{ github.token }}
- - name: 'Check out gh-pages repository'
- uses: actions/checkout@v2
- with:
- ref: 'refs/heads/gh-pages'
- path: gh-pages
- - name: 'Validate latest Dagger version'
- run: ./gh-pages/.github/scripts/validate-latest-dagger-version.sh gh-pages/_config.yml
+ - uses: actions/checkout@v2
+ - uses: ./.github/actions/prechecks
+ bazel-build:
+ name: 'Bazel build'
+ needs: validate-latest-dagger-version
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: ./.github/actions/bazel-build
bazel-test:
name: 'Bazel tests'
needs: validate-latest-dagger-version
runs-on: ubuntu-latest
steps:
- - name: 'Install Java ${{ env.USE_JAVA_VERSION }}'
- uses: actions/setup-java@v1
- with:
- java-version: '${{ env.USE_JAVA_VERSION }}'
- - name: 'Check out repository'
- uses: actions/checkout@v2
- - name: 'Cache local Maven repository'
- uses: actions/cache@v2
- with:
- path: |
- ~/.m2/repository
- !~/.m2/repository/com/google/dagger
- key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-
- - name: 'Cache Bazel files'
- uses: actions/cache@v2
- with:
- path: ~/.cache/bazel
- key: ${{ runner.os }}-bazel-${{ github.sha }}
- restore-keys: |
- ${{ runner.os }}-bazel-
- - name: 'Cache Gradle files'
- uses: actions/cache@v2
- with:
- path: |
- ~/.gradle/caches
- ~/.gradle/wrapper
- key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
- restore-keys: |
- ${{ runner.os }}-gradle-
- - name: 'Run Bazel tests'
- run: bazel test --test_output=errors //... --keep_going
- shell: bash
- - name: 'Install local snapshot'
- run: ./util/install-local-snapshot.sh
- shell: bash
- - name: 'Upload local snapshot for tests'
- uses: actions/upload-artifact@v2
- with:
- name: local-snapshot
- path: ~/.m2/repository/com/google/dagger
+ - uses: actions/checkout@v2
+ - uses: ./.github/actions/bazel-test
artifact-java-local-tests:
name: 'Artifact Java local tests'
- needs: bazel-test
+ needs: bazel-build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: ./.github/actions/artifact-java-local-tests
+ test-gradle-plugin:
+ name: 'Test Hilt Gradle plugin'
+ needs: bazel-build
runs-on: ubuntu-latest
steps:
- - name: 'Check out repository'
- uses: actions/checkout@v2
- - name: 'Cache Gradle files'
- uses: actions/cache@v2
- with:
- path: |
- ~/.gradle/caches
- ~/.gradle/wrapper
- key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
- restore-keys: |
- ${{ runner.os }}-gradle-
- - name: 'Download local snapshot for tests'
- uses: actions/download-artifact@v2
- with:
- name: local-snapshot
- path: ~/.m2/repository/com/google/dagger
- - name: 'Gradle Java local tests'
- run: ./util/run-local-gradle-tests.sh
- shell: bash
+ - uses: actions/checkout@v2
+ - uses: ./.github/actions/test-gradle-plugin
artifact-android-local-tests:
name: 'Artifact Android local tests (AGP ${{ matrix.agp }})'
- needs: bazel-test
+ needs: bazel-build
runs-on: ubuntu-latest
strategy:
matrix:
- agp: ['4.1.0', '4.2.0-beta04']
+ agp: ['4.1.0', '4.2.0', '7.0.0']
steps:
- - name: 'Check out repository'
- uses: actions/checkout@v2
- - name: 'Cache Gradle files'
- uses: actions/cache@v2
- with:
- path: |
- ~/.gradle/caches
- ~/.gradle/wrapper
- key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
- restore-keys: |
- ${{ runner.os }}-gradle-
- - name: 'Download local snapshot for tests'
- uses: actions/download-artifact@v2
- with:
- name: local-snapshot
- path: ~/.m2/repository/com/google/dagger
- - name: 'Gradle Android local tests (AGP ${{ matrix.agp }})'
- run: ./util/run-local-gradle-android-tests.sh "${{ matrix.agp }}"
- shell: bash
- - name: 'Upload test reports (AGP ${{ matrix.agp }})'
- if: ${{ always() }}
- uses: actions/upload-artifact@v2
+ - uses: actions/checkout@v2
+ - uses: ./.github/actions/artifact-android-local-tests
with:
- name: tests-reports-agp-${{ matrix.agp }}
- path: ${{ github.workspace }}/**/build/reports/tests/*
+ agp: '${{ matrix.agp }}'
artifact-android-emulator-tests:
name: 'Artifact Android emulator tests (API 30)'
- needs: bazel-test
+ needs: bazel-build
# It's recommended to run emulator tests on macOS
# See https://github.com/marketplace/actions/android-emulator-runner
runs-on: macos-latest
steps:
- - name: 'Check out repository'
- uses: actions/checkout@v2
- - name: 'Cache Gradle files'
- uses: actions/cache@v2
- with:
- path: |
- ~/.gradle/caches
- ~/.gradle/wrapper
- key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
- restore-keys: |
- ${{ runner.os }}-gradle-
- - name: 'Download local snapshot for tests'
- uses: actions/download-artifact@v2
- with:
- name: local-snapshot
- path: ~/.m2/repository/com/google/dagger
- - name: 'Gradle Android emulator tests (API 30)'
- uses: reactivecircus/android-emulator-runner@v2
+ - uses: actions/checkout@v2
+ - uses: ./.github/actions/artifact-android-emulator-tests
timeout-minutes: 25
with:
- api-level: 30
- target: google_apis
- script: ./util/run-local-emulator-tests.sh
- - name: 'Upload test reports (API 30)'
- if: ${{ always() }}
- uses: actions/upload-artifact@v2
+ api-level: '30'
+ artifact-android-emulator-legacy-api-tests:
+ name: 'Artifact Android emulator tests (API ${{ matrix.api-level }})'
+ # We only run this on master push (essentially a postsubmit) since these
+ # can take a while to run
+ if: github.event_name == 'push' && github.repository == 'google/dagger' && github.ref == 'refs/heads/master'
+ needs: bazel-build
+ # It's recommended to run emulator tests on macOS
+ # See https://github.com/marketplace/actions/android-emulator-runner
+ runs-on: macos-latest
+ strategy:
+ matrix: # Run on 16 (PreL), 21 (L), and 26 (O).
+ api-level: [16, 21, 26]
+ steps:
+ - uses: actions/checkout@v2
+ - uses: ./.github/actions/artifact-android-emulator-tests
+ timeout-minutes: 25
with:
- name: androidTests-reports-api-30
- path: ${{ github.workspace }}/**/build/reports/androidTests/connected/*
+ api-level: '${{ matrix.api-level }}'
publish-snapshot:
name: 'Publish snapshot'
# TODO(bcorso): Consider also waiting on artifact-android-emulator-tests
# and artifact-android-emulator-legacy-api-tests after checking flakiness.
- needs: [bazel-test, artifact-java-local-tests, artifact-android-local-tests]
+ needs: [bazel-test, artifact-java-local-tests, artifact-android-local-tests, test-gradle-plugin]
if: github.event_name == 'push' && github.repository == 'google/dagger' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
steps:
- name: 'Install Java ${{ env.USE_JAVA_VERSION }}'
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v2
with:
+ distribution: '${{ env.USE_JAVA_DISTRIBUTION }}'
java-version: '${{ env.USE_JAVA_VERSION }}'
+ server-id: sonatype-nexus-snapshots
+ server-username: CI_DEPLOY_USERNAME
+ server-password: CI_DEPLOY_PASSWORD
- name: 'Check out repository'
uses: actions/checkout@v2
- name: 'Cache local Maven repository'
@@ -200,9 +124,9 @@ jobs:
uses: actions/cache@v2
with:
path: ~/.cache/bazel
- key: ${{ runner.os }}-bazel-${{ github.sha }}
+ key: ${{ runner.os }}-bazel-build-${{ github.sha }}
restore-keys: |
- ${{ runner.os }}-bazel-
+ ${{ runner.os }}-bazel-build-
- name: 'Cache Gradle files'
uses: actions/cache@v2
with:
@@ -218,50 +142,33 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
- name: 'Publish latest snapshot'
- run: ./util/publish-snapshot-on-commit.sh
+ run: |
+ util/deploy-all.sh \
+ "deploy:deploy-file" \
+ "HEAD-SNAPSHOT" \
+ "-DrepositoryId=sonatype-nexus-snapshots" \
+ "-Durl=https://oss.sonatype.org/content/repositories/snapshots"
shell: bash
env:
CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }}
CI_DEPLOY_PASSWORD: ${{ secrets.CI_DEPLOY_PASSWORD }}
- artifact-android-emulator-legacy-api-tests:
- name: 'Artifact Android emulator tests (API ${{ matrix.api-level }})'
- # We only run this on master push (essentially a postsubmit) since these
- # can take a while to run
+ - name: 'Clean bazel cache'
+ # According to the documentation, we should be able to exclude these via
+ # the actions/cache path, e.g. "!~/.cache/bazel/*/*/external/" but that
+ # doesn't seem to work.
+ run: |
+ rm -rf $(bazel info repository_cache)
+ rm -rf ~/.cache/bazel/*/*/external/
+ shell: bash
+ build-gradle-plugin-latest-agp:
+ name: 'Build Hilt Gradle plugin against latest AGP version'
+ # We only run this on master push (essentially a postsubmit) since we
+ # don't want this job to prevent merges
if: github.event_name == 'push' && github.repository == 'google/dagger' && github.ref == 'refs/heads/master'
- needs: bazel-test
- # It's recommended to run emulator tests on macOS
- # See https://github.com/marketplace/actions/android-emulator-runner
- runs-on: macos-latest
- strategy:
- matrix: # Run on 16 (PreL), 21 (L), and 26 (O).
- api-level: [16, 21, 26]
+ needs: bazel-build
+ runs-on: ubuntu-latest
steps:
- - name: 'Check out repository'
- uses: actions/checkout@v2
- - name: 'Cache Gradle files'
- uses: actions/cache@v2
- with:
- path: |
- ~/.gradle/caches
- ~/.gradle/wrapper
- key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
- restore-keys: |
- ${{ runner.os }}-gradle-
- - name: 'Download local snapshot for tests'
- uses: actions/download-artifact@v2
- with:
- name: local-snapshot
- path: ~/.m2/repository/com/google/dagger
- - name: 'Gradle Android emulator tests (API ${{ matrix.api-level }})'
- uses: reactivecircus/android-emulator-runner@v2
- timeout-minutes: 25
- with:
- api-level: ${{ matrix.api-level }}
- target: google_apis
- script: ./util/run-local-emulator-tests.sh
- - name: 'Upload test reports (API ${{ matrix.api-level }})'
- if: ${{ always() }}
- uses: actions/upload-artifact@v2
+ - uses: actions/checkout@v2
+ - uses: ./.github/actions/build-gradle-plugin
with:
- name: androidTests-report-api-${{ matrix.api-level }}
- path: ${{ github.workspace }}/**/build/reports/androidTests/connected/*
+ agp: '+'
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 000000000..3359c7122
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,142 @@
+name: Dagger Release
+
+on:
+ workflow_dispatch:
+ inputs:
+ dagger_release_version:
+ description: 'The Dagger version to use in this release.'
+ required: true
+
+env:
+ USE_JAVA_DISTRIBUTION: 'zulu'
+ # Our Bazel builds currently rely on JDK 8.
+ USE_JAVA_VERSION: '8'
+ # Our Bazel builds currently rely on 4.2.1. The version is set via
+ # baselisk by USE_BAZEL_VERSION: https://github.com/bazelbuild/bazelisk.
+ USE_BAZEL_VERSION: '4.2.1'
+ DAGGER_RELEASE_VERSION: "${{ github.event.inputs.dagger_release_version }}"
+
+# TODO(bcorso):Convert these jobs into local composite actions to share with the
+# continuous integration workflow.
+jobs:
+ validate-latest-dagger-version:
+ name: 'Validate Dagger version'
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: ./.github/actions/prechecks
+ bazel-build:
+ name: 'Bazel build'
+ needs: validate-latest-dagger-version
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: ./.github/actions/bazel-build
+ bazel-test:
+ name: 'Bazel tests'
+ needs: validate-latest-dagger-version
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: ./.github/actions/bazel-test
+ artifact-java-local-tests:
+ name: 'Artifact Java local tests'
+ needs: bazel-build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: ./.github/actions/artifact-java-local-tests
+ test-gradle-plugin:
+ name: 'Test Hilt Gradle plugin'
+ needs: bazel-build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: ./.github/actions/test-gradle-plugin
+ artifact-android-local-tests:
+ name: 'Artifact Android local tests (AGP ${{ matrix.agp }})'
+ needs: bazel-build
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ agp: ['4.1.0', '4.2.0', '7.0.0']
+ steps:
+ - uses: actions/checkout@v2
+ - uses: ./.github/actions/artifact-android-local-tests
+ with:
+ agp: '${{ matrix.agp }}'
+ publish-artifacts:
+ name: 'Publish Artifact'
+ needs: [bazel-test, artifact-java-local-tests, artifact-android-local-tests, test-gradle-plugin]
+ runs-on: ubuntu-latest
+ steps:
+ - name: 'Install Java ${{ env.USE_JAVA_VERSION }}'
+ uses: actions/setup-java@v2
+ with:
+ distribution: '${{ env.USE_JAVA_DISTRIBUTION }}'
+ java-version: '${{ env.USE_JAVA_VERSION }}'
+ server-id: sonatype-nexus-staging
+ server-username: CI_DEPLOY_USERNAME
+ server-password: CI_DEPLOY_PASSWORD
+ gpg-private-key: ${{ secrets.CI_GPG_PRIVATE_KEY }}
+ gpg-passphrase: CI_GPG_PASSPHRASE
+ - name: 'Check out repository'
+ uses: actions/checkout@v2
+ - name: 'Cache local Maven repository'
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.m2/repository
+ !~/.m2/repository/com/google/dagger
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+ - name: 'Cache Bazel files'
+ uses: actions/cache@v2
+ with:
+ path: ~/.cache/bazel
+ key: ${{ runner.os }}-bazel-build-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.os }}-bazel-build-
+ - name: 'Cache Gradle files'
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: Publish artifacts
+ run: |
+ util/deploy-all.sh \
+ "gpg:sign-and-deploy-file" \
+ "${{ env.DAGGER_RELEASE_VERSION }}" \
+ "-DrepositoryId=sonatype-nexus-staging" \
+ "-Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/"
+ shell: bash
+ env:
+ CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }}
+ CI_DEPLOY_PASSWORD: ${{ secrets.CI_DEPLOY_PASSWORD }}
+ CI_GPG_PASSPHRASE: ${{ secrets.CI_GPG_PASSPHRASE }}
+ - name: 'Set git credentials'
+ run: |
+ git config --global user.email "dagger-dev+github@google.com"
+ git config --global user.name "Dagger Team"
+ shell: bash
+ - name: 'Publish tagged release'
+ run: util/publish-tagged-release.sh ${{ env.DAGGER_RELEASE_VERSION }}
+ shell: bash
+ - name: 'Publish tagged docs'
+ run: util/publish-tagged-docs.sh ${{ env.DAGGER_RELEASE_VERSION }}
+ shell: bash
+ env:
+ GH_TOKEN: ${{ github.token }}
+ - name: 'Clean bazel cache'
+ # According to the documentation, we should be able to exclude these via
+ # the actions/cache path, e.g. "!~/.cache/bazel/*/*/external/" but that
+ # doesn't seem to work.
+ run: |
+ rm -rf $(bazel info repository_cache)
+ rm -rf ~/.cache/bazel/*/*/external/
+ shell: bash
diff --git a/Android.bp b/Android.bp
index 17db0d72c..61b133d92 100644
--- a/Android.bp
+++ b/Android.bp
@@ -45,7 +45,6 @@ license {
],
license_text: [
"LICENSE.txt",
- "NOTICE",
],
}
@@ -85,9 +84,18 @@ java_library {
"com.android.adservices",
"com.android.extservices",
"com.android.ondevicepersonalization",
+ "com.android.healthfitness",
+ "com.android.devicelock",
],
sdk_version: "core_current",
+
+ errorprone: {
+ javacflags: [
+ "-Xep:FormatStringAnnotation:WARN",
+ "-Xep:NoCanIgnoreReturnValueOnClasses:WARN",
+ ],
+ },
}
// build dagger2 producers library
@@ -126,6 +134,16 @@ java_plugin {
jarjar_rules: "jarjar-rules.txt",
}
+// Dagger distributes its own copy of androidx.room.compiler.processing
+// while the API is unstable. There are shading rules in jarjar-rules.txt
+// to prevent conflicts with official version. When this is removed
+// in favor of the official version the shading rules should also be
+// removed.
+java_import_host {
+ name: "dagger2-room-compiler-processing",
+ jars: ["java/dagger/internal/codegen/xprocessing/xprocessing.jar"],
+}
+
java_library_host {
name: "dagger2-compiler-lib",
use_tools_jar: true,
@@ -136,6 +154,7 @@ java_library_host {
"java/dagger/model/*.java",
"java/dagger/spi/*.java",
+ "java/dagger/spi/model/*.java",
],
exclude_srcs: [
@@ -151,11 +170,13 @@ java_library_host {
"auto_common",
"dagger2",
"dagger2-producers",
+ "dagger2-room-compiler-processing",
"google_java_format",
"guava",
"javapoet",
"jsr330",
"kotlin-stdlib",
+ "kotlin-stdlib-jdk8",
"kotlinx_metadata_jvm",
],
@@ -193,6 +214,13 @@ java_library_host {
"--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
"--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
],
+
+ errorprone: {
+ javacflags: [
+ "-Xep:FormatStringAnnotation:WARN",
+ "-Xep:NoCanIgnoreReturnValueOnClasses:WARN",
+ ],
+ },
}
// Compile dummy implementations of annotations used by dagger2 but not
@@ -230,7 +258,9 @@ java_library {
"hilt_generates_root_input_processor",
],
apex_available: [
+ "//apex_available:platform",
"com.android.ondevicepersonalization",
+ "com.android.healthfitness",
],
}
@@ -242,18 +272,22 @@ android_library {
srcs: [
"java/dagger/hilt/android/*.java",
+ "java/dagger/hilt/android/*.kt",
"java/dagger/hilt/android/components/*.java",
+ "java/dagger/hilt/android/flags/*.java",
"java/dagger/hilt/android/migration/*.java",
"java/dagger/hilt/android/qualifiers/*.java",
"java/dagger/hilt/android/scopes/*.java",
"java/dagger/hilt/android/internal/*.java",
"java/dagger/hilt/android/internal/builders/*.java",
+ "java/dagger/hilt/android/internal/legacy/*.java",
"java/dagger/hilt/android/internal/lifecycle/*.java",
"java/dagger/hilt/android/internal/managers/*.java",
"java/dagger/hilt/android/internal/migration/*.java",
"java/dagger/hilt/android/internal/modules/*.java",
"java/dagger/hilt/android/lifecycle/*.java",
"java/dagger/hilt/internal/aggregatedroot/*.java",
+ "java/dagger/hilt/internal/componenttreedeps/*.java",
"java/dagger/hilt/internal/processedrootsentinel/*.java",
],
manifest: "java/dagger/hilt/android/AndroidManifest.xml",
@@ -282,17 +316,22 @@ android_library {
],
exported_plugins: [
"dagger2-compiler",
+
"hilt_android_entry_point_processor",
"hilt_aggregated_deps_processor",
"hilt_alias_of_processor",
+ "hilt_component_tree_deps_processor",
"hilt_define_component_processor",
+ "hilt_early_entry_point_processor",
"hilt_generates_root_input_processor",
"hilt_originating_element_processor",
"hilt_root_processor",
"hilt_viewmodel_processor",
],
apex_available: [
+ "//apex_available:platform",
"com.android.ondevicepersonalization",
+ "com.android.healthfitness",
],
}
@@ -302,7 +341,10 @@ android_library {
srcs: [
"java/dagger/hilt/android/internal/testing/*.java",
+ "java/dagger/hilt/android/internal/testing/root/*.java",
+ "java/dagger/hilt/android/internal/uninstallmodules/*.java",
"java/dagger/hilt/android/testing/*.java",
+ "java/dagger/hilt/testing/*.java",
],
manifest: "java/dagger/hilt/android/testing/AndroidManifest.xml",
static_libs: [
@@ -315,6 +357,7 @@ android_library {
"android-support-multidex",
"jsr305",
"dagger2",
+ "hilt_android",
"hilt_core",
"junit",
],
@@ -327,13 +370,18 @@ android_library {
],
exported_plugins: [
"dagger2-compiler",
+
"hilt_android_entry_point_processor",
"hilt_aggregated_deps_processor",
+ "hilt_alias_of_processor",
+ "hilt_component_tree_deps_processor",
"hilt_define_component_processor",
+ "hilt_early_entry_point_processor",
"hilt_generates_root_input_processor",
"hilt_originating_element_processor",
"hilt_root_processor",
- "hilt_viewmodel_processor",
+ "hilt_viewmodel_processor",
+
"hilt_custom_test_application_processor",
"hilt_bindvalue_processor",
"hilt_uninstall_modules_processor",
@@ -370,12 +418,24 @@ java_plugin {
}
java_plugin {
+ name: "hilt_component_tree_deps_processor",
+ generates_api: true,
+ processor_class: "dagger.hilt.processor.internal.root.ComponentTreeDepsProcessor",
+}
+
+java_plugin {
name: "hilt_define_component_processor",
generates_api: true,
processor_class: "dagger.hilt.processor.internal.definecomponent.DefineComponentProcessor",
}
java_plugin {
+ name: "hilt_early_entry_point_processor",
+ generates_api: true,
+ processor_class: "dagger.hilt.processor.internal.earlyentrypoint.EarlyEntryPointProcessor",
+}
+
+java_plugin {
name: "hilt_originating_element_processor",
generates_api: true,
processor_class: "dagger.hilt.processor.internal.originatingelement.OriginatingElementProcessor",
@@ -420,6 +480,7 @@ java_library_host {
"java/dagger/hilt/android/processor/**/*.kt",
"java/dagger/hilt/codegen/*.java",
"java/dagger/hilt/processor/internal/**/*.java",
+ "java/dagger/hilt/processor/internal/**/*.kt",
],
plugins: [
"auto_service_plugin",
diff --git a/BUILD b/BUILD
index b2495d7ee..8692ea11d 100644
--- a/BUILD
+++ b/BUILD
@@ -79,7 +79,7 @@ jarjar_library(
name = "shaded_android_processor",
jars = [
"//java/dagger/android/processor",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
],
rules = [
"rule com.google.auto.common.** dagger.android.shaded.auto.common.@1",
@@ -90,7 +90,7 @@ jarjar_library(
name = "shaded_grpc_server_processor",
jars = [
"//java/dagger/grpc/server/processor",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
],
rules = [
"rule com.google.auto.common.** dagger.grpc.shaded.auto.common.@1",
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 54fb50aa9..f0748e091 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -28,6 +28,10 @@ information on using pull requests.
Dagger is built with [`bazel`](https://bazel.build).
+Ensure that Dagger is checked out on a case-sensitive filesystem. On a
+case-insensitive file system (e.g. Windows or MacOS by default) some tasks that
+attempt to delete the `build/` folder will also delete the bazel `BUILD` files.
+
### Building Dagger from the command line
* [Install Bazel](https://docs.bazel.build/versions/master/install.html)
diff --git a/LICENSE b/LICENSE
new file mode 120000
index 000000000..85de3d454
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+LICENSE.txt \ No newline at end of file
diff --git a/METADATA b/METADATA
index 5eef5c3b8..c9c792571 100644
--- a/METADATA
+++ b/METADATA
@@ -11,7 +11,7 @@ third_party {
type: GIT
value: "https://github.com/google/dagger"
}
- version: "dagger-2.19.1"
- last_upgrade_date { year: 2020 month: 11 day: 18 }
+ version: "dagger-2.41"
+ last_upgrade_date { year: 2022 month: 04 day: 04 }
license_type: NOTICE
}
diff --git a/NOTICE b/NOTICE
deleted file mode 100644
index d64569567..000000000
--- a/NOTICE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/OWNERS b/OWNERS
index 87a5dbee3..fcafdd6af 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1 +1,3 @@
include platform/libcore:/OWNERS
+
+ccross@android.com
diff --git a/README.md b/README.md
index 393e2e7c7..fce903205 100644
--- a/README.md
+++ b/README.md
@@ -39,8 +39,8 @@ release.
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-DAGGER_TAG = "2.28.1"
-DAGGER_SHA = "9e69ab2f9a47e0f74e71fe49098bea908c528aa02fa0c5995334447b310d0cdd"
+DAGGER_TAG = "2.40.5"
+DAGGER_SHA = "5a6923e56edbc1e34c8089ecab5338a1b8ddb79a3a54b6c86cdcf31212680d32"
http_archive(
name = "dagger",
strip_prefix = "dagger-dagger-%s" % DAGGER_TAG,
diff --git a/WORKSPACE b/WORKSPACE
index d49c0e2f3..d37a5a32e 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -15,6 +15,39 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
#############################
+# Upgrade java_tools version
+#############################
+
+# These targets added per instructions at
+# https://github.com/bazelbuild/java_tools/releases/tag/javac11_v10.7
+http_archive(
+ name = "remote_java_tools_linux",
+ sha256 = "cf57fc238ed5c24c718436ab4178ade5eb838fe56e7c32c4fafe0b6fbdaec51f",
+ urls = [
+ "https://mirror.bazel.build/bazel_java_tools/releases/javac11/v10.7/java_tools_javac11_linux-v10.7.zip",
+ "https://github.com/bazelbuild/java_tools/releases/download/javac11_v10.7/java_tools_javac11_linux-v10.7.zip",
+ ],
+)
+
+http_archive(
+ name = "remote_java_tools_windows",
+ sha256 = "a0fc3a3be3ea01a4858d12f56892dd663c02f218104e8c1dc9f3e90d5e583bcb",
+ urls = [
+ "https://mirror.bazel.build/bazel_java_tools/releases/javac11/v10.7/java_tools_javac11_windows-v10.7.zip",
+ "https://github.com/bazelbuild/java_tools/releases/download/javac11_v10.7/java_tools_javac11_windows-v10.7.zip",
+ ],
+)
+
+http_archive(
+ name = "remote_java_tools_darwin",
+ sha256 = "51a4cf424d3b26d6c42703cf2d80002f1489ba0d28c939519c3bb9c3d6ee3720",
+ urls = [
+ "https://mirror.bazel.build/bazel_java_tools/releases/javac11/v10.7/java_tools_javac11_darwin-v10.7.zip",
+ "https://github.com/bazelbuild/java_tools/releases/download/javac11_v10.7/java_tools_javac11_darwin-v10.7.zip",
+ ],
+)
+
+#############################
# Load nested repository
#############################
@@ -31,9 +64,9 @@ local_repository(
http_archive(
name = "google_bazel_common",
- sha256 = "d8aa0ef609248c2a494d5dbdd4c89ef2a527a97c5a87687e5a218eb0b77ff640",
- strip_prefix = "bazel-common-4a8d451e57fb7e1efecbf9495587a10684a19eb2",
- urls = ["https://github.com/google/bazel-common/archive/4a8d451e57fb7e1efecbf9495587a10684a19eb2.zip"],
+ sha256 = "8b6aebdc095c8448b2f6a72bb8eae4a563891467e2d20c943f21940b1c444e38",
+ strip_prefix = "bazel-common-3d0e5005cfcbee836e31695d4ab91b5328ccc506",
+ urls = ["https://github.com/google/bazel-common/archive/3d0e5005cfcbee836e31695d4ab91b5328ccc506.zip"],
)
load("@google_bazel_common//:workspace_defs.bzl", "google_common_workspace_rules")
@@ -87,36 +120,41 @@ robolectric_repositories()
# Load Kotlin repository
#############################
-RULES_KOTLIN_COMMIT = "2c283821911439e244285b5bfec39148e7d90e21"
+RULES_KOTLIN_COMMIT = "686f0f1cf3e1cc8c750688bb082316b3eadb3cb6"
-RULES_KOTLIN_SHA = "b04cd539e7e3571745179da95069586b6fa76a64306b24bb286154e652010608"
+RULES_KOTLIN_SHA = "1d8758bbf27400a5f9d40f01e4337f6834d2b7864df34e9aa5cf0a9ab6cc9241"
http_archive(
- name = "io_bazel_rules_kotlin",
+ name = "io_bazel_rules_kotlin_head",
sha256 = RULES_KOTLIN_SHA,
strip_prefix = "rules_kotlin-%s" % RULES_KOTLIN_COMMIT,
type = "zip",
urls = ["https://github.com/bazelbuild/rules_kotlin/archive/%s.zip" % RULES_KOTLIN_COMMIT],
)
-load("@io_bazel_rules_kotlin//kotlin:dependencies.bzl", "kt_download_local_dev_dependencies")
+load("@io_bazel_rules_kotlin_head//src/main/starlark/release_archive:repository.bzl", "archive_repository")
-kt_download_local_dev_dependencies()
+archive_repository(
+ name = "io_bazel_rules_kotlin",
+ source_repository_name = "io_bazel_rules_kotlin_head",
+)
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kotlin_repositories")
+load("@io_bazel_rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories", "kotlinc_version")
-KOTLIN_VERSION = "1.4.20"
+KOTLIN_VERSION = "1.5.32"
-KOTLINC_RELEASE_SHA = "11db93a4d6789e3406c7f60b9f267eba26d6483dcd771eff9f85bb7e9837011f"
+KOTLINC_RELEASE_SHA = "2e728c43ee0bf819eae06630a4cbbc28ba2ed5b19a55ee0af96d2c0ab6b6c2a5"
-KOTLINC_RELEASE = {
- "sha256": KOTLINC_RELEASE_SHA,
- "urls": ["https://github.com/JetBrains/kotlin/releases/download/v{v}/kotlin-compiler-{v}.zip".format(v = KOTLIN_VERSION)],
-}
+kotlin_repositories(
+ compiler_release = kotlinc_version(
+ release = KOTLIN_VERSION,
+ sha256 = KOTLINC_RELEASE_SHA,
+ ),
+)
-kotlin_repositories(compiler_release = KOTLINC_RELEASE)
+load("@io_bazel_rules_kotlin//kotlin:core.bzl", "kt_register_toolchains")
-register_toolchains("//:kotlin_toolchain")
+kt_register_toolchains()
#############################
# Load Maven dependencies
@@ -135,23 +173,39 @@ http_archive(
load("@rules_jvm_external//:defs.bzl", "maven_install")
-ANDROID_LINT_VERSION = "26.6.2"
+ANDROID_LINT_VERSION = "30.1.0"
+
+AUTO_COMMON_VERSION = "1.2.1"
+
+# NOTE(bcorso): Even though we set the version here, our Guava version in
+# processor code will use whatever version is built into JavaBuilder, which is
+# tied to the version of Bazel we're using.
+GUAVA_VERSION = "27.1"
+
+GRPC_VERSION = "1.2.0"
+
+INCAP_VERSION = "0.2"
+
+BYTE_BUDDY_VERSION = "1.9.10"
+
+CHECKER_FRAMEWORK_VERSION = "2.5.3"
+
+ERROR_PRONE_VERSION = "2.3.2"
maven_install(
artifacts = [
"androidx.annotation:annotation:1.1.0",
- "androidx.appcompat:appcompat:1.2.0",
- "androidx.activity:activity:1.2.2",
- "androidx.fragment:fragment:1.3.2",
+ "androidx.appcompat:appcompat:1.3.1",
+ "androidx.activity:activity:1.3.1",
+ "androidx.fragment:fragment:1.3.6",
"androidx.lifecycle:lifecycle-common:2.3.1",
"androidx.lifecycle:lifecycle-viewmodel:2.3.1",
"androidx.lifecycle:lifecycle-viewmodel-savedstate:2.3.1",
"androidx.multidex:multidex:2.0.1",
"androidx.savedstate:savedstate:1.0.0",
- "androidx.test:monitor:1.1.1",
- "androidx.test:core:1.1.0",
- "androidx.test.ext:junit:1.1.2",
- "com.google.auto:auto-common:0.11",
+ "androidx.test:monitor:1.4.0",
+ "androidx.test:core:1.4.0",
+ "androidx.test.ext:junit:1.1.3",
"com.android.support:appcompat-v7:25.0.0",
"com.android.support:support-annotations:25.0.0",
"com.android.support:support-fragment:25.0.0",
@@ -164,17 +218,54 @@ maven_install(
"com.android.tools.lint:lint-tests:%s" % ANDROID_LINT_VERSION,
"com.android.tools:testutils:%s" % ANDROID_LINT_VERSION,
"com.github.tschuchortdev:kotlin-compile-testing:1.2.8",
- "com.google.guava:guava:27.1-android",
+ "com.google.auto:auto-common:%s" % AUTO_COMMON_VERSION,
+ "com.google.auto.factory:auto-factory:1.0",
+ "com.google.auto.service:auto-service:1.0",
+ "com.google.auto.service:auto-service-annotations:1.0",
+ "com.google.auto.value:auto-value:1.6",
+ "com.google.auto.value:auto-value-annotations:1.6",
+ "com.google.code.findbugs:jsr305:3.0.1",
+ "com.google.devtools.ksp:symbol-processing-api:1.5.30-1.0.0",
+ "com.google.errorprone:error_prone_annotation:%s" % ERROR_PRONE_VERSION,
+ "com.google.errorprone:error_prone_annotations:%s" % ERROR_PRONE_VERSION,
+ "com.google.errorprone:error_prone_check_api:%s" % ERROR_PRONE_VERSION,
+ "com.google.googlejavaformat:google-java-format:1.5",
+ "com.google.guava:guava:%s-jre" % GUAVA_VERSION,
+ "com.google.guava:guava-testlib:%s-jre" % GUAVA_VERSION,
+ "com.google.guava:failureaccess:1.0.1",
+ "com.google.guava:guava-beta-checker:1.0",
+ "com.google.protobuf:protobuf-java:3.7.0",
+ "com.google.testing.compile:compile-testing:0.18",
+ "com.google.truth:truth:1.1",
+ "com.squareup:javapoet:1.13.0",
+ "io.grpc:grpc-context:%s" % GRPC_VERSION,
+ "io.grpc:grpc-core:%s" % GRPC_VERSION,
+ "io.grpc:grpc-netty:%s" % GRPC_VERSION,
+ "io.grpc:grpc-protobuf:%s" % GRPC_VERSION,
+ "jakarta.inject:jakarta.inject-api:2.0.1",
+ "javax.annotation:jsr250-api:1.0",
+ "javax.inject:javax.inject:1",
+ "javax.inject:javax.inject-tck:1",
"junit:junit:4.13",
+ "net.bytebuddy:byte-buddy:%s" % BYTE_BUDDY_VERSION,
+ "net.bytebuddy:byte-buddy-agent:%s" % BYTE_BUDDY_VERSION,
+ "net.ltgt.gradle.incap:incap:%s" % INCAP_VERSION,
+ "net.ltgt.gradle.incap:incap-processor:%s" % INCAP_VERSION,
+ "org.checkerframework:checker-compat-qual:%s" % CHECKER_FRAMEWORK_VERSION,
+ "org.checkerframework:dataflow:%s" % CHECKER_FRAMEWORK_VERSION,
+ "org.checkerframework:javacutil:%s" % CHECKER_FRAMEWORK_VERSION,
+ "org.hamcrest:hamcrest-core:1.3",
"org.jetbrains.kotlin:kotlin-stdlib:%s" % KOTLIN_VERSION,
- "org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.2.0",
+ "org.jetbrains.kotlin:kotlin-stdlib-jdk8:%s" % KOTLIN_VERSION,
+ "org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.3.0",
+ "org.mockito:mockito-core:2.28.2",
+ "org.objenesis:objenesis:1.0",
"org.robolectric:robolectric:4.4",
"org.robolectric:shadows-framework:4.4", # For ActivityController
],
repositories = [
"https://repo1.maven.org/maven2",
"https://maven.google.com",
- "https://jcenter.bintray.com/", # Lint has one trove4j dependency in jCenter
],
)
diff --git a/android-annotation-stubs/gen_annotations.sh b/android-annotation-stubs/gen_annotations.sh
index d4a029029..1aa5d278b 100755
--- a/android-annotation-stubs/gen_annotations.sh
+++ b/android-annotation-stubs/gen_annotations.sh
@@ -58,9 +58,14 @@ cat > ${f} <<EOF
*/
package net.ltgt.gradle.incap;
+import java.util.Locale;
public enum IncrementalAnnotationProcessorType {
AGGREGATING,
DYNAMIC,
- ISOLATING
+ ISOLATING;
+
+ public String getProcessorOption() {
+ return "org.gradle.annotation.processing." + name().toLowerCase(Locale.ROOT);
+ }
}
EOF
diff --git a/android-annotation-stubs/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessorType.java b/android-annotation-stubs/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessorType.java
index ef86328ae..55a3a5e47 100644
--- a/android-annotation-stubs/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessorType.java
+++ b/android-annotation-stubs/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessorType.java
@@ -15,8 +15,13 @@
*/
package net.ltgt.gradle.incap;
+import java.util.Locale;
public enum IncrementalAnnotationProcessorType {
AGGREGATING,
DYNAMIC,
- ISOLATING
+ ISOLATING;
+
+ public String getProcessorOption() {
+ return "org.gradle.annotation.processing." + name().toLowerCase(Locale.ROOT);
+ }
}
diff --git a/examples/bazel/WORKSPACE b/examples/bazel/WORKSPACE
index 23f93b11c..6a1197f4d 100644
--- a/examples/bazel/WORKSPACE
+++ b/examples/bazel/WORKSPACE
@@ -19,7 +19,9 @@
# Load Dagger repository
########################
-# TODO(bcorso): Replace with `http_archive` pointing to tagged released.
+# In a real project, this repository would use `http_archive` to link to a
+# tagged, released version of the Dagger, but we use `local_repository` so that
+# CI testing can test local changes to workspace_defs.bzl.
local_repository(
name = "dagger",
path = "../../",
diff --git a/jarjar-rules.txt b/jarjar-rules.txt
index 57941b373..abb7fb27a 100644
--- a/jarjar-rules.txt
+++ b/jarjar-rules.txt
@@ -1,3 +1,6 @@
# shade guava to avoid conflicts with guava embedded in Error Prone.
rule com.google.common.** com.google.dagger.common.@1
rule com.google.auto.** com.google.dagger.auto.@1
+
+# shade local xprocessing.jar to avoid conflicts with upstream Xprocessing
+rule androidx.room.compiler.processing.** dagger.spi.shaded.androidx.room.compiler.processing.@1
diff --git a/java/dagger/BUILD b/java/dagger/BUILD
index aaebadee0..17c6c9665 100644
--- a/java/dagger/BUILD
+++ b/java/dagger/BUILD
@@ -32,9 +32,9 @@ java_library(
srcs = glob(["**/*.java"]),
javacopts = SOURCE_7_TARGET_7 + DOCLINT_HTML_AND_SYNTAX,
tags = ["maven_coordinates=com.google.dagger:dagger:" + POM_VERSION],
- exports = ["@google_bazel_common//third_party/java/jsr330_inject"],
+ exports = ["//third_party/java/jsr330_inject"],
deps = [
- "@google_bazel_common//third_party/java/jsr330_inject",
+ "//third_party/java/jsr330_inject",
],
)
@@ -55,5 +55,5 @@ javadoc_library(
srcs = [":javadoc-srcs"],
exclude_packages = ["dagger.internal"],
root_packages = ["dagger"],
- deps = ["@google_bazel_common//third_party/java/jsr330_inject"],
+ deps = ["//third_party/java/jsr330_inject"],
)
diff --git a/java/dagger/Component.java b/java/dagger/Component.java
index 709b0e6be..be746e815 100644
--- a/java/dagger/Component.java
+++ b/java/dagger/Component.java
@@ -35,14 +35,16 @@ import javax.inject.Singleton;
* example, {@code @Component interface MyComponent {...}} will produce an implementation named
* {@code DaggerMyComponent}.
*
- * <a name="component-methods"></a>
+ * <p><a id="component-methods"></a>
+ *
* <h2>Component methods</h2>
*
* <p>Every type annotated with {@code @Component} must contain at least one abstract component
* method. Component methods may have any name, but must have signatures that conform to either
* {@linkplain Provider provision} or {@linkplain MembersInjector members-injection} contracts.
*
- * <a name="provision-methods"></a>
+ * <p><a id="provision-methods"></a>
+ *
* <h3>Provision methods</h3>
*
* <p>Provision methods have no parameters and return an {@link Inject injected} or {@link Provides
@@ -68,7 +70,8 @@ import javax.inject.Singleton;
* {@literal Lazy<SomeType>} getLazySomeType();
* </code></pre>
*
- * <a name="members-injection-methods"></a>
+ * <a id="members-injection-methods"></a>
+ *
* <h3>Members-injection methods</h3>
*
* <p>Members-injection methods have a single parameter and inject dependencies into each of the
@@ -111,7 +114,8 @@ import javax.inject.Singleton;
* }
* </code></pre>
*
- * <a name="instantiation"></a>
+ * <a id="instantiation"></a>
+ *
* <h2>Instantiation</h2>
*
* <p>Component implementations are primarily instantiated via a generated <a
@@ -131,17 +135,17 @@ import javax.inject.Singleton;
* <p>Example of using a builder:
*
* <pre>{@code
- * public static void main(String[] args) {
- * OtherComponent otherComponent = ...;
- * MyComponent component = DaggerMyComponent.builder()
- * // required because component dependencies must be set
- * .otherComponent(otherComponent)
- * // required because FlagsModule has constructor parameters
- * .flagsModule(new FlagsModule(args))
- * // may be elided because a no-args constructor is visible
- * .myApplicationModule(new MyApplicationModule())
- * .build();
- * }
+ * public static void main(String[] args) {
+ * OtherComponent otherComponent = ...;
+ * MyComponent component = DaggerMyComponent.builder()
+ * // required because component dependencies must be set
+ * .otherComponent(otherComponent)
+ * // required because FlagsModule has constructor parameters
+ * .flagsModule(new FlagsModule(args))
+ * // may be elided because a no-args constructor is visible
+ * .myApplicationModule(new MyApplicationModule())
+ * .build();
+ * }
* }</pre>
*
* <p>Example of using a factory:
@@ -162,7 +166,8 @@ import javax.inject.Singleton;
* SomeComponent.create()} and {@code SomeComponent.builder().build()} are both valid and
* equivalent.
*
- * <a name="scope"></a>
+ * <p><a id="scope"></a>
+ *
* <h2>Scope</h2>
*
* <p>Each Dagger component can be associated with a scope by annotating it with the {@linkplain
@@ -184,14 +189,16 @@ import javax.inject.Singleton;
* self-contained implementations, exiting a scope is as simple as dropping all references to the
* component instance.
*
- * <a name="component-relationships"></a>
+ * <p><a id="component-relationships"></a>
+ *
* <h2>Component relationships</h2>
*
* <p>While there is much utility in isolated components with purely unscoped bindings, many
* applications will call for multiple components with multiple scopes to interact. Dagger provides
* two mechanisms for relating components.
*
- * <a name="subcomponents"></a>
+ * <p><a id="subcomponents"></a>
+ *
* <h3>Subcomponents</h3>
*
* <p>The simplest way to relate two components is by declaring a {@link Subcomponent}. A
@@ -219,7 +226,8 @@ import javax.inject.Singleton;
* }
* </code></pre>
*
- * <a name="component-dependencies"></a>
+ * <a id="component-dependencies"></a>
+ *
* <h3>Component dependencies</h3>
*
* <p>While subcomponents are the simplest way to compose subgraphs of bindings, subcomponents are
diff --git a/java/dagger/Module.java b/java/dagger/Module.java
index bd32a1f23..a3cdb54b8 100644
--- a/java/dagger/Module.java
+++ b/java/dagger/Module.java
@@ -23,18 +23,15 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-/**
- * Annotates a class that contributes to the object graph.
- */
+/** Annotates a class that contributes to the object graph. */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Module {
/**
- * Additional {@code @Module}-annotated classes from which this module is
- * composed. The de-duplicated contributions of the modules in
- * {@code includes}, and of their inclusions recursively, are all contributed
- * to the object graph.
+ * Additional {@code @Module}-annotated classes from which this module is composed. The
+ * de-duplicated contributions of the modules in {@code includes}, and of their inclusions
+ * recursively, are all contributed to the object graph.
*/
Class<?>[] includes() default {};
diff --git a/java/dagger/Provides.java b/java/dagger/Provides.java
index 5d7827be7..011f9903f 100644
--- a/java/dagger/Provides.java
+++ b/java/dagger/Provides.java
@@ -33,14 +33,14 @@ import java.lang.annotation.Target;
* <p>Dagger forbids injecting {@code null} by default. Component implementations that invoke
* {@code @Provides} methods that return {@code null} will throw a {@link NullPointerException}
* immediately thereafter. {@code @Provides} methods may opt into allowing {@code null} by
- * annotating the method with any {@code @Nullable} annotation like
- * {@code javax.annotation.Nullable} or {@code androidx.annotation.Nullable}.
+ * annotating the method with any {@code @Nullable} annotation like {@code
+ * javax.annotation.Nullable} or {@code androidx.annotation.Nullable}.
*
- * <p>If a {@code @Provides} method is marked {@code @Nullable}, Dagger will <em>only</em>
- * allow injection into sites that are marked {@code @Nullable} as well. A component that
- * attempts to pair a {@code @Nullable} provision with a non-{@code @Nullable} injection site
- * will fail to compile.
+ * <p>If a {@code @Provides} method is marked {@code @Nullable}, Dagger will <em>only</em> allow
+ * injection into sites that are marked {@code @Nullable} as well. A component that attempts to pair
+ * a {@code @Nullable} provision with a non-{@code @Nullable} injection site will fail to compile.
*/
-@Documented @Target(METHOD) @Retention(RUNTIME)
-public @interface Provides {
-}
+@Documented
+@Target(METHOD)
+@Retention(RUNTIME)
+public @interface Provides {}
diff --git a/java/dagger/android/BUILD b/java/dagger/android/BUILD
index f0cea4149..503a29860 100644
--- a/java/dagger/android/BUILD
+++ b/java/dagger/android/BUILD
@@ -54,8 +54,8 @@ android_library(
],
deps = [
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/error_prone:annotations",
+ "//third_party/java/auto:value",
+ "//third_party/java/error_prone:annotations",
"@maven//:androidx_annotation_annotation",
],
)
@@ -68,14 +68,6 @@ pom_file(
targets = [":android"],
)
-# b/37741866 and https://github.com/google/dagger/issues/715
-pom_file(
- name = "jarimpl-pom",
- artifact_id = "dagger-android-jarimpl",
- artifact_name = "Dagger Android",
- targets = [":android"],
-)
-
dejetified_library(
name = "dejetified-android",
input = ":android.aar",
@@ -87,8 +79,8 @@ android_library(
tags = ["maven_coordinates=com.google.dagger:dagger-android-legacy:" + POM_VERSION],
exports = [
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/error_prone:annotations",
+ "//third_party/java/auto:value",
+ "//third_party/java/error_prone:annotations",
"@maven//:com_android_support_support_annotations",
],
)
diff --git a/java/dagger/android/internal/proguard/BUILD b/java/dagger/android/internal/proguard/BUILD
index a11d0c07e..5a85279fb 100644
--- a/java/dagger/android/internal/proguard/BUILD
+++ b/java/dagger/android/internal/proguard/BUILD
@@ -25,7 +25,7 @@ java_library(
srcs = ["ProguardProcessor.java"],
javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
deps = [
- "@google_bazel_common//third_party/java/auto:service",
+ "//third_party/java/auto:service",
],
)
diff --git a/java/dagger/android/processor/AndroidInjectorDescriptor.java b/java/dagger/android/processor/AndroidInjectorDescriptor.java
index 3ec66139e..0b9d74b6d 100644
--- a/java/dagger/android/processor/AndroidInjectorDescriptor.java
+++ b/java/dagger/android/processor/AndroidInjectorDescriptor.java
@@ -16,10 +16,8 @@
package dagger.android.processor;
-import static com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations;
import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
-import static com.google.auto.common.MoreElements.getAnnotationMirror;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotatedAnnotations;
import static java.util.stream.Collectors.toList;
import static javax.lang.model.element.Modifier.ABSTRACT;
@@ -27,16 +25,13 @@ import com.google.auto.common.MoreElements;
import com.google.auto.common.MoreTypes;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeName;
-import dagger.Module;
-import dagger.android.ContributesAndroidInjector;
import java.util.List;
import java.util.Optional;
import javax.annotation.processing.Messager;
-import javax.inject.Qualifier;
-import javax.inject.Scope;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
@@ -47,24 +42,24 @@ import javax.lang.model.util.SimpleAnnotationValueVisitor8;
import javax.tools.Diagnostic.Kind;
/**
- * A descriptor of a generated {@link Module} and {@link dagger.Subcomponent} to be generated from a
- * {@link ContributesAndroidInjector} method.
+ * A descriptor of a generated {@link dagger.Module} and {@link dagger.Subcomponent} to be generated
+ * from a {@code ContributesAndroidInjector} method.
*/
@AutoValue
abstract class AndroidInjectorDescriptor {
- /** The type to be injected; the return type of the {@link ContributesAndroidInjector} method. */
+ /** The type to be injected; the return type of the {@code ContributesAndroidInjector} method. */
abstract ClassName injectedType();
/** Scopes to apply to the generated {@link dagger.Subcomponent}. */
abstract ImmutableSet<AnnotationSpec> scopes();
- /** @see ContributesAndroidInjector#modules() */
+ /** See {@code ContributesAndroidInjector#modules()} */
abstract ImmutableSet<ClassName> modules();
- /** The {@link Module} that contains the {@link ContributesAndroidInjector} method. */
+ /** The {@link dagger.Module} that contains the {@code ContributesAndroidInjector} method. */
abstract ClassName enclosingModule();
- /** The method annotated with {@link ContributesAndroidInjector}. */
+ /** The method annotated with {@code ContributesAndroidInjector}. */
abstract ExecutableElement method();
@AutoValue.Builder
@@ -90,7 +85,7 @@ abstract class AndroidInjectorDescriptor {
}
/**
- * Validates a {@link ContributesAndroidInjector} method, returning an {@link
+ * Validates a {@code ContributesAndroidInjector} method, returning an {@link
* AndroidInjectorDescriptor} if it is valid, or {@link Optional#empty()} otherwise.
*/
Optional<AndroidInjectorDescriptor> createIfValid(ExecutableElement method) {
@@ -107,7 +102,7 @@ abstract class AndroidInjectorDescriptor {
AndroidInjectorDescriptor.Builder builder =
new AutoValue_AndroidInjectorDescriptor.Builder().method(method);
TypeElement enclosingElement = MoreElements.asType(method.getEnclosingElement());
- if (!isAnnotationPresent(enclosingElement, Module.class)) {
+ if (!MoreDaggerElements.isAnnotationPresent(enclosingElement, TypeNames.MODULE)) {
reporter.reportError("@ContributesAndroidInjector methods must be in a @Module");
}
builder.enclosingModule(ClassName.get(enclosingElement));
@@ -121,21 +116,26 @@ abstract class AndroidInjectorDescriptor {
}
AnnotationMirror annotation =
- getAnnotationMirror(method, ContributesAndroidInjector.class).get();
+ MoreDaggerElements.getAnnotationMirror(method, TypeNames.CONTRIBUTES_ANDROID_INJECTOR)
+ .get();
for (TypeMirror module :
getAnnotationValue(annotation, "modules").accept(new AllTypesVisitor(), null)) {
- if (isAnnotationPresent(MoreTypes.asElement(module), Module.class)) {
+ if (MoreDaggerElements.isAnnotationPresent(MoreTypes.asElement(module), TypeNames.MODULE)) {
builder.modulesBuilder().add((ClassName) TypeName.get(module));
} else {
reporter.reportError(String.format("%s is not a @Module", module), annotation);
}
}
- for (AnnotationMirror scope : getAnnotatedAnnotations(method, Scope.class)) {
+ for (AnnotationMirror scope : Sets.union(
+ getAnnotatedAnnotations(method, TypeNames.SCOPE),
+ getAnnotatedAnnotations(method, TypeNames.SCOPE_JAVAX))) {
builder.scopesBuilder().add(AnnotationSpec.get(scope));
}
- for (AnnotationMirror qualifier : getAnnotatedAnnotations(method, Qualifier.class)) {
+ for (AnnotationMirror qualifier : Sets.union(
+ getAnnotatedAnnotations(method, TypeNames.QUALIFIER),
+ getAnnotatedAnnotations(method, TypeNames.QUALIFIER_JAVAX))) {
reporter.reportError(
"@ContributesAndroidInjector methods cannot have qualifiers", qualifier);
}
diff --git a/java/dagger/android/processor/AndroidMapKeyValidator.java b/java/dagger/android/processor/AndroidMapKeyValidator.java
index f6e808ac6..02135265e 100644
--- a/java/dagger/android/processor/AndroidMapKeyValidator.java
+++ b/java/dagger/android/processor/AndroidMapKeyValidator.java
@@ -17,25 +17,19 @@
package dagger.android.processor;
import static com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations;
-import static com.google.auto.common.MoreElements.getAnnotationMirror;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.android.processor.AndroidMapKeys.injectedTypeFromMapKey;
+import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotatedAnnotations;
-import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
+import com.google.auto.common.BasicAnnotationProcessor.Step;
import com.google.auto.common.MoreElements;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.SetMultimap;
-import dagger.Binds;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Sets;
+import com.squareup.javapoet.ClassName;
import dagger.MapKey;
-import dagger.android.AndroidInjectionKey;
-import dagger.android.AndroidInjector;
-import dagger.multibindings.ClassKey;
-import java.lang.annotation.Annotation;
-import java.util.Set;
import javax.annotation.processing.Messager;
-import javax.inject.Qualifier;
-import javax.inject.Scope;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
@@ -46,8 +40,13 @@ import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic.Kind;
-/** Validates the correctness of {@link MapKey}s used with {@code dagger.android}. */
-final class AndroidMapKeyValidator implements ProcessingStep {
+/** Validates the correctness of {@link dagger.MapKey}s used with {@code dagger.android}. */
+final class AndroidMapKeyValidator implements Step {
+ private static final ImmutableMap<String, ClassName> SUPPORTED_ANNOTATIONS =
+ ImmutableMap.of(
+ TypeNames.ANDROID_INJECTION_KEY.toString(), TypeNames.ANDROID_INJECTION_KEY,
+ TypeNames.CLASS_KEY.toString(), TypeNames.CLASS_KEY);
+
private final Elements elements;
private final Types types;
private final Messager messager;
@@ -59,16 +58,12 @@ final class AndroidMapKeyValidator implements ProcessingStep {
}
@Override
- public Set<? extends Class<? extends Annotation>> annotations() {
- return ImmutableSet.<Class<? extends Annotation>>builder()
- .add(AndroidInjectionKey.class)
- .add(ClassKey.class)
- .build();
+ public ImmutableSet<String> annotations() {
+ return SUPPORTED_ANNOTATIONS.keySet();
}
@Override
- public Set<Element> process(
- SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ public ImmutableSet<Element> process(ImmutableSetMultimap<String, Element> elementsByAnnotation) {
ImmutableSet.Builder<Element> deferredElements = ImmutableSet.builder();
elementsByAnnotation
.entries()
@@ -83,8 +78,9 @@ final class AndroidMapKeyValidator implements ProcessingStep {
return deferredElements.build();
}
- private void validateMethod(Class<? extends Annotation> annotation, ExecutableElement method) {
- if (!getAnnotatedAnnotations(method, Qualifier.class).isEmpty()) {
+ private void validateMethod(String annotation, ExecutableElement method) {
+ if (!Sets.union(getAnnotatedAnnotations(method, TypeNames.QUALIFIER),
+ getAnnotatedAnnotations(method, TypeNames.QUALIFIER_JAVAX)).isEmpty()) {
return;
}
@@ -94,7 +90,8 @@ final class AndroidMapKeyValidator implements ProcessingStep {
return;
}
- if (!getAnnotatedAnnotations(method, Scope.class).isEmpty()) {
+ if (!Sets.union(getAnnotatedAnnotations(method, TypeNames.SCOPE),
+ getAnnotatedAnnotations(method, TypeNames.SCOPE_JAVAX)).isEmpty()) {
SuppressWarnings suppressedWarnings = method.getAnnotation(SuppressWarnings.class);
if (suppressedWarnings == null
|| !ImmutableSet.copyOf(suppressedWarnings.value())
@@ -107,7 +104,7 @@ final class AndroidMapKeyValidator implements ProcessingStep {
Kind.ERROR,
String.format(
"%s bindings should not be scoped. Scoping this method may leak instances of %s.",
- AndroidInjector.Factory.class.getCanonicalName(),
+ TypeNames.ANDROID_INJECTOR_FACTORY.canonicalName(),
mapKeyValueElement.getQualifiedName()),
method);
}
@@ -117,7 +114,8 @@ final class AndroidMapKeyValidator implements ProcessingStep {
// @Binds methods should only have one parameter, but we can't guarantee the order of Processors
// in javac, so do a basic check for valid form
- if (isAnnotationPresent(method, Binds.class) && method.getParameters().size() == 1) {
+ if (MoreDaggerElements.isAnnotationPresent(method, TypeNames.BINDS)
+ && method.getParameters().size() == 1) {
validateMapKeyMatchesBindsParameter(annotation, method);
}
}
@@ -138,10 +136,10 @@ final class AndroidMapKeyValidator implements ProcessingStep {
}
/**
- * A valid @Binds method could bind an {@link AndroidInjector.Factory} for one type, while giving
+ * A valid @Binds method could bind an {@code AndroidInjector.Factory} for one type, while giving
* it a map key of a different type. The return type and parameter type would pass typical @Binds
- * validation, but the map lookup in {@link dagger.android.DispatchingAndroidInjector} would
- * retrieve the wrong injector factory.
+ * validation, but the map lookup in {@code DispatchingAndroidInjector} would retrieve the wrong
+ * injector factory.
*
* <pre>{@code
* {@literal @Binds}
@@ -151,10 +149,10 @@ final class AndroidMapKeyValidator implements ProcessingStep {
* BlueActivityComponent.Builder builder);
* }</pre>
*/
- private void validateMapKeyMatchesBindsParameter(
- Class<? extends Annotation> annotation, ExecutableElement method) {
+ private void validateMapKeyMatchesBindsParameter(String annotation, ExecutableElement method) {
TypeMirror parameterType = getOnlyElement(method.getParameters()).asType();
- AnnotationMirror annotationMirror = getAnnotationMirror(method, annotation).get();
+ AnnotationMirror annotationMirror =
+ MoreDaggerElements.getAnnotationMirror(method, SUPPORTED_ANNOTATIONS.get(annotation)).get();
TypeMirror mapKeyType =
elements.getTypeElement(injectedTypeFromMapKey(annotationMirror).get()).asType();
if (!types.isAssignable(parameterType, injectorFactoryOf(mapKeyType))) {
@@ -172,6 +170,6 @@ final class AndroidMapKeyValidator implements ProcessingStep {
}
private TypeElement factoryElement() {
- return elements.getTypeElement(AndroidInjector.Factory.class.getCanonicalName());
+ return elements.getTypeElement(TypeNames.ANDROID_INJECTOR_FACTORY.canonicalName());
}
}
diff --git a/java/dagger/android/processor/AndroidMapKeys.java b/java/dagger/android/processor/AndroidMapKeys.java
index fb1fc3853..28da2715a 100644
--- a/java/dagger/android/processor/AndroidMapKeys.java
+++ b/java/dagger/android/processor/AndroidMapKeys.java
@@ -19,7 +19,6 @@ package dagger.android.processor;
import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
import com.google.auto.common.MoreTypes;
-import dagger.android.AndroidInjectionKey;
import java.util.Optional;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.TypeElement;
@@ -27,7 +26,7 @@ import javax.lang.model.type.TypeMirror;
final class AndroidMapKeys {
/**
- * If {@code mapKey} is {@link AndroidInjectionKey}, returns the string value for the map key. If
+ * If {@code mapKey} is {@code AndroidInjectionKey}, returns the string value for the map key. If
* it's {@link dagger.multibindings.ClassKey}, returns the fully-qualified class name of the
* annotation value. Otherwise returns {@link Optional#empty()}.
*/
diff --git a/java/dagger/android/processor/AndroidProcessor.java b/java/dagger/android/processor/AndroidProcessor.java
index ad7f08ef0..357f7dea4 100644
--- a/java/dagger/android/processor/AndroidProcessor.java
+++ b/java/dagger/android/processor/AndroidProcessor.java
@@ -55,7 +55,7 @@ public final class AndroidProcessor extends BasicAnnotationProcessor {
"dagger.android.experimentalUseStringKeys";
@Override
- protected Iterable<? extends ProcessingStep> initSteps() {
+ protected Iterable<? extends Step> steps() {
Filer filer = new FormattingFiler(processingEnv.getFiler());
Messager messager = processingEnv.getMessager();
Elements elements = processingEnv.getElementUtils();
diff --git a/java/dagger/android/processor/BUILD b/java/dagger/android/processor/BUILD
index 7e63c7633..3ab6eee3a 100644
--- a/java/dagger/android/processor/BUILD
+++ b/java/dagger/android/processor/BUILD
@@ -15,7 +15,7 @@
# Description:
# Public Dagger API for Android
-load("@rules_java//java:defs.bzl", "java_import", "java_library", "java_plugin")
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
load(
"//:build_defs.bzl",
"DOCLINT_HTML_AND_SYNTAX",
@@ -38,35 +38,20 @@ java_library(
javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
tags = ["maven_coordinates=com.google.dagger:dagger-android-processor:" + POM_VERSION],
deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/auto:value",
- "@maven//:com_google_auto_auto_common",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/google_java_format",
"//java/dagger:core",
+ "//java/dagger/internal/codegen/langmodel",
"//java/dagger/spi",
- # https://github.com/bazelbuild/bazel/issues/2517
- ":dagger-android-jar",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:service",
+ "//third_party/java/auto:value",
+ "//third_party/java/google_java_format",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/incap",
+ "//third_party/java/javapoet",
],
)
-# https://github.com/bazelbuild/bazel/issues/2517
-# This target serves two (related) purposes:
-# 1. Bazel does not allow a java_library to depend on an android_library, even if that java_library
-# will be used in a java_plugin.
-# 2. It stores the metadata for the "jarimpl" target that we use to work-around Gradle not loading
-# aar artifacts that are declared as deps of an annotation processor. Our pom.xml generator reads
-# the tags and includes them apppropriately.
-java_import(
- name = "dagger-android-jar",
- jars = ["//java/dagger/android:libandroid.jar"],
- tags = ["maven_coordinates=com.google.dagger:dagger-android-jarimpl:" + POM_VERSION],
- visibility = ["//visibility:private"],
-)
-
pom_file(
name = "pom",
artifact_id = "dagger-android-processor",
diff --git a/java/dagger/android/processor/ContributesAndroidInjectorGenerator.java b/java/dagger/android/processor/ContributesAndroidInjectorGenerator.java
index 5c99fd413..f3f4d18ab 100644
--- a/java/dagger/android/processor/ContributesAndroidInjectorGenerator.java
+++ b/java/dagger/android/processor/ContributesAndroidInjectorGenerator.java
@@ -29,10 +29,10 @@ import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
import static javax.lang.model.util.ElementFilter.methodsIn;
-import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
+import com.google.auto.common.BasicAnnotationProcessor.Step;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.SetMultimap;
+import com.google.common.collect.ImmutableSetMultimap;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
@@ -41,26 +41,16 @@ import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.WildcardTypeName;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Subcomponent;
-import dagger.android.AndroidInjectionKey;
-import dagger.android.AndroidInjector;
-import dagger.android.ContributesAndroidInjector;
import dagger.android.processor.AndroidInjectorDescriptor.Validator;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
import java.io.IOException;
-import java.lang.annotation.Annotation;
-import java.util.Set;
import javax.annotation.processing.Filer;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.util.Elements;
-/** Generates the implementation specified in {@link ContributesAndroidInjector}. */
-final class ContributesAndroidInjectorGenerator implements ProcessingStep {
+/** Generates the implementation specified in {@code ContributesAndroidInjector}. */
+final class ContributesAndroidInjectorGenerator implements Step {
private final AndroidInjectorDescriptor.Validator validator;
private final Filer filer;
@@ -82,13 +72,12 @@ final class ContributesAndroidInjectorGenerator implements ProcessingStep {
}
@Override
- public Set<? extends Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(ContributesAndroidInjector.class);
+ public ImmutableSet<String> annotations() {
+ return ImmutableSet.of(TypeNames.CONTRIBUTES_ANDROID_INJECTOR.toString());
}
@Override
- public Set<Element> process(
- SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ public ImmutableSet<Element> process(ImmutableSetMultimap<String, Element> elementsByAnnotation) {
ImmutableSet.Builder<Element> deferredElements = ImmutableSet.builder();
for (ExecutableElement method : methodsIn(elementsByAnnotation.values())) {
try {
@@ -118,7 +107,7 @@ final class ContributesAndroidInjectorGenerator implements ProcessingStep {
classBuilder(moduleName)
.addOriginatingElement(descriptor.method())
.addAnnotation(
- AnnotationSpec.builder(Module.class)
+ AnnotationSpec.builder(TypeNames.MODULE)
.addMember("subcomponents", "$T.class", subcomponentName)
.build())
.addModifiers(PUBLIC, ABSTRACT)
@@ -141,25 +130,24 @@ final class ContributesAndroidInjectorGenerator implements ProcessingStep {
private MethodSpec bindAndroidInjectorFactory(
AndroidInjectorDescriptor descriptor, ClassName subcomponentBuilderName) {
return methodBuilder("bindAndroidInjectorFactory")
- .addAnnotation(Binds.class)
- .addAnnotation(IntoMap.class)
+ .addAnnotation(TypeNames.BINDS)
+ .addAnnotation(TypeNames.INTO_MAP)
.addAnnotation(androidInjectorMapKey(descriptor))
.addModifiers(ABSTRACT)
.returns(
- parameterizedTypeName(
- AndroidInjector.Factory.class,
- WildcardTypeName.subtypeOf(TypeName.OBJECT)))
+ ParameterizedTypeName.get(
+ TypeNames.ANDROID_INJECTOR_FACTORY, WildcardTypeName.subtypeOf(TypeName.OBJECT)))
.addParameter(subcomponentBuilderName, "builder")
.build();
}
private AnnotationSpec androidInjectorMapKey(AndroidInjectorDescriptor descriptor) {
if (useStringKeys) {
- return AnnotationSpec.builder(AndroidInjectionKey.class)
+ return AnnotationSpec.builder(TypeNames.ANDROID_INJECTION_KEY)
.addMember("value", "$S", descriptor.injectedType().toString())
.build();
}
- return AnnotationSpec.builder(ClassKey.class)
+ return AnnotationSpec.builder(TypeNames.CLASS_KEY)
.addMember("value", "$T.class", descriptor.injectedType())
.build();
}
@@ -168,7 +156,7 @@ final class ContributesAndroidInjectorGenerator implements ProcessingStep {
AndroidInjectorDescriptor descriptor,
ClassName subcomponentName,
ClassName subcomponentFactoryName) {
- AnnotationSpec.Builder subcomponentAnnotation = AnnotationSpec.builder(Subcomponent.class);
+ AnnotationSpec.Builder subcomponentAnnotation = AnnotationSpec.builder(TypeNames.SUBCOMPONENT);
for (ClassName module : descriptor.modules()) {
subcomponentAnnotation.addMember("modules", "$T.class", module);
}
@@ -177,7 +165,8 @@ final class ContributesAndroidInjectorGenerator implements ProcessingStep {
.addModifiers(PUBLIC)
.addAnnotation(subcomponentAnnotation.build())
.addAnnotations(descriptor.scopes())
- .addSuperinterface(parameterizedTypeName(AndroidInjector.class, descriptor.injectedType()))
+ .addSuperinterface(
+ ParameterizedTypeName.get(TypeNames.ANDROID_INJECTOR, descriptor.injectedType()))
.addType(subcomponentFactory(descriptor, subcomponentFactoryName))
.build();
}
@@ -185,15 +174,11 @@ final class ContributesAndroidInjectorGenerator implements ProcessingStep {
private TypeSpec subcomponentFactory(
AndroidInjectorDescriptor descriptor, ClassName subcomponentFactoryName) {
return interfaceBuilder(subcomponentFactoryName)
- .addAnnotation(Subcomponent.Factory.class)
+ .addAnnotation(TypeNames.SUBCOMPONENT_FACTORY)
.addModifiers(PUBLIC, STATIC)
.addSuperinterface(
- parameterizedTypeName(AndroidInjector.Factory.class, descriptor.injectedType()))
+ ParameterizedTypeName.get(
+ TypeNames.ANDROID_INJECTOR_FACTORY, descriptor.injectedType()))
.build();
}
-
- private static ParameterizedTypeName parameterizedTypeName(
- Class<?> clazz, TypeName... typeArguments) {
- return ParameterizedTypeName.get(ClassName.get(clazz), typeArguments);
- }
}
diff --git a/java/dagger/android/processor/DuplicateAndroidInjectorsChecker.java b/java/dagger/android/processor/DuplicateAndroidInjectorsChecker.java
index a19c5efaa..bcc8e5a1e 100644
--- a/java/dagger/android/processor/DuplicateAndroidInjectorsChecker.java
+++ b/java/dagger/android/processor/DuplicateAndroidInjectorsChecker.java
@@ -30,8 +30,6 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimaps;
import dagger.MapKey;
-import dagger.android.AndroidInjector;
-import dagger.android.DispatchingAndroidInjector;
import dagger.model.Binding;
import dagger.model.BindingGraph;
import dagger.model.BindingKind;
@@ -43,13 +41,12 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
-import javax.inject.Provider;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
/**
- * Validates that the two maps that {@link DispatchingAndroidInjector} injects have logically
+ * Validates that the two maps that {@code DispatchingAndroidInjector} injects have logically
* different keys. If a contribution exists for the same {@code FooActivity} with
* {@code @ActivityKey(FooActivity.class)} and
* {@code @AndroidInjectionKey("com.example.FooActivity")}, report an error.
@@ -67,7 +64,7 @@ public final class DuplicateAndroidInjectorsChecker implements BindingGraphPlugi
private boolean isDispatchingAndroidInjector(Binding binding) {
Key key = binding.key();
- return MoreTypes.isTypeOf(DispatchingAndroidInjector.class, key.type())
+ return MoreDaggerTypes.isTypeOf(TypeNames.DISPATCHING_ANDROID_INJECTOR, key.type())
&& !key.qualifier().isPresent();
}
@@ -118,12 +115,12 @@ public final class DuplicateAndroidInjectorsChecker implements BindingGraphPlugi
requestedBinding -> {
TypeMirror valueType =
MoreTypes.asDeclared(requestedBinding.key().type()).getTypeArguments().get(1);
- if (!MoreTypes.isTypeOf(Provider.class, valueType)
+ if (!MoreDaggerTypes.isTypeOf(TypeNames.PROVIDER, valueType)
|| !valueType.getKind().equals(TypeKind.DECLARED)) {
return false;
}
TypeMirror providedType = MoreTypes.asDeclared(valueType).getTypeArguments().get(0);
- return MoreTypes.isTypeOf(AndroidInjector.Factory.class, providedType);
+ return MoreDaggerTypes.isTypeOf(TypeNames.ANDROID_INJECTOR_FACTORY, providedType);
});
}
diff --git a/java/dagger/android/processor/MoreDaggerElements.java b/java/dagger/android/processor/MoreDaggerElements.java
new file mode 100644
index 000000000..06dea38ca
--- /dev/null
+++ b/java/dagger/android/processor/MoreDaggerElements.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.android.processor;
+
+import com.google.auto.common.MoreElements;
+import com.squareup.javapoet.ClassName;
+import java.util.Optional;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+// TODO(bcorso): Dedupe with dagger/internal/codegen/langmodel/DaggerElements.java?
+// TODO(bcorso): Contribute upstream to auto common?
+/** Similar to auto common, but uses {@link ClassName} rather than {@link Class}. */
+final class MoreDaggerElements {
+ /**
+ * Returns {@code true} iff the given element has an {@link AnnotationMirror} whose {@linkplain
+ * AnnotationMirror#getAnnotationType() annotation type} has the same canonical name as that of
+ * {@code annotationClass}. This method is a safer alternative to calling {@link
+ * Element#getAnnotation} and checking for {@code null} as it avoids any interaction with
+ * annotation proxies.
+ */
+ public static boolean isAnnotationPresent(Element element, ClassName annotationName) {
+ return getAnnotationMirror(element, annotationName).isPresent();
+ }
+
+ /**
+ * Returns an {@link AnnotationMirror} for the annotation of type {@code annotationClass} on
+ * {@code element}, or {@link Optional#empty()} if no such annotation exists. This method is a
+ * safer alternative to calling {@link Element#getAnnotation} as it avoids any interaction with
+ * annotation proxies.
+ */
+ public static Optional<AnnotationMirror> getAnnotationMirror(
+ Element element, ClassName annotationName) {
+ String annotationClassName = annotationName.canonicalName();
+ for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
+ TypeElement annotationTypeElement =
+ MoreElements.asType(annotationMirror.getAnnotationType().asElement());
+ if (annotationTypeElement.getQualifiedName().contentEquals(annotationClassName)) {
+ return Optional.of(annotationMirror);
+ }
+ }
+ return Optional.empty();
+ }
+
+ private MoreDaggerElements() {}
+}
diff --git a/java/dagger/android/processor/MoreDaggerTypes.java b/java/dagger/android/processor/MoreDaggerTypes.java
new file mode 100644
index 000000000..4bde405e1
--- /dev/null
+++ b/java/dagger/android/processor/MoreDaggerTypes.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.android.processor;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.auto.common.MoreElements;
+import com.squareup.javapoet.ArrayTypeName;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.TypeName;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ErrorType;
+import javax.lang.model.type.NoType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleTypeVisitor8;
+
+// TODO(bcorso): Dedupe with dagger/internal/codegen/langmodel/DaggerTypes.java?
+// TODO(bcorso): Contribute upstream to auto common?
+/** Similar to auto common, but uses {@link ClassName} rather than {@link Class}. */
+final class MoreDaggerTypes {
+
+ /**
+ * Returns true if the raw type underlying the given {@link TypeMirror} represents the same raw
+ * type as the given {@link Class} and throws an IllegalArgumentException if the {@link
+ * TypeMirror} does not represent a type that can be referenced by a {@link Class}
+ */
+ public static boolean isTypeOf(final TypeName typeName, TypeMirror type) {
+ checkNotNull(typeName);
+ return type.accept(new IsTypeOf(typeName), null);
+ }
+
+ private static final class IsTypeOf extends SimpleTypeVisitor8<Boolean, Void> {
+ private final TypeName typeName;
+
+ IsTypeOf(TypeName typeName) {
+ this.typeName = typeName;
+ }
+
+ @Override
+ protected Boolean defaultAction(TypeMirror type, Void ignored) {
+ throw new IllegalArgumentException(type + " cannot be represented as a Class<?>.");
+ }
+
+ @Override
+ public Boolean visitNoType(NoType noType, Void p) {
+ if (noType.getKind().equals(TypeKind.VOID)) {
+ return typeName.equals(TypeName.VOID);
+ }
+ throw new IllegalArgumentException(noType + " cannot be represented as a Class<?>.");
+ }
+
+ @Override
+ public Boolean visitError(ErrorType errorType, Void p) {
+ return false;
+ }
+
+ @Override
+ public Boolean visitPrimitive(PrimitiveType type, Void p) {
+ switch (type.getKind()) {
+ case BOOLEAN:
+ return typeName.equals(TypeName.BOOLEAN);
+ case BYTE:
+ return typeName.equals(TypeName.BYTE);
+ case CHAR:
+ return typeName.equals(TypeName.CHAR);
+ case DOUBLE:
+ return typeName.equals(TypeName.DOUBLE);
+ case FLOAT:
+ return typeName.equals(TypeName.FLOAT);
+ case INT:
+ return typeName.equals(TypeName.INT);
+ case LONG:
+ return typeName.equals(TypeName.LONG);
+ case SHORT:
+ return typeName.equals(TypeName.SHORT);
+ default:
+ throw new IllegalArgumentException(type + " cannot be represented as a Class<?>.");
+ }
+ }
+
+ @Override
+ public Boolean visitArray(ArrayType array, Void p) {
+ return (typeName instanceof ArrayTypeName)
+ && isTypeOf(((ArrayTypeName) typeName).componentType, array.getComponentType());
+ }
+
+ @Override
+ public Boolean visitDeclared(DeclaredType type, Void ignored) {
+ TypeElement typeElement = MoreElements.asType(type.asElement());
+ return (typeName instanceof ClassName)
+ && typeElement.getQualifiedName().contentEquals(((ClassName) typeName).canonicalName());
+ }
+ }
+
+ private MoreDaggerTypes() {}
+}
diff --git a/java/dagger/android/processor/TypeNames.java b/java/dagger/android/processor/TypeNames.java
new file mode 100644
index 000000000..7325690ca
--- /dev/null
+++ b/java/dagger/android/processor/TypeNames.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.android.processor;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.TypeName;
+
+// TODO(bcorso): Dedupe with dagger/internal/codegen/javapoet/TypeNames.java?
+/** Common names and methods for JavaPoet {@link TypeName} and {@link ClassName} usage. */
+public final class TypeNames {
+
+ // Core Dagger classnames
+ public static final ClassName BINDS = ClassName.get("dagger", "Binds");
+ public static final ClassName CLASS_KEY = ClassName.get("dagger.multibindings", "ClassKey");
+ public static final ClassName INTO_MAP = ClassName.get("dagger.multibindings", "IntoMap");
+ public static final ClassName MAP_KEY = ClassName.get("dagger", "MapKey");
+ public static final ClassName MODULE = ClassName.get("dagger", "Module");
+ public static final ClassName SUBCOMPONENT = ClassName.get("dagger", "Subcomponent");
+ public static final ClassName SUBCOMPONENT_FACTORY = SUBCOMPONENT.nestedClass("Factory");
+
+ // Dagger.android classnames
+ public static final ClassName ANDROID_INJECTION_KEY =
+ ClassName.get("dagger.android", "AndroidInjectionKey");
+ public static final ClassName ANDROID_INJECTOR =
+ ClassName.get("dagger.android", "AndroidInjector");
+ public static final ClassName DISPATCHING_ANDROID_INJECTOR =
+ ClassName.get("dagger.android", "DispatchingAndroidInjector");
+ public static final ClassName ANDROID_INJECTOR_FACTORY = ANDROID_INJECTOR.nestedClass("Factory");
+ public static final ClassName CONTRIBUTES_ANDROID_INJECTOR =
+ ClassName.get("dagger.android", "ContributesAndroidInjector");
+
+ // Other classnames
+ public static final ClassName PROVIDER = ClassName.get("javax.inject", "Provider");
+ public static final ClassName QUALIFIER = ClassName.get("jakarta.inject", "Qualifier");
+ public static final ClassName QUALIFIER_JAVAX = ClassName.get("javax.inject", "Qualifier");
+ public static final ClassName SCOPE = ClassName.get("jakarta.inject", "Scope");
+ public static final ClassName SCOPE_JAVAX = ClassName.get("javax.inject", "Scope");
+
+ private TypeNames() {}
+}
diff --git a/java/dagger/android/support/BUILD b/java/dagger/android/support/BUILD
index 8afa703d4..80747a4b1 100644
--- a/java/dagger/android/support/BUILD
+++ b/java/dagger/android/support/BUILD
@@ -40,7 +40,7 @@ android_library(
deps = [
"//:dagger_with_compiler",
"//java/dagger/android",
- "@google_bazel_common//third_party/java/error_prone:annotations",
+ "//third_party/java/error_prone:annotations",
"@maven//:androidx_activity_activity",
"@maven//:androidx_annotation_annotation",
"@maven//:androidx_appcompat_appcompat",
@@ -71,7 +71,7 @@ android_library(
exports = [
"//:dagger_with_compiler",
"//java/dagger/android:legacy-deps",
- "@google_bazel_common//third_party/java/error_prone:annotations",
+ "//third_party/java/error_prone:annotations",
"@maven//:com_android_support_appcompat_v7",
"@maven//:com_android_support_support_annotations",
"@maven//:com_android_support_support_fragment",
diff --git a/java/dagger/errorprone/BUILD b/java/dagger/errorprone/BUILD
index 9c3707f09..0bb288a65 100644
--- a/java/dagger/errorprone/BUILD
+++ b/java/dagger/errorprone/BUILD
@@ -10,8 +10,8 @@ java_library(
srcs = glob(["*.java"]),
deps = [
"//java/dagger:core",
- "//java/dagger/internal/guava:collect",
+ "//third_party/java/error_prone:check_api",
+ "//third_party/java/guava/collect",
"@bazel_tools//tools/jdk:langtools-neverlink",
- "@google_bazel_common//third_party/java/error_prone:check_api",
],
)
diff --git a/java/dagger/example/gradle/android/simple/app/build.gradle b/java/dagger/example/gradle/android/simple/app/build.gradle
deleted file mode 100644
index d8f6346cb..000000000
--- a/java/dagger/example/gradle/android/simple/app/build.gradle
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-apply plugin: 'com.android.application'
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- applicationId "dagger.example.gradle.android.simple"
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- }
-}
-
-dependencies {
- implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation 'com.google.dagger:dagger:LOCAL-SNAPSHOT'
- implementation 'com.google.dagger:dagger-android-support:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:dagger-compiler:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:dagger-android-processor:LOCAL-SNAPSHOT'
-
- // To help us catch usages of Guava APIs for Java 8 in the '-jre' variant.
- annotationProcessor'com.google.guava:guava:28.1-android'
-}
diff --git a/java/dagger/example/gradle/android/simple/app/src/main/AndroidManifest.xml b/java/dagger/example/gradle/android/simple/app/src/main/AndroidManifest.xml
deleted file mode 100644
index cc666d2f2..000000000
--- a/java/dagger/example/gradle/android/simple/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
- ~ Copyright (C) 2017 The Dagger Authors.
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.example.gradle.android.simple">
-
- <application
- android:name=".SimpleApplication"
- android:label="@string/appName"
- android:theme="@style/Theme.AppCompat.Light">
- <activity android:name=".SimpleActivity" android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/SimpleActivity.java b/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/SimpleActivity.java
deleted file mode 100644
index 734590afd..000000000
--- a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/SimpleActivity.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2019 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.example.gradle.android.simple;
-
-import android.os.Bundle;
-import android.util.Log;
-import android.widget.TextView;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Subcomponent;
-import dagger.android.AndroidInjector;
-import dagger.android.support.DaggerAppCompatActivity;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
-import javax.inject.Inject;
-
-/**
- * The main activity of the application.
- *
- * <p>It can be injected with any binding from both {@link SimpleActivityComponent} and {@link
- * SimpleApplication.SimpleComponent}.
- */
-public class SimpleActivity extends DaggerAppCompatActivity {
- @Subcomponent
- interface SimpleActivityComponent extends AndroidInjector<SimpleActivity> {
-
- @Subcomponent.Factory
- interface Factory extends AndroidInjector.Factory<SimpleActivity> {}
- }
-
- @Module(subcomponents = SimpleActivityComponent.class)
- abstract static class InjectorModule {
-
- @Binds
- @IntoMap
- @ClassKey(SimpleActivity.class)
- abstract AndroidInjector.Factory<?> bind(SimpleActivityComponent.Factory factory);
- }
-
- private static final String TAG = SimpleActivity.class.getSimpleName();
-
- @Inject @Model String model;
-
- @Inject
- void logInjection() {
- Log.i(TAG, "Injecting");
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_main);
-
- TextView greeting = (TextView) findViewById(R.id.greeting);
- String text = getResources().getString(R.string.welcome, model);
- greeting.setText(text);
- }
-}
diff --git a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/SimpleApplication.java b/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/SimpleApplication.java
deleted file mode 100644
index e2e34ea50..000000000
--- a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/SimpleApplication.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2019 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.example.gradle.android.simple;
-
-import android.util.Log;
-import dagger.Component;
-import dagger.android.AndroidInjectionModule;
-import dagger.android.AndroidInjector;
-import dagger.android.DaggerApplication;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * A simple, skeletal application that demonstrates a dependency-injected application using the
- * utilities in {@code dagger.android}.
- */
-public class SimpleApplication extends DaggerApplication {
- private static final String TAG = SimpleApplication.class.getSimpleName();
-
- @Singleton
- @Component(
- modules = {
- AndroidInjectionModule.class,
- SimpleActivity.InjectorModule.class,
- BuildModule.class
- }
- )
- interface SimpleComponent extends AndroidInjector<SimpleApplication> {
- @Component.Factory
- interface Factory extends AndroidInjector.Factory<SimpleApplication> {}
- }
-
- @Inject
- void logInjection() {
- Log.i(TAG, "Injecting " + SimpleApplication.class.getSimpleName());
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- }
-
- @Override
- protected AndroidInjector<SimpleApplication> applicationInjector() {
- return DaggerSimpleApplication_SimpleComponent.factory().create(this);
- }
-}
diff --git a/java/dagger/example/gradle/android/simple/app/src/main/res/layout/activity_main.xml b/java/dagger/example/gradle/android/simple/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 18a547bbd..000000000
--- a/java/dagger/example/gradle/android/simple/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2017 The Dagger Authors.
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/background_light">
-
- <TextView
- android:id="@+id/greeting"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_alignParentTop="true"
- android:textColor="@android:color/primary_text_light"
- />
-</RelativeLayout>
diff --git a/java/dagger/example/gradle/android/simple/app/src/main/res/values/strings.xml b/java/dagger/example/gradle/android/simple/app/src/main/res/values/strings.xml
deleted file mode 100644
index f45fd411c..000000000
--- a/java/dagger/example/gradle/android/simple/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <string name="appName">Simple Dagger Android</string>
- <string name="welcome">Hello, %s!</string>
-</resources>
diff --git a/java/dagger/example/gradle/android/simple/gradle.properties b/java/dagger/example/gradle/android/simple/gradle.properties
deleted file mode 100644
index 2d8d1e4dd..000000000
--- a/java/dagger/example/gradle/android/simple/gradle.properties
+++ /dev/null
@@ -1 +0,0 @@
-android.useAndroidX=true \ No newline at end of file
diff --git a/java/dagger/example/gradle/android/simple/settings.gradle b/java/dagger/example/gradle/android/simple/settings.gradle
deleted file mode 100644
index c5a07bc20..000000000
--- a/java/dagger/example/gradle/android/simple/settings.gradle
+++ /dev/null
@@ -1,2 +0,0 @@
-include ':app'
-rootProject.name='Simple Dagger Android' \ No newline at end of file
diff --git a/java/dagger/example/spi/BUILD b/java/dagger/example/spi/BUILD
index bd889c350..2cbb84ab9 100644
--- a/java/dagger/example/spi/BUILD
+++ b/java/dagger/example/spi/BUILD
@@ -23,12 +23,12 @@ java_plugin(
name = "binding-graph-visualizer",
srcs = glob(["*.java"]),
deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:graph",
"//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@google_bazel_common//third_party/java/javapoet",
+ "//third_party/java/auto:service",
+ "//third_party/java/error_prone:annotations",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/graph",
+ "//third_party/java/javapoet",
],
)
diff --git a/java/dagger/grpc/server/BUILD b/java/dagger/grpc/server/BUILD
index d9a2f9789..8aa82bee8 100644
--- a/java/dagger/grpc/server/BUILD
+++ b/java/dagger/grpc/server/BUILD
@@ -24,7 +24,7 @@ java_library(
javacopts = DOCLINT_HTML_AND_SYNTAX,
tags = ["maven_coordinates=com.google.dagger:dagger-grpc-server-annotations:" + POM_VERSION],
deps = [
- "@google_bazel_common//third_party/java/jsr330_inject",
+ "//third_party/java/jsr330_inject",
],
)
@@ -41,15 +41,15 @@ java_library(
exports = [":annotations"],
deps = [
"//:dagger_with_compiler",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/grpc:context",
- "@google_bazel_common//third_party/java/grpc:core",
- "@google_bazel_common//third_party/java/grpc:netty",
- "@google_bazel_common//third_party/java/grpc:protobuf",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/protobuf",
+ "//third_party/java/auto:value",
+ "//third_party/java/grpc:context",
+ "//third_party/java/grpc:core",
+ "//third_party/java/grpc:netty",
+ "//third_party/java/grpc:protobuf",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/protobuf",
],
)
diff --git a/java/dagger/grpc/server/processor/BUILD b/java/dagger/grpc/server/processor/BUILD
index dd3365166..ed288363d 100644
--- a/java/dagger/grpc/server/processor/BUILD
+++ b/java/dagger/grpc/server/processor/BUILD
@@ -17,14 +17,14 @@ java_library(
deps = [
"//:dagger_with_compiler",
"//java/dagger/grpc/server:annotations",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:io",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/google_java_format",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr250_annotations",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:service",
+ "//third_party/java/google_java_format",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/io",
+ "//third_party/java/javapoet",
+ "//third_party/java/jsr250_annotations",
],
)
diff --git a/java/dagger/hilt/BUILD b/java/dagger/hilt/BUILD
index 3d12c91e7..13990a2bb 100644
--- a/java/dagger/hilt/BUILD
+++ b/java/dagger/hilt/BUILD
@@ -54,7 +54,7 @@ java_library(
"//java/dagger/hilt/internal:generated_component",
"//java/dagger/hilt/internal:preconditions",
"//java/dagger/hilt/internal:test_singleton_component",
- "@google_bazel_common//third_party/java/jsr305_annotations",
+ "//third_party/java/jsr305_annotations",
],
)
@@ -96,7 +96,7 @@ java_library(
name = "package_info",
srcs = ["package-info.java"],
deps = [
- "@google_bazel_common//third_party/java/jsr305_annotations",
+ "//third_party/java/jsr305_annotations",
],
)
@@ -135,6 +135,7 @@ filegroup(
srcs = [
"//java/dagger/hilt/android:srcs_filegroup",
"//java/dagger/hilt/android/components:srcs_filegroup",
+ "//java/dagger/hilt/android/flags:srcs_filegroup",
"//java/dagger/hilt/android/internal:srcs_filegroup",
"//java/dagger/hilt/android/internal/builders:srcs_filegroup",
"//java/dagger/hilt/android/internal/lifecycle:srcs_filegroup",
@@ -175,6 +176,7 @@ filegroup(
"//java/dagger/hilt/processor/internal/generatesrootinput:srcs_filegroup",
"//java/dagger/hilt/processor/internal/originatingelement:srcs_filegroup",
"//java/dagger/hilt/processor/internal/root:srcs_filegroup",
+ "//java/dagger/hilt/processor/internal/root/ir:srcs_filegroup",
"//java/dagger/hilt/processor/internal/uninstallmodules:srcs_filegroup",
],
)
diff --git a/java/dagger/hilt/android/BUILD b/java/dagger/hilt/android/BUILD
index d8833e77c..1cce5ea8c 100644
--- a/java/dagger/hilt/android/BUILD
+++ b/java/dagger/hilt/android/BUILD
@@ -16,6 +16,7 @@
# A library based on Hilt that provides standard components and automated injection for Android.
load("//:build_defs.bzl", "POM_VERSION")
load("//tools:maven.bzl", "gen_maven_artifact")
+load("//tools:bazel_compat.bzl", "compat_kt_android_library")
package(default_visibility = ["//:src"])
@@ -31,6 +32,8 @@ android_library(
exports = [
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android/components",
+ "//java/dagger/hilt/android/flags:fragment_get_context_fix",
+ "//java/dagger/hilt/android/internal",
"//java/dagger/hilt/android/internal/builders",
"//java/dagger/hilt/android/internal/managers",
"//java/dagger/hilt/android/internal/managers:component_supplier",
@@ -60,7 +63,8 @@ android_library(
exported_plugins = [
"//java/dagger/hilt/android/processor/internal/androidentrypoint:plugin",
"//java/dagger/hilt/android/processor/internal/viewmodel:validation_plugin",
- "//java/dagger/hilt/processor/internal/root:plugin",
+ "//java/dagger/hilt/processor/internal/root:component_tree_deps_plugin",
+ "//java/dagger/hilt/processor/internal/root:root_plugin",
],
exports = [
":activity_retained_lifecycle",
@@ -68,6 +72,7 @@ android_library(
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android/components",
"//java/dagger/hilt/android/internal/builders",
+ "//java/dagger/hilt/android/internal/legacy:aggregated_element_proxy",
"//java/dagger/hilt/android/internal/managers",
"//java/dagger/hilt/android/internal/managers:component_supplier",
"//java/dagger/hilt/android/internal/modules",
@@ -77,6 +82,7 @@ android_library(
"//java/dagger/hilt/internal:generated_component",
"//java/dagger/hilt/internal:generated_entry_point",
"//java/dagger/hilt/internal/aggregatedroot",
+ "//java/dagger/hilt/internal/componenttreedeps",
"//java/dagger/hilt/internal/processedrootsentinel",
"//java/dagger/hilt/migration:disable_install_in_check",
"@maven//:androidx_activity_activity",
@@ -93,21 +99,6 @@ android_library(
)
android_library(
- name = "entry_point_accessors",
- srcs = ["EntryPointAccessors.java"],
- deps = [
- ":package_info",
- "//java/dagger/hilt:entry_point",
- "@google_bazel_common//third_party/java/jsr305_annotations",
- "@maven//:androidx_activity_activity",
- "@maven//:androidx_fragment_fragment",
- "@maven//:androidx_lifecycle_lifecycle_common",
- "@maven//:androidx_lifecycle_lifecycle_viewmodel",
- "@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
- ],
-)
-
-android_library(
name = "activity_retained_lifecycle",
srcs = ["ActivityRetainedLifecycle.java"],
deps = [
@@ -134,10 +125,11 @@ android_library(
":package_info",
"//:dagger_with_compiler",
"//java/dagger/hilt:entry_point",
+ "//java/dagger/hilt/android/internal",
"//java/dagger/hilt/internal:component_manager",
"//java/dagger/hilt/internal:preconditions",
"//java/dagger/hilt/internal:test_singleton_component_manager",
- "@google_bazel_common//third_party/java/jsr305_annotations",
+ "//third_party/java/jsr305_annotations",
],
)
@@ -145,7 +137,7 @@ java_library(
name = "package_info",
srcs = ["package-info.java"],
deps = [
- "@google_bazel_common//third_party/java/jsr305_annotations",
+ "//third_party/java/jsr305_annotations",
],
)
@@ -159,6 +151,7 @@ android_library(
":hilt_android_app",
":package_info",
"//java/dagger/hilt:artifact-core-lib",
+ "//java/dagger/hilt/android/migration:custom_inject",
"//java/dagger/hilt/android/migration:optional_inject",
"//java/dagger/lint:lint-android-artifact-lib",
],
@@ -178,15 +171,19 @@ gen_maven_artifact(
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/components",
"//java/dagger/hilt/android/components:package_info",
+ "//java/dagger/hilt/android/flags:fragment_get_context_fix",
"//java/dagger/hilt/android/internal",
"//java/dagger/hilt/android/internal/builders",
"//java/dagger/hilt/android/internal/earlyentrypoint",
+ "//java/dagger/hilt/android/internal/legacy:aggregated_element_proxy",
"//java/dagger/hilt/android/internal/lifecycle",
"//java/dagger/hilt/android/internal/managers",
"//java/dagger/hilt/android/internal/managers:component_supplier",
+ "//java/dagger/hilt/android/internal/migration:has_custom_inject",
"//java/dagger/hilt/android/internal/migration:injected_by_hilt",
"//java/dagger/hilt/android/internal/modules",
"//java/dagger/hilt/android/lifecycle",
+ "//java/dagger/hilt/android/migration:custom_inject",
"//java/dagger/hilt/android/migration:optional_inject",
"//java/dagger/hilt/android/migration:package_info",
"//java/dagger/hilt/android/qualifiers",
@@ -198,6 +195,7 @@ gen_maven_artifact(
"//java/dagger/hilt/internal:test_singleton_component_manager",
"//java/dagger/hilt/internal/aggregatedroot:aggregatedroot",
"//java/dagger/hilt/internal/processedrootsentinel:processedrootsentinel",
+ "//java/dagger/hilt/internal/componenttreedeps:componenttreedeps",
],
artifact_target_maven_deps = [
"androidx.activity:activity",
@@ -212,6 +210,7 @@ gen_maven_artifact(
"com.google.dagger:dagger",
"com.google.dagger:hilt-core",
"javax.inject:javax.inject",
+ "org.jetbrains.kotlin:kotlin-stdlib",
],
artifact_target_maven_deps_banned = [
"com.google.guava:guava",
@@ -237,6 +236,20 @@ gen_maven_artifact(
],
)
+compat_kt_android_library(
+ name = "entry_point_accessors",
+ srcs = ["EntryPointAccessors.kt"],
+ deps = [
+ "//java/dagger/hilt:entry_point",
+ "//java/dagger/hilt/android/internal",
+ "@maven//:androidx_activity_activity",
+ "@maven//:androidx_fragment_fragment",
+ "@maven//:androidx_lifecycle_lifecycle_common",
+ "@maven//:androidx_lifecycle_lifecycle_viewmodel",
+ "@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
+ ],
+)
+
filegroup(
name = "srcs_filegroup",
srcs = glob(["*"]),
diff --git a/java/dagger/hilt/android/EarlyEntryPoints.java b/java/dagger/hilt/android/EarlyEntryPoints.java
index e71401995..d6ebdd655 100644
--- a/java/dagger/hilt/android/EarlyEntryPoints.java
+++ b/java/dagger/hilt/android/EarlyEntryPoints.java
@@ -16,8 +16,10 @@
package dagger.hilt.android;
+import android.app.Application;
import android.content.Context;
import dagger.hilt.EntryPoints;
+import dagger.hilt.android.internal.Contexts;
import dagger.hilt.internal.GeneratedComponentManagerHolder;
import dagger.hilt.internal.Preconditions;
import dagger.hilt.internal.TestSingletonComponentManager;
@@ -43,13 +45,13 @@ public final class EarlyEntryPoints {
// this method easier to use, since most code will use this with an Application or Context type.
@Nonnull
public static <T> T get(Context applicationContext, Class<T> entryPoint) {
- applicationContext = applicationContext.getApplicationContext();
+ Application application = Contexts.getApplication(applicationContext.getApplicationContext());
Preconditions.checkState(
- applicationContext instanceof GeneratedComponentManagerHolder,
+ application instanceof GeneratedComponentManagerHolder,
"Expected application context to implement GeneratedComponentManagerHolder. "
+ "Check that you're passing in an application context that uses Hilt.");
Object componentManager =
- ((GeneratedComponentManagerHolder) applicationContext).componentManager();
+ ((GeneratedComponentManagerHolder) application).componentManager();
if (componentManager instanceof TestSingletonComponentManager) {
Preconditions.checkState(
hasAnnotationReflection(entryPoint, EarlyEntryPoint.class),
@@ -62,7 +64,7 @@ public final class EarlyEntryPoints {
// @EarlyEntryPoint only has an effect in test environment, so if this is not a test we
// delegate to EntryPoints.
- return EntryPoints.get(applicationContext, entryPoint);
+ return EntryPoints.get(application, entryPoint);
}
// Note: This method uses reflection but it should only be called in test environments.
diff --git a/java/dagger/hilt/android/EntryPointAccessors.java b/java/dagger/hilt/android/EntryPointAccessors.java
deleted file mode 100644
index 6145af1bc..000000000
--- a/java/dagger/hilt/android/EntryPointAccessors.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android;
-
-import android.app.Activity;
-import android.content.Context;
-import androidx.fragment.app.Fragment;
-import android.view.View;
-import dagger.hilt.EntryPoints;
-import javax.annotation.Nonnull;
-
-/** Static utility methods for dealing with entry points for standard Android components. */
-public final class EntryPointAccessors {
-
- /**
- * Returns the entry point interface from an application. The context can be any context derived
- * from the application context. May only be used with entry point interfaces installed in the
- * ApplicationComponent.
- */
- @Nonnull
- public static <T> T fromApplication(Context context, Class<T> entryPoint) {
- return EntryPoints.get(context.getApplicationContext(), entryPoint);
- }
-
- /**
- * Returns the entry point interface from an activity. May only be used with entry point
- * interfaces installed in the ActivityComponent.
- */
- @Nonnull
- public static <T> T fromActivity(Activity activity, Class<T> entryPoint) {
- return EntryPoints.get(activity, entryPoint);
- }
-
- /**
- * Returns the entry point interface from a fragment. May only be used with entry point interfaces
- * installed in the FragmentComponent.
- */
- @Nonnull
- public static <T> T fromFragment(Fragment fragment, Class<T> entryPoint) {
- return EntryPoints.get(fragment, entryPoint);
- }
-
- /**
- * Returns the entry point interface from a view. May only be used with entry point interfaces
- * installed in the ViewComponent or ViewNoFragmentComponent.
- */
- @Nonnull
- public static <T> T fromView(View view, Class<T> entryPoint) {
- return EntryPoints.get(view, entryPoint);
- }
-
- private EntryPointAccessors() {}
-}
diff --git a/java/dagger/hilt/android/EntryPointAccessors.kt b/java/dagger/hilt/android/EntryPointAccessors.kt
new file mode 100644
index 000000000..8970c1e57
--- /dev/null
+++ b/java/dagger/hilt/android/EntryPointAccessors.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android
+
+import android.app.Activity
+import android.content.Context
+import androidx.fragment.app.Fragment
+import android.view.View
+import dagger.hilt.EntryPoints
+import dagger.hilt.android.internal.Contexts
+
+/** Utility functions for dealing with entry points for standard Android components. */
+object EntryPointAccessors {
+ /**
+ * Returns the entry point interface from an application. The context can be any context derived
+ * from the application context. May only be used with entry point interfaces installed in the
+ * SingletonComponent.
+ */
+ @JvmStatic
+ fun <T> fromApplication(context: Context, entryPoint: Class<T>): T =
+ EntryPoints.get(Contexts.getApplication(context.applicationContext), entryPoint)
+
+ /**
+ * Returns the entry point interface from an application. The context can be any context derived
+ * from the application context. May only be used with entry point interfaces installed in the
+ * SingletonComponent.
+ */
+ inline fun <reified T> fromApplication(context: Context): T =
+ fromApplication(context, T::class.java)
+
+ /**
+ * Returns the entry point interface from an activity. May only be used with entry point
+ * interfaces installed in the ActivityComponent.
+ */
+ @JvmStatic
+ fun <T> fromActivity(activity: Activity, entryPoint: Class<T>): T =
+ EntryPoints.get(activity, entryPoint)
+
+ /**
+ * Returns the entry point interface from an activity. May only be used with entry point
+ * interfaces installed in the ActivityComponent.
+ */
+ inline fun <reified T> fromActivity(activity: Activity): T =
+ fromActivity(activity, T::class.java)
+
+ /**
+ * Returns the entry point interface from a fragment. May only be used with entry point interfaces
+ * installed in the FragmentComponent.
+ */
+ @JvmStatic
+ fun <T> fromFragment(fragment: Fragment, entryPoint: Class<T>): T =
+ EntryPoints.get(fragment, entryPoint)
+
+ /**
+ * Returns the entry point interface from a fragment. May only be used with entry point interfaces
+ * installed in the FragmentComponent.
+ */
+ inline fun <reified T> fromFragment(fragment: Fragment): T =
+ fromFragment(fragment, T::class.java)
+
+ /**
+ * Returns the entry point interface from a view. May only be used with entry point interfaces
+ * installed in the ViewComponent or ViewNoFragmentComponent.
+ */
+ @JvmStatic
+ fun <T> fromView(view: View, entryPoint: Class<T>): T = EntryPoints.get(view, entryPoint)
+
+ /**
+ * Returns the entry point interface from a view. May only be used with entry point interfaces
+ * installed in the ViewComponent or ViewNoFragmentComponent.
+ */
+ inline fun <reified T> fromView(view: View): T =
+ fromView(view, T::class.java)
+}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/build.gradle b/java/dagger/hilt/android/example/gradle/simple/app/build.gradle
deleted file mode 100644
index b3687ee63..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/build.gradle
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2019 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-apply plugin: 'com.android.application'
-apply plugin: 'dagger.hilt.android.plugin'
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- applicationId "dagger.hilt.android.example.gradle.simple"
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "dagger.hilt.android.example.gradle.simple.SimpleEmulatorTestRunner"
- }
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
- testOptions {
- unitTests.includeAndroidResources = true
- }
- sourceSets {
- String sharedTestDir = 'src/sharedTest/java'
- test {
- java.srcDirs += sharedTestDir
- }
- androidTest {
- java.srcDirs += sharedTestDir
- }
- }
-}
-
-dependencies {
- implementation project(':feature')
- implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:hilt-android-compiler:LOCAL-SNAPSHOT'
-
- testImplementation 'com.google.truth:truth:1.0.1'
- testImplementation 'junit:junit:4.13'
- testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
- testImplementation 'androidx.core:core:1.3.2'
- testImplementation 'androidx.test.ext:junit:1.1.2'
- testImplementation 'androidx.test:runner:1.3.0'
- testImplementation 'com.google.dagger:hilt-android-testing:LOCAL-SNAPSHOT'
- testAnnotationProcessor 'com.google.dagger:hilt-android-compiler:LOCAL-SNAPSHOT'
-
- androidTestImplementation 'com.google.truth:truth:1.0.1'
- androidTestImplementation 'junit:junit:4.13'
- androidTestImplementation 'androidx.test.ext:junit:1.1.2'
- androidTestImplementation 'androidx.test:runner:1.3.0'
- androidTestImplementation 'com.google.dagger:hilt-android-testing:LOCAL-SNAPSHOT'
- androidTestAnnotationProcessor 'com.google.dagger:hilt-android-compiler:LOCAL-SNAPSHOT'
-
- // To help us catch usages of Guava APIs for Java 8 in the '-jre' variant.
- annotationProcessor'com.google.guava:guava:28.1-android'
- testAnnotationProcessor'com.google.guava:guava:28.1-android'
- androidTestAnnotationProcessor'com.google.guava:guava:28.1-android'
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SettingsActivityEmulatorTest.java b/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SettingsActivityEmulatorTest.java
deleted file mode 100644
index 28a722302..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SettingsActivityEmulatorTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.android.testing.UninstallModules;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** A simple test using Hilt. */
-@UninstallModules(ModelModule.class)
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class SettingsActivityEmulatorTest {
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @BindValue @Model String fakeModel = "FakeModel";
-
- @Inject @Model String injectedModel;
-
- @Test
- public void testInjectedModel() throws Exception {
- assertThat(injectedModel).isNull();
- rule.inject();
- assertThat(injectedModel).isEqualTo("FakeModel");
- }
-
- @Test
- public void testActivityInject() throws Exception {
- try (ActivityScenario<SettingsActivity> scenario =
- ActivityScenario.launch(SettingsActivity.class)) {
- scenario.onActivity(
- activity ->
- assertThat(activity.greeter.greet())
- .isEqualTo("ProdUser, you are on build FakeModel."));
- }
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SimpleActivityEmulatorTest.java b/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SimpleActivityEmulatorTest.java
deleted file mode 100644
index cbf8f7f72..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SimpleActivityEmulatorTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.android.testing.UninstallModules;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** A simple test using Hilt. */
-@UninstallModules(UserNameModule.class)
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class SimpleActivityEmulatorTest {
-
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @BindValue @UserName String fakeUserName = "FakeUser";
-
- @Inject @UserName String injectedUserName;
-
- @Test
- public void testInjectedUserName() throws Exception {
- assertThat(injectedUserName).isNull();
- rule.inject();
- assertThat(injectedUserName).isEqualTo("FakeUser");
- }
-
- @Test
- public void testActivityInject() throws Exception {
- try (ActivityScenario<SimpleActivity> scenario =
- ActivityScenario.launch(SimpleActivity.class)) {
- scenario.onActivity(
- activity -> assertThat(activity.greeter.greet()).isEqualTo("Hello, FakeUser!"));
- }
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SimpleEmulatorTestRunner.java b/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SimpleEmulatorTestRunner.java
deleted file mode 100644
index daf046b2e..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SimpleEmulatorTestRunner.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import android.app.Application;
-import android.content.Context;
-import androidx.test.runner.AndroidJUnitRunner;
-import dagger.hilt.android.testing.HiltTestApplication;
-
-/** A custom runner to setup the emulator application class for tests. */
-public final class SimpleEmulatorTestRunner extends AndroidJUnitRunner {
-
- @Override
- public Application newApplication(ClassLoader cl, String className, Context context)
- throws ClassNotFoundException, IllegalAccessException, InstantiationException {
- return super.newApplication(cl, HiltTestApplication.class.getName(), context);
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/debug/AndroidManifest.xml b/java/dagger/hilt/android/example/gradle/simple/app/src/debug/AndroidManifest.xml
deleted file mode 100644
index 86460d834..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/debug/AndroidManifest.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
- ~ Copyright (C) 2017 The Dagger Authors.
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.example.gradle.simple">
-
- <application>
- <activity
- android:name=".Injection1Test$TestActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="false" />
- <activity
- android:name=".Injection2Test$TestActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="false"/>
- <activity
- android:name=".ActivityScenarioRuleTest$TestActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="false"/>
- </application>
-</manifest>
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/AndroidManifest.xml b/java/dagger/hilt/android/example/gradle/simple/app/src/main/AndroidManifest.xml
deleted file mode 100644
index 662c5b4c2..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<!--
- ~ Copyright (C) 2017 The Dagger Authors.
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.example.gradle.simple">
-
- <application android:name=".SimpleApplication" android:label="@string/appName">
- <activity
- android:name=".SimpleActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity
- android:name=".SettingsActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="false">
- </activity>
- </application>
-</manifest>
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SettingsActivity.java b/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SettingsActivity.java
deleted file mode 100644
index f508e48a0..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SettingsActivity.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import android.os.Bundle;
-import android.widget.TextView;
-import androidx.appcompat.app.AppCompatActivity;
-import dagger.hilt.android.AndroidEntryPoint;
-import javax.inject.Inject;
-
-/** The settings activity of the application. */
-@AndroidEntryPoint
-public class SettingsActivity extends AppCompatActivity {
- private static final String TAG = SettingsActivity.class.getSimpleName();
-
- @Inject SettingsGreeter greeter;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_settings);
-
- ((TextView) findViewById(R.id.settings_greeting)).setText(greeter.greet());
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SettingsGreeter.java b/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SettingsGreeter.java
deleted file mode 100644
index 4f8ab14cd..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SettingsGreeter.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import android.app.Activity;
-import javax.inject.Inject;
-
-/** A class that returns a greeting for {@link SettingsActivity}. */
-final class SettingsGreeter {
- private final Activity activity;
- private final String userName;
- private final String model;
-
- @Inject
- SettingsGreeter(Activity activity, @UserName String userName, @Model String model) {
- this.activity = activity;
- this.userName = userName;
- this.model = model;
- }
-
- public String greet() {
- return activity.getResources().getString(R.string.settings_welcome, userName, model);
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleActivity.java b/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleActivity.java
deleted file mode 100644
index 70e2e5775..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleActivity.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.widget.Button;
-import android.widget.TextView;
-import androidx.appcompat.app.AppCompatActivity;
-import dagger.hilt.android.AndroidEntryPoint;
-import dagger.hilt.android.example.gradle.simple.feature.FeatureActivity;
-import javax.inject.Inject;
-
-/** The main activity of the application. */
-@AndroidEntryPoint
-public class SimpleActivity extends AppCompatActivity {
- private static final String TAG = SimpleActivity.class.getSimpleName();
-
- @Inject SimpleGreeter greeter;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_main);
-
- ((TextView) findViewById(R.id.greeting)).setText(greeter.greet());
-
- Button featureButton = (Button) findViewById(R.id.goto_feature);
- featureButton.setOnClickListener(
- view -> startActivity(new Intent(this, FeatureActivity.class)));
-
- Button settingsButton = (Button) findViewById(R.id.goto_settings);
- settingsButton.setOnClickListener(
- view -> startActivity(new Intent(this, SettingsActivity.class)));
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/UserName.java b/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/UserName.java
deleted file mode 100644
index 173b163b9..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/UserName.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/** Qualifies bindings relating to the user name. */
-@Qualifier
-@Retention(RUNTIME)
-@Documented
-@interface UserName {}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/UserNameModule.java b/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/UserNameModule.java
deleted file mode 100644
index 3969b7335..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/UserNameModule.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.components.ActivityComponent;
-
-@Module
-@InstallIn(ActivityComponent.class)
-final class UserNameModule {
- @UserName
- @Provides
- static String provideUserName() {
- return "ProdUser";
- }
-
- private UserNameModule() {}
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/layout/activity_main.xml b/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 8a23af595..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2017 The Dagger Authors.
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/background_light">
-
- <TextView
- android:id="@+id/greeting"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:textColor="@android:color/primary_text_light"
- />
-
- <Button
- android:id="@+id/goto_settings"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/greeting"
- android:text="@string/navigateToSettings"
- />
-
- <Button
- android:id="@+id/goto_feature"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/goto_settings"
- android:text="@string/navigateToFeature"
- />
-</RelativeLayout>
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/layout/activity_settings.xml b/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/layout/activity_settings.xml
deleted file mode 100644
index 466856c26..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/layout/activity_settings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <TextView
- android:id="@+id/settings_greeting"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/settings_welcome" />
-</FrameLayout>
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/values/strings.xml b/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/values/strings.xml
deleted file mode 100644
index f1b550cf9..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <!--The app name [CHAR_LIMIT=20]-->
- <string name="appName">Simple Hilt Android</string>
-
- <!--The greeting message [CHAR_LIMIT=100]-->
- <string name="welcome">Hello, %1$s!</string>
-
- <!--The feature button message [CHAR_LIMIT=100]-->
- <string name="navigateToFeature">Navigate to a feature!</string>
-
- <!--The settings button message [CHAR_LIMIT=100]-->
- <string name="navigateToSettings">Navigate to settings!</string>
-
- <!--The feature button message [CHAR_LIMIT=100]-->
- <string name="settings_welcome">%1$s, you are on build %2$s.</string>
-</resources>
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/ActivityScenarioRuleTest.java b/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/ActivityScenarioRuleTest.java
deleted file mode 100644
index 7f1fcfcea..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/ActivityScenarioRuleTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import static androidx.lifecycle.Lifecycle.State.RESUMED;
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.test.ext.junit.rules.ActivityScenarioRule;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.hilt.android.AndroidEntryPoint;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Tests that {@link ActivityScenarioRule} works with Hilt tests. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class ActivityScenarioRuleTest {
- private static final String STR_VALUE = "STR_VALUE";
-
- /** An activity to test injection. */
- @AndroidEntryPoint
- public static final class TestActivity extends AppCompatActivity {
- @Inject String str;
- }
-
- @Rule(order = 0) public HiltAndroidRule hiltRule = new HiltAndroidRule(this);
-
- @Rule(order = 1)
- public ActivityScenarioRule<TestActivity> scenarioRule =
- new ActivityScenarioRule<>(TestActivity.class);
-
- @BindValue String str = STR_VALUE;
-
- @Test
- public void testState() {
- assertThat(scenarioRule.getScenario().getState()).isEqualTo(RESUMED);
- }
-
- @Test
- public void testInjection() {
- scenarioRule
- .getScenario()
- .onActivity(activity -> assertThat(activity.str).isEqualTo(STR_VALUE));
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/BindValueTest.java b/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/BindValueTest.java
deleted file mode 100644
index 7abe3c2ff..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/BindValueTest.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import com.google.common.collect.ImmutableSet;
-import dagger.MapKey;
-import dagger.hilt.EntryPoint;
-import dagger.hilt.EntryPoints;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.testing.BindElementsIntoSet;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.BindValueIntoMap;
-import dagger.hilt.android.testing.BindValueIntoSet;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.components.SingletonComponent;
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** A simple test using Hilt. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class BindValueTest {
- private static final String BIND_VALUE_STRING = "BIND_VALUE_STRING";
- private static final String TEST_QUALIFIER = "TEST_QUALIFIER";
-
- private static final String SET_STRING_1 = "SetString1";
- private static final String SET_STRING_2 = "SetString2";
- private static final String SET_STRING_3 = "SetString3";
-
- private static final String KEY_1 = "Key1";
- private static final String KEY_2 = "Key2";
- private static final String VALUE_1 = "Value1";
- private static final String VALUE_2 = "Value2";
- private static final String VALUE_3 = "Value3";
-
- private static final Integer SET_INT_1 = 1;
- private static final Integer SET_INT_2 = 2;
- private static final Integer SET_INT_3 = 3;
-
- @EntryPoint
- @InstallIn(SingletonComponent.class)
- interface BindValueEntryPoint {
- @Named(TEST_QUALIFIER)
- String bindValueString();
-
- Set<String> getStringSet();
- }
-
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @BindValue
- @Named(TEST_QUALIFIER)
- String bindValueString = BIND_VALUE_STRING;
-
- @BindElementsIntoSet Set<String> bindElementsSet1 = ImmutableSet.of(SET_STRING_1);
- @BindElementsIntoSet Set<String> bindElementsSet2 = ImmutableSet.of(SET_STRING_2);
-
- @BindValueIntoMap
- @MyMapKey(KEY_1)
- String boundValue1 = VALUE_1;
-
- @BindValueIntoMap
- @MyMapKey(KEY_2)
- String boundValue2 = VALUE_2;
-
- @BindValueIntoSet Integer bindValueSetInt1 = SET_INT_1;
- @BindValueIntoSet Integer bindValueSetInt2 = SET_INT_2;
-
- @Inject Set<String> stringSet;
- @Inject Provider<Set<String>> providedStringSet;
- @Inject Provider<Map<String, String>> mapProvider;
- @Inject Set<Integer> intSet;
- @Inject Provider<Set<Integer>> providedIntSet;
-
- @Test
- public void testBindValueFieldIsProvided() throws Exception {
- assertThat(bindValueString).isEqualTo(BIND_VALUE_STRING);
- assertThat(getBinding()).isEqualTo(BIND_VALUE_STRING);
- }
-
- @Test
- public void testBindValueIsMutable() throws Exception {
- bindValueString = "newValue";
- assertThat(getBinding()).isEqualTo("newValue");
- }
-
- @Test
- public void testElementsIntoSet() throws Exception {
- rule.inject();
- // basic check that initial/default values are properly injected
- assertThat(providedStringSet.get()).containsExactly(SET_STRING_1, SET_STRING_2);
- // Test empty sets (something that cannot be done with @BindValueIntoSet)
- bindElementsSet1 = ImmutableSet.of();
- bindElementsSet2 = ImmutableSet.of();
- assertThat(providedStringSet.get()).isEmpty();
- // Test multiple elements in set.
- bindElementsSet1 = ImmutableSet.of(SET_STRING_1, SET_STRING_2, SET_STRING_3);
- assertThat(providedStringSet.get()).containsExactly(SET_STRING_1, SET_STRING_2, SET_STRING_3);
- }
-
- @Test
- public void testBindValueIntoMap() throws Exception {
- rule.inject();
- Map<String, String> oldMap = mapProvider.get();
- assertThat(oldMap).containsExactly(KEY_1, VALUE_1, KEY_2, VALUE_2);
- boundValue1 = VALUE_3;
- Map<String, String> newMap = mapProvider.get();
- assertThat(oldMap).containsExactly(KEY_1, VALUE_1, KEY_2, VALUE_2);
- assertThat(newMap).containsExactly(KEY_1, VALUE_3, KEY_2, VALUE_2);
- }
-
- @Test
- public void testBindValueIntoSet() throws Exception {
- rule.inject();
- // basic check that initial/default values are properly injected
- assertThat(providedIntSet.get()).containsExactly(SET_INT_1, SET_INT_2);
- bindValueSetInt1 = SET_INT_3;
- // change the value for bindValueSetString from 1 to 3
- assertThat(providedIntSet.get()).containsExactly(SET_INT_2, SET_INT_3);
- }
-
- @MapKey
- @interface MyMapKey {
- String value();
- }
-
- private static String getBinding() {
- return EntryPoints.get(getApplicationContext(), BindValueEntryPoint.class).bindValueString();
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/Injection1Test.java b/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/Injection1Test.java
deleted file mode 100644
index 0ebd1506c..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/Injection1Test.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.AndroidEntryPoint;
-import dagger.hilt.android.components.ActivityComponent;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.components.SingletonComponent;
-import javax.inject.Inject;
-import javax.inject.Named;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Tests basic injection APIs, and that bindings don't conflict with {@link Injection2Test}. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class Injection1Test {
- private static final String APPLICATION_QUALIFIER = "APPLICATION_QUALIFIER";
- private static final String ACTIVITY_QUALIFIER = "ACTIVITY_QUALIFIER";
- private static final String APPLICATION_VALUE = "Injection1Test_ApplicationValue";
- private static final String ACTIVITY_VALUE = "Injection1Test_ActivityValue";
-
- @Module
- @InstallIn(SingletonComponent.class)
- interface TestApplicationModule {
- @Provides
- @Named(APPLICATION_QUALIFIER)
- static String provideString() {
- return APPLICATION_VALUE;
- }
- }
-
- @Module
- @InstallIn(ActivityComponent.class)
- interface TestActivityModule {
- @Provides
- @Named(ACTIVITY_QUALIFIER)
- static String provideString() {
- return ACTIVITY_VALUE;
- }
- }
-
- /** Test activity used to test activity injection */
- @AndroidEntryPoint
- public static final class TestActivity extends AppCompatActivity {
- @Inject @Named(ACTIVITY_QUALIFIER) String activityValue;
- }
-
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @Inject @Named(APPLICATION_QUALIFIER) String applicationValue;
-
- @Test
- public void testApplicationInjection() throws Exception {
- assertThat(applicationValue).isNull();
- rule.inject();
- assertThat(applicationValue).isEqualTo(APPLICATION_VALUE);
- }
-
- @Test
- public void testActivityInjection() throws Exception {
- try (ActivityScenario<TestActivity> scenario = ActivityScenario.launch(TestActivity.class)) {
- scenario.onActivity(activity -> assertThat(activity.activityValue).isEqualTo(ACTIVITY_VALUE));
- }
- }
-
- @Test
- public void testSuperClassTransformation() {
- try (ActivityScenario<TestActivity> scenario = ActivityScenario.launch(TestActivity.class)) {
- scenario.onActivity(
- activity ->
- assertThat(activity.getClass().getSuperclass().getSimpleName())
- .isEqualTo("Hilt_Injection1Test_TestActivity"));
- }
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/Injection2Test.java b/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/Injection2Test.java
deleted file mode 100644
index 51d60b239..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/Injection2Test.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.AndroidEntryPoint;
-import dagger.hilt.android.components.ActivityComponent;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.components.SingletonComponent;
-import javax.inject.Inject;
-import javax.inject.Named;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Tests basic injection APIs, and that bindings don't conflict with {@link Injection1Test}. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class Injection2Test {
- private static final String APPLICATION_QUALIFIER = "APPLICATION_QUALIFIER";
- private static final String ACTIVITY_QUALIFIER = "ACTIVITY_QUALIFIER";
- private static final String APPLICATION_VALUE = "Injection2Test_ApplicationValue";
- private static final String ACTIVITY_VALUE = "Injection2Test_ActivityValue";
-
- @Module
- @InstallIn(SingletonComponent.class)
- interface TestApplicationModule {
- @Provides
- @Named(APPLICATION_QUALIFIER)
- static String provideString() {
- return APPLICATION_VALUE;
- }
- }
-
- @Module
- @InstallIn(ActivityComponent.class)
- interface TestActivityModule {
- @Provides
- @Named(ACTIVITY_QUALIFIER)
- static String provideString() {
- return ACTIVITY_VALUE;
- }
- }
-
- /** Test activity used to test activity injection */
- @AndroidEntryPoint
- public static final class TestActivity extends AppCompatActivity {
- @Inject @Named(ACTIVITY_QUALIFIER) String activityValue;
- }
-
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @Inject @Named(APPLICATION_QUALIFIER) String applicationValue;
-
- @Test
- public void testApplicationInjection() throws Exception {
- assertThat(applicationValue).isNull();
- rule.inject();
- assertThat(applicationValue).isEqualTo(APPLICATION_VALUE);
- }
-
- @Test
- public void testActivityInjection() throws Exception {
- try (ActivityScenario<TestActivity> scenario = ActivityScenario.launch(TestActivity.class)) {
- scenario.onActivity(activity -> assertThat(activity.activityValue).isEqualTo(ACTIVITY_VALUE));
- }
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/ModuleTest.java b/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/ModuleTest.java
deleted file mode 100644
index 73daf8fac..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/ModuleTest.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import static org.junit.Assert.assertEquals;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.components.SingletonComponent;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-import javax.inject.Inject;
-import javax.inject.Qualifier;
-import javax.inject.Singleton;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Tests basic functionality of using modules in test. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class ModuleTest {
- @Rule public final HiltAndroidRule rules = new HiltAndroidRule(this);
-
- /** Qualifier for distinguishing test Strings, */
- @Qualifier
- @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
- public @interface TestQualifier {
- int value();
- }
-
- @Inject
- @TestQualifier(1)
- String testString1;
-
- @Inject
- @TestQualifier(2)
- String testString2;
-
- @Inject
- @TestQualifier(3)
- String testString3;
-
- @Inject
- @TestQualifier(4)
- String testString4;
-
- @Inject FooImpl fooImpl;
- @Inject Foo foo;
-
- /**
- * Module which is used to test if non-static test modules get registered in the component
- * correctly.
- */
- @Module
- @InstallIn(SingletonComponent.class)
- public final class NonStaticModuleNonStaticProvides {
- @Provides
- @TestQualifier(1)
- String provideString() {
- return "1";
- }
- }
-
- /**
- * Module which is used to test if static test modules get registered in the component correctly.
- */
- @Module
- @InstallIn(SingletonComponent.class)
- public static final class StaticModuleStaticProvides {
- @Provides
- @TestQualifier(2)
- static String provideString() {
- return "2";
- }
-
- private StaticModuleStaticProvides() {}
- }
-
- /**
- * Module which is used to test if static test modules with a non-static methods get registered in
- * the component correctly.
- */
- @Module
- @InstallIn(SingletonComponent.class)
- public static final class StaticModuleNonStaticProvidesDefaultConstructor {
- @Provides
- @TestQualifier(3)
- String provideString() {
- return "3";
- }
- }
-
- /**
- * Module which is used to test if abstract test modules get registered in the component
- * correctly.
- */
- @Module
- @InstallIn(SingletonComponent.class)
- public abstract static class AbstractModuleStaticProvides {
- @Provides
- @TestQualifier(4)
- static String provideString() {
- return "4";
- }
-
- private AbstractModuleStaticProvides() {}
- }
-
- /**
- * Module which is used to test if abstract test modules with a binds method get registered in the
- * component correctly.
- */
- @Module
- @InstallIn(SingletonComponent.class)
- public abstract static class AbstractModuleBindsMethod {
- @Binds
- abstract Foo foo(FooImpl fooImpl);
- }
-
- interface Foo {}
-
- @Singleton
- static final class FooImpl implements Foo {
- @Inject
- FooImpl() {}
- }
-
- @Test
- public void testInjection() throws Exception {
- rules.inject();
- assertEquals("1", testString1);
- assertEquals("2", testString2);
- assertEquals("3", testString3);
- assertEquals("4", testString4);
- assertEquals(fooImpl, foo);
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/test/java/dagger/hilt/android/example/gradle/simple/SettingsActivityTest.java b/java/dagger/hilt/android/example/gradle/simple/app/src/test/java/dagger/hilt/android/example/gradle/simple/SettingsActivityTest.java
deleted file mode 100644
index f1e5f278e..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/test/java/dagger/hilt/android/example/gradle/simple/SettingsActivityTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.os.Build;
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.android.testing.HiltTestApplication;
-import dagger.hilt.android.testing.UninstallModules;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.annotation.Config;
-
-/** A simple test using Hilt. */
-@UninstallModules(ModelModule.class)
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
-@Config(sdk = Build.VERSION_CODES.P, application = HiltTestApplication.class)
-public final class SettingsActivityTest {
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @BindValue @Model String fakeModel = "FakeModel";
-
- @Inject @Model String injectedModel;
-
- @Test
- public void testInjectedModel() throws Exception {
- assertThat(injectedModel).isNull();
- rule.inject();
- assertThat(injectedModel).isEqualTo("FakeModel");
- }
-
- @Test
- public void testActivityInject() throws Exception {
- try (ActivityScenario<SettingsActivity> scenario =
- ActivityScenario.launch(SettingsActivity.class)) {
- scenario.onActivity(
- activity ->
- assertThat(activity.greeter.greet())
- .isEqualTo("ProdUser, you are on build FakeModel."));
- }
- }
-
- @Test
- public void testSuperClassTransformation() {
- try (ActivityScenario<SettingsActivity> scenario =
- ActivityScenario.launch(SettingsActivity.class)) {
- scenario.onActivity(
- activity ->
- assertThat(activity.getClass().getSuperclass().getSimpleName())
- .isEqualTo("Hilt_SettingsActivity"));
- }
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/test/java/dagger/hilt/android/example/gradle/simple/SimpleActivityTest.java b/java/dagger/hilt/android/example/gradle/simple/app/src/test/java/dagger/hilt/android/example/gradle/simple/SimpleActivityTest.java
deleted file mode 100644
index 29b5f70ff..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/test/java/dagger/hilt/android/example/gradle/simple/SimpleActivityTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.os.Build;
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.android.testing.HiltTestApplication;
-import dagger.hilt.android.testing.UninstallModules;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.annotation.Config;
-
-/** A simple test using Hilt. */
-@UninstallModules(UserNameModule.class)
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
-@Config(sdk = Build.VERSION_CODES.P, application = HiltTestApplication.class)
-public final class SimpleActivityTest {
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @BindValue @UserName String fakeUserName = "FakeUser";
-
- @Inject @UserName String injectedUserName;
-
- @Test
- public void testInjectedUserName() throws Exception {
- assertThat(injectedUserName).isNull();
- rule.inject();
- assertThat(injectedUserName).isEqualTo("FakeUser");
- }
-
- @Test
- public void testActivityInject() throws Exception {
- try (ActivityScenario<SimpleActivity> scenario =
- ActivityScenario.launch(SimpleActivity.class)) {
- scenario.onActivity(
- activity -> assertThat(activity.greeter.greet()).isEqualTo("Hello, FakeUser!"));
- }
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/test/resources/dagger/hilt/android/example/gradle/simple/robolectric.properties b/java/dagger/hilt/android/example/gradle/simple/app/src/test/resources/dagger/hilt/android/example/gradle/simple/robolectric.properties
deleted file mode 100644
index 0234ffe6f..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/test/resources/dagger/hilt/android/example/gradle/simple/robolectric.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-sdk=28
-application=dagger.hilt.android.testing.HiltTestApplication \ No newline at end of file
diff --git a/java/dagger/hilt/android/example/gradle/simple/build.gradle b/java/dagger/hilt/android/example/gradle/simple/build.gradle
deleted file mode 100644
index c0916a4d2..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/build.gradle
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-buildscript {
- ext {
- kotlin_version = '1.3.61'
- agp_version = "4.2.0-beta04"
- }
- repositories {
- google()
- jcenter()
- mavenLocal()
- }
- dependencies {
- classpath "com.android.tools.build:gradle:$agp_version"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath 'com.google.dagger:hilt-android-gradle-plugin:LOCAL-SNAPSHOT'
- }
-}
-
-allprojects {
- repositories {
- google()
- jcenter()
- mavenCentral()
- mavenLocal()
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/AndroidManifest.xml b/java/dagger/hilt/android/example/gradle/simple/feature/src/main/AndroidManifest.xml
deleted file mode 100644
index f7919a92f..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.example.gradle.simple.feature">
- <application>
- <activity
- android:name=".FeatureActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="true"/>
- </application>
-</manifest>
diff --git a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureActivity.kt b/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureActivity.kt
deleted file mode 100644
index 03b9ae9f7..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureActivity.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple.feature
-
-import android.os.Bundle
-import android.widget.Button
-import android.widget.TextView
-import androidx.appcompat.app.AppCompatActivity
-import dagger.hilt.android.AndroidEntryPoint
-import javax.inject.Inject
-
-@AndroidEntryPoint
-class FeatureActivity : AppCompatActivity() {
- @Inject lateinit var counter: FeatureCounter
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- setContentView(R.layout.activity_feature)
-
- findViewById<Button>(R.id.feature_button).setOnClickListener {
- counter.count++
- updateCountText()
- }
-
- updateCountText()
- }
-
- private fun updateCountText() {
- findViewById<TextView>(R.id.feature_count).text = "The count: ${counter.count}"
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureModule.kt b/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureModule.kt
deleted file mode 100644
index 84ca99a84..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureModule.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple.feature
-
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.android.components.ActivityRetainedComponent
-import dagger.hilt.android.scopes.ActivityRetainedScoped
-
-@Module
-@InstallIn(ActivityRetainedComponent::class)
-object FeatureModule {
- @Provides
- @ActivityRetainedScoped
- fun provideData() = FeatureCounter(0)
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/res/layout/activity_feature.xml b/java/dagger/hilt/android/example/gradle/simple/feature/src/main/res/layout/activity_feature.xml
deleted file mode 100644
index bf524311d..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/res/layout/activity_feature.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2017 The Dagger Authors.
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/background_light">
-
- <TextView
- android:id="@+id/feature_count"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:textColor="@android:color/primary_text_light"
- />
-
- <Button
- android:id="@+id/feature_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/feature_count"
- android:text="Count++"
- />
-</RelativeLayout>
diff --git a/java/dagger/hilt/android/example/gradle/simple/gradle.properties b/java/dagger/hilt/android/example/gradle/simple/gradle.properties
deleted file mode 100644
index 646c51b97..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/gradle.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-android.useAndroidX=true
-android.enableJetifier=true
diff --git a/java/dagger/hilt/android/example/gradle/simple/settings.gradle b/java/dagger/hilt/android/example/gradle/simple/settings.gradle
deleted file mode 100644
index 2ae0b0a70..000000000
--- a/java/dagger/hilt/android/example/gradle/simple/settings.gradle
+++ /dev/null
@@ -1,3 +0,0 @@
-rootProject.name='Simple Hilt Android'
-include ':app'
-include ':feature'
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/build.gradle b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/build.gradle
deleted file mode 100644
index bff479799..000000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/build.gradle
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-apply plugin: 'dagger.hilt.android.plugin'
-apply plugin: 'kotlin-kapt'
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- applicationId "dagger.hilt.android.example.gradle.simpleKotlin"
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- }
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
- testOptions {
- unitTests.includeAndroidResources = true
- }
-}
-
-dependencies {
- implementation fileTree(dir: "libs", include: ["*.jar"])
- implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
- implementation 'androidx.appcompat:appcompat:1.2.0'
-
- implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- kapt 'com.google.dagger:hilt-android-compiler:LOCAL-SNAPSHOT'
-
- testImplementation 'com.google.truth:truth:1.0.1'
- testImplementation 'junit:junit:4.13'
- testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
- testImplementation 'androidx.core:core:1.3.2'
- // TODO(bcorso): This multidex dep shouldn't be required -- it's a dep for the generated code.
- testImplementation 'androidx.multidex:multidex:2.0.0'
- testImplementation 'com.google.dagger:hilt-android-testing:LOCAL-SNAPSHOT'
- kaptTest 'com.google.dagger:hilt-android-compiler:LOCAL-SNAPSHOT'
-}
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/AndroidManifest.xml b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/AndroidManifest.xml
deleted file mode 100644
index 2e274ab0b..000000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Dagger Authors.
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.example.gradle.simpleKotlin">
-
- <application
- android:name=".KotlinApplication"
- android:allowBackup="true"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/Theme.AppCompat.Light">
- <activity android:name=".MainActivity" android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/ActivityModule.kt b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/ActivityModule.kt
deleted file mode 100644
index 8a85040ab..000000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/ActivityModule.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package dagger.hilt.android.example.gradle.simpleKotlin
-
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.android.components.ActivityComponent
-
-@Module
-@InstallIn(ActivityComponent::class)
-object ActivityModule {
- @UserName
- @Provides
- fun provideUserName(): String {
- return "Android User"
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/ApplicationModule.kt b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/ApplicationModule.kt
deleted file mode 100644
index 9ee904d52..000000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/ApplicationModule.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simpleKotlin
-
-import android.os.Build
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-
-@Module
-@InstallIn(SingletonComponent::class)
-object ApplicationModule {
- @Provides
- @Model
- fun provideModel(): String {
- return Build.MODEL
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/MainActivity.kt b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/MainActivity.kt
deleted file mode 100644
index 564f05ab1..000000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/MainActivity.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simpleKotlin
-
-import android.os.Bundle
-import android.view.View
-import android.widget.TextView
-import androidx.appcompat.app.AppCompatActivity
-import dagger.hilt.android.AndroidEntryPoint
-import javax.inject.Inject
-
-@AndroidEntryPoint
-class MainActivity : AppCompatActivity() {
- // Shows that we can inject Application/Activity bindings into an activity.
- @JvmField
- @Model
- @Inject
- var model: String? = null
-
- @JvmField
- @UserName
- @Inject
- var name: String? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- val greeting = findViewById<View>(R.id.greeting) as TextView
- val text = resources.getString(R.string.welcome, name, model)
- greeting.text = text
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/res/layout/activity_main.xml b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 0d7637d42..000000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Dagger Authors.
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/background_light">
-
- <TextView
- android:id="@+id/greeting"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:textColor="@android:color/primary_text_light"
- />
-</RelativeLayout>
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/test/java/dagger/hilt/android/example/gradle/simpleKotlin/SimpleTest.kt b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/test/java/dagger/hilt/android/example/gradle/simpleKotlin/SimpleTest.kt
deleted file mode 100644
index d52ff716d..000000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/test/java/dagger/hilt/android/example/gradle/simpleKotlin/SimpleTest.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simpleKotlin
-
-import android.os.Build
-import androidx.appcompat.app.AppCompatActivity
-import androidx.test.core.app.ActivityScenario
-import com.google.common.truth.Truth.assertThat
-import dagger.hilt.android.AndroidEntryPoint
-import dagger.hilt.android.testing.HiltAndroidRule
-import dagger.hilt.android.testing.HiltAndroidTest
-import dagger.hilt.android.testing.HiltTestApplication
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.robolectric.RobolectricTestRunner
-import org.robolectric.annotation.Config
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-@HiltAndroidTest
-@RunWith(RobolectricTestRunner::class)
-// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
-@Config(sdk = [Build.VERSION_CODES.P], application = HiltTestApplication::class)
-class SimpleTest {
- @Rule
- @JvmField
- var rule = HiltAndroidRule(this)
-
- @AndroidEntryPoint
- class TestActivity : AppCompatActivity()
-
- @Test
- fun verifyMainActivity() {
- ActivityScenario.launch(MainActivity::class.java).use { scenario ->
- scenario.onActivity { activity ->
- assertThat(activity::class.java.getSuperclass()?.getSimpleName())
- .isEqualTo("Hilt_MainActivity")
- assertThat(activity.model).isNotNull()
- assertThat(activity.name).isNotNull()
- }
- }
- }
-
- @Test
- fun verifyTestActivity() {
- ActivityScenario.launch(TestActivity::class.java).use { scenario ->
- scenario.onActivity { activity ->
- assertThat(activity::class.java.getSuperclass()?.getSimpleName())
- .isEqualTo("Hilt_SimpleTest_TestActivity")
- }
- }
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle.properties b/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle.properties
deleted file mode 100644
index 646c51b97..000000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-android.useAndroidX=true
-android.enableJetifier=true
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle/wrapper/gradle-wrapper.jar b/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 5c2d1cf01..000000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle/wrapper/gradle-wrapper.properties b/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 4d9ca1649..000000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradlew b/java/dagger/hilt/android/example/gradle/simpleKotlin/gradlew
deleted file mode 100755
index b0d6d0ab5..000000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradlew
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/usr/bin/env sh
-
-#
-# Copyright 2015 the original author or authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-##############################################################################
-##
-## Gradle start up script for UN*X
-##
-##############################################################################
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn () {
- echo "$*"
-}
-
-die () {
- echo
- echo "$*"
- echo
- exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
- else
- JAVACMD="$JAVA_HOME/bin/java"
- fi
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
- fi
- i=$((i+1))
- done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
-fi
-
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=$(save "$@")
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
- cd "$(dirname "$0")"
-fi
-
-exec "$JAVACMD" "$@"
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/settings.gradle b/java/dagger/hilt/android/example/gradle/simpleKotlin/settings.gradle
deleted file mode 100644
index e42f9d1ea..000000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/settings.gradle
+++ /dev/null
@@ -1,2 +0,0 @@
-rootProject.name='Simple Kotlin Hilt Android'
-include ':app'
diff --git a/java/dagger/hilt/android/flags/BUILD b/java/dagger/hilt/android/flags/BUILD
new file mode 100644
index 000000000..7bd9010a3
--- /dev/null
+++ b/java/dagger/hilt/android/flags/BUILD
@@ -0,0 +1,40 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Description:
+# Runtime flags to control Hilt behavior for rollout of changes. These flags are usually
+# meant to be temporary and so defaults may change with releases and then these flags
+# may eventually be removed, just like compiler options with similar purposes.
+
+package(default_visibility = ["//:src"])
+
+android_library(
+ name = "fragment_get_context_fix",
+ srcs = [
+ "FragmentGetContextFix.java",
+ ],
+ deps = [
+ "//:dagger_with_compiler",
+ "//java/dagger/hilt:entry_point",
+ "//java/dagger/hilt:install_in",
+ "//java/dagger/hilt/android:entry_point_accessors",
+ "//java/dagger/hilt/android/components",
+ "//java/dagger/hilt/internal:preconditions",
+ ],
+)
+
+filegroup(
+ name = "srcs_filegroup",
+ srcs = glob(["*"]),
+)
diff --git a/java/dagger/hilt/android/flags/FragmentGetContextFix.java b/java/dagger/hilt/android/flags/FragmentGetContextFix.java
new file mode 100644
index 000000000..d85d39b82
--- /dev/null
+++ b/java/dagger/hilt/android/flags/FragmentGetContextFix.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.flags;
+
+import android.content.Context;
+import dagger.Module;
+import dagger.hilt.EntryPoint;
+import dagger.hilt.InstallIn;
+import dagger.hilt.android.EntryPointAccessors;
+import dagger.hilt.components.SingletonComponent;
+import dagger.hilt.internal.Preconditions;
+import dagger.multibindings.Multibinds;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.util.Set;
+import javax.inject.Qualifier;
+
+/**
+ * Runtime flag for the Fragment.getContext() fix. See https://github.com/google/dagger/pull/2620
+ * for this change. Controls if fragment code should use the fixed getContext() behavior where it
+ * correctly returns null after a fragment is removed. This fixed behavior matches the behavior of a
+ * regular, non-Hilt fragment and can help catch issues where a removed or leaked fragment is
+ * incorrectly used.
+ *
+ * <p>In order to set the flag, bind a boolean value qualified with
+ * {@link DisableFragmentGetContextFix} into a set in the {@code SingletonComponent}. A set is used
+ * instead of an optional binding to avoid a dependency on Guava. Only one value may be bound into
+ * the set within a given app. If this is not set, the default is to not use the fix. Example for
+ * binding the value:
+ *
+ * <pre><code>
+ * {@literal @}Module
+ * {@literal @}InstallIn(SingletonComponent.class)
+ * public final class DisableFragmentGetContextFixModule {
+ * {@literal @}Provides
+ * {@literal @}IntoSet
+ * {@literal @}FragmentGetContextFix.DisableFragmentGetContextFix
+ * static Boolean provideDisableFragmentGetContextFix() {
+ * return // true or false depending on some rollout logic for your app
+ * }
+ * }
+ * </code></pre>
+ */
+public final class FragmentGetContextFix {
+
+ /** Qualifier annotation to bind disable the Fragment.getContext() fix at runtime. */
+ @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
+ @Qualifier
+ public @interface DisableFragmentGetContextFix {}
+
+ public static boolean isFragmentGetContextFixDisabled(Context context) {
+ // Use a set here instead of an optional to avoid the Guava dependency
+ Set<Boolean> flagSet = EntryPointAccessors.fromApplication(
+ context, FragmentGetContextFixEntryPoint.class).getDisableFragmentGetContextFix();
+
+ // TODO(b/199927963): Consider adding a plugin to check this at compile time
+ Preconditions.checkState(flagSet.size() <= 1,
+ "Cannot bind the flag @DisableFragmentGetContextFix more than once.");
+
+ if (flagSet.isEmpty()) {
+ return true;
+ } else {
+ return flagSet.iterator().next();
+ }
+ }
+
+ /** Entry point for getting the flag. */
+ @EntryPoint
+ @InstallIn(SingletonComponent.class)
+ public interface FragmentGetContextFixEntryPoint {
+ @DisableFragmentGetContextFix Set<Boolean> getDisableFragmentGetContextFix();
+ }
+
+ /** Declare the empty flag set. */
+ @Module
+ @InstallIn(SingletonComponent.class)
+ abstract static class FragmentGetContextFixModule {
+ @Multibinds
+ @DisableFragmentGetContextFix
+ abstract Set<Boolean> disableFragmentGetContextFix();
+ }
+
+ private FragmentGetContextFix() {
+ }
+}
diff --git a/java/dagger/hilt/android/flags/package-info.java b/java/dagger/hilt/android/flags/package-info.java
new file mode 100644
index 000000000..1a39fc29a
--- /dev/null
+++ b/java/dagger/hilt/android/flags/package-info.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Runtime flags to control Hilt behavior for rollout of changes. These flags are usually meant to
+ * be temporary and so defaults may change with releases and then these flags may eventually be
+ * removed, just like compiler options with similar purposes.
+ *
+ * @see <a href="https://dagger.dev/hilt">Hilt Developer Docs</a>
+ */
+@ParametersAreNonnullByDefault
+package dagger.hilt.android.flags;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/java/dagger/hilt/android/internal/BUILD b/java/dagger/hilt/android/internal/BUILD
index 57c84e3eb..ae8a06692 100644
--- a/java/dagger/hilt/android/internal/BUILD
+++ b/java/dagger/hilt/android/internal/BUILD
@@ -19,7 +19,10 @@ package(default_visibility = ["//:src"])
android_library(
name = "internal",
- srcs = ["ThreadUtil.java"],
+ srcs = [
+ "Contexts.java",
+ "ThreadUtil.java",
+ ],
)
filegroup(
diff --git a/java/dagger/hilt/android/internal/Contexts.java b/java/dagger/hilt/android/internal/Contexts.java
new file mode 100644
index 000000000..b0a6cf8a6
--- /dev/null
+++ b/java/dagger/hilt/android/internal/Contexts.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.internal;
+
+import android.app.Application;
+import android.content.Context;
+import android.content.ContextWrapper;
+
+/**
+ * Utility methods for dealing with contexts.
+ */
+public final class Contexts {
+
+ /** Finds the android Application from a context. */
+ public static Application getApplication(Context context) {
+ if (context instanceof Application) {
+ return (Application) context;
+ }
+
+ Context unwrapContext = context;
+ while (unwrapContext instanceof ContextWrapper) {
+ unwrapContext = ((ContextWrapper) unwrapContext).getBaseContext();
+ if (unwrapContext instanceof Application) {
+ return (Application) unwrapContext;
+ }
+ }
+
+ throw new IllegalStateException(
+ "Could not find an Application in the given context: " + context);
+ }
+
+ private Contexts() {}
+}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/Model.java b/java/dagger/hilt/android/internal/legacy/AggregatedElementProxy.java
index b4aec95d4..e88de29cb 100644
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/Model.java
+++ b/java/dagger/hilt/android/internal/legacy/AggregatedElementProxy.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Dagger Authors.
+ * Copyright (C) 2021 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,16 +14,21 @@
* limitations under the License.
*/
-package dagger.hilt.android.example.gradle.simple;
+package dagger.hilt.android.internal.legacy;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static java.lang.annotation.RetentionPolicy.CLASS;
-import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
+import java.lang.annotation.Target;
-/** Qualifies bindings relating to {@link android.os.Build#MODEL}. */
-@Qualifier
-@Retention(RUNTIME)
-@Documented
-@interface Model {}
+/**
+ * Annotation for marking public proxies that reference package-private aggregating elements from
+ * pre-stable versions of Hilt (version < 2.35).
+ */
+@Target(ElementType.TYPE)
+@Retention(CLASS)
+public @interface AggregatedElementProxy {
+ /** A reference to the legacy package-private aggregating class. */
+ Class<?> value();
+}
diff --git a/java/dagger/hilt/android/internal/legacy/BUILD b/java/dagger/hilt/android/internal/legacy/BUILD
new file mode 100644
index 000000000..0814af06d
--- /dev/null
+++ b/java/dagger/hilt/android/internal/legacy/BUILD
@@ -0,0 +1,23 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Description:
+# Internal Hilt libraries for legacy code.
+
+package(default_visibility = ["//:src"])
+
+java_library(
+ name = "aggregated_element_proxy",
+ srcs = ["AggregatedElementProxy.java"],
+)
diff --git a/java/dagger/hilt/android/internal/lifecycle/DefaultViewModelFactories.java b/java/dagger/hilt/android/internal/lifecycle/DefaultViewModelFactories.java
index 448847cd3..3fb4f19ab 100644
--- a/java/dagger/hilt/android/internal/lifecycle/DefaultViewModelFactories.java
+++ b/java/dagger/hilt/android/internal/lifecycle/DefaultViewModelFactories.java
@@ -17,12 +17,12 @@
package dagger.hilt.android.internal.lifecycle;
import android.app.Application;
-import androidx.lifecycle.SavedStateViewModelFactory;
-import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.activity.ComponentActivity;
+import androidx.lifecycle.SavedStateViewModelFactory;
+import androidx.lifecycle.ViewModelProvider;
import androidx.savedstate.SavedStateRegistryOwner;
import dagger.Module;
import dagger.hilt.EntryPoint;
diff --git a/java/dagger/hilt/android/internal/lifecycle/HiltViewModelFactory.java b/java/dagger/hilt/android/internal/lifecycle/HiltViewModelFactory.java
index 443894127..4e2e0fa8b 100644
--- a/java/dagger/hilt/android/internal/lifecycle/HiltViewModelFactory.java
+++ b/java/dagger/hilt/android/internal/lifecycle/HiltViewModelFactory.java
@@ -17,13 +17,13 @@
package dagger.hilt.android.internal.lifecycle;
import android.app.Activity;
+import android.os.Bundle;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.lifecycle.AbstractSavedStateViewModelFactory;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
-import android.os.Bundle;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.savedstate.SavedStateRegistryOwner;
import dagger.Module;
import dagger.hilt.EntryPoint;
diff --git a/java/dagger/hilt/android/internal/managers/ActivityRetainedComponentManager.java b/java/dagger/hilt/android/internal/managers/ActivityRetainedComponentManager.java
index 0af3dcd11..dc8d7e052 100644
--- a/java/dagger/hilt/android/internal/managers/ActivityRetainedComponentManager.java
+++ b/java/dagger/hilt/android/internal/managers/ActivityRetainedComponentManager.java
@@ -16,19 +16,20 @@
package dagger.hilt.android.internal.managers;
-import androidx.lifecycle.ViewModel;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.lifecycle.ViewModelStoreOwner;
import android.content.Context;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.activity.ComponentActivity;
+import androidx.annotation.NonNull;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.lifecycle.ViewModelStoreOwner;
import dagger.Binds;
import dagger.Module;
import dagger.hilt.EntryPoint;
import dagger.hilt.EntryPoints;
import dagger.hilt.InstallIn;
import dagger.hilt.android.ActivityRetainedLifecycle;
+import dagger.hilt.android.EntryPointAccessors;
import dagger.hilt.android.components.ActivityRetainedComponent;
import dagger.hilt.android.internal.ThreadUtil;
import dagger.hilt.android.internal.builders.ActivityRetainedComponentBuilder;
@@ -84,11 +85,11 @@ final class ActivityRetainedComponentManager
private final Object componentLock = new Object();
ActivityRetainedComponentManager(ComponentActivity activity) {
- this.viewModelProvider = getViewModelProvider(activity, activity.getApplication());
+ this.viewModelProvider = getViewModelProvider(activity, activity);
}
private ViewModelProvider getViewModelProvider(
- ViewModelStoreOwner owner, Context applicationContext) {
+ ViewModelStoreOwner owner, Context context) {
return new ViewModelProvider(
owner,
new ViewModelProvider.Factory() {
@@ -97,8 +98,8 @@ final class ActivityRetainedComponentManager
@SuppressWarnings("unchecked")
public <T extends ViewModel> T create(@NonNull Class<T> aClass) {
ActivityRetainedComponent component =
- EntryPoints.get(
- applicationContext, ActivityRetainedComponentBuilderEntryPoint.class)
+ EntryPointAccessors.fromApplication(
+ context, ActivityRetainedComponentBuilderEntryPoint.class)
.retainedComponentBuilder()
.build();
return (T) new ActivityRetainedComponentViewModel(component);
diff --git a/java/dagger/hilt/android/internal/managers/BUILD b/java/dagger/hilt/android/internal/managers/BUILD
index 76613101e..e9831a238 100644
--- a/java/dagger/hilt/android/internal/managers/BUILD
+++ b/java/dagger/hilt/android/internal/managers/BUILD
@@ -39,6 +39,7 @@ android_library(
"//java/dagger/hilt:entry_point",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android:activity_retained_lifecycle",
+ "//java/dagger/hilt/android:entry_point_accessors",
"//java/dagger/hilt/android/components",
"//java/dagger/hilt/android/internal",
"//java/dagger/hilt/android/internal/builders",
diff --git a/java/dagger/hilt/android/internal/managers/BroadcastReceiverComponentManager.java b/java/dagger/hilt/android/internal/managers/BroadcastReceiverComponentManager.java
index 471c31c91..bc9f9adfd 100644
--- a/java/dagger/hilt/android/internal/managers/BroadcastReceiverComponentManager.java
+++ b/java/dagger/hilt/android/internal/managers/BroadcastReceiverComponentManager.java
@@ -18,6 +18,7 @@ package dagger.hilt.android.internal.managers;
import android.app.Application;
import android.content.Context;
+import dagger.hilt.android.internal.Contexts;
import dagger.hilt.internal.GeneratedComponentManager;
import dagger.hilt.internal.Preconditions;
@@ -27,9 +28,9 @@ import dagger.hilt.internal.Preconditions;
* <p>A manager for the creation of components that live in the BroadcastReceiver.
*/
public final class BroadcastReceiverComponentManager {
- @SuppressWarnings("unchecked")
+
public static Object generatedComponent(Context context) {
- Application application = (Application) context.getApplicationContext();
+ Application application = Contexts.getApplication(context.getApplicationContext());
Preconditions.checkArgument(
application instanceof GeneratedComponentManager,
diff --git a/java/dagger/hilt/android/internal/managers/ViewComponentManager.java b/java/dagger/hilt/android/internal/managers/ViewComponentManager.java
index 78614950a..c209f5511 100644
--- a/java/dagger/hilt/android/internal/managers/ViewComponentManager.java
+++ b/java/dagger/hilt/android/internal/managers/ViewComponentManager.java
@@ -16,19 +16,20 @@
package dagger.hilt.android.internal.managers;
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleEventObserver;
-import androidx.lifecycle.LifecycleOwner;
import android.content.Context;
import android.content.ContextWrapper;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleEventObserver;
+import androidx.lifecycle.LifecycleOwner;
import dagger.hilt.EntryPoint;
import dagger.hilt.EntryPoints;
import dagger.hilt.InstallIn;
import dagger.hilt.android.components.ActivityComponent;
import dagger.hilt.android.components.FragmentComponent;
+import dagger.hilt.android.internal.Contexts;
import dagger.hilt.android.internal.builders.ViewComponentBuilder;
import dagger.hilt.android.internal.builders.ViewWithFragmentComponentBuilder;
import dagger.hilt.internal.GeneratedComponentManager;
@@ -143,8 +144,8 @@ public final class ViewComponentManager implements GeneratedComponentManager<Obj
private Context getParentContext(Class<?> parentType, boolean allowMissing) {
Context context = unwrap(view.getContext(), parentType);
- if (context == unwrap(context.getApplicationContext(), GeneratedComponentManager.class)) {
- // If we searched for a type but ended up on the application context, just return null
+ if (context == Contexts.getApplication(context.getApplicationContext())) {
+ // If we searched for a type but ended up on the application, just return null
// as this is never what we are looking for
Preconditions.checkState(
allowMissing,
diff --git a/java/dagger/hilt/android/internal/migration/BUILD b/java/dagger/hilt/android/internal/migration/BUILD
index b877f6f48..c2549fa7e 100644
--- a/java/dagger/hilt/android/internal/migration/BUILD
+++ b/java/dagger/hilt/android/internal/migration/BUILD
@@ -18,6 +18,11 @@
package(default_visibility = ["//:src"])
android_library(
+ name = "has_custom_inject",
+ srcs = ["HasCustomInject.java"],
+)
+
+android_library(
name = "injected_by_hilt",
srcs = ["InjectedByHilt.java"],
)
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/UserName.kt b/java/dagger/hilt/android/internal/migration/HasCustomInject.java
index a061ab587..ebcac9307 100644
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/UserName.kt
+++ b/java/dagger/hilt/android/internal/migration/HasCustomInject.java
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package dagger.hilt.android.example.gradle.simpleKotlin
+package dagger.hilt.android.internal.migration;
-import javax.inject.Qualifier
-
-/** Qualifies bindings relating to the user name. */
-@Qualifier
-@Retention(AnnotationRetention.RUNTIME)
-internal annotation class UserName
+/**
+ * Do not use except in Hilt generated code. Internal interface for application's using
+ * {@code CustomInject}.
+ */
+public interface HasCustomInject {
+ void customInject();
+}
diff --git a/java/dagger/hilt/android/internal/modules/ApplicationContextModule.java b/java/dagger/hilt/android/internal/modules/ApplicationContextModule.java
index af4ebc250..00f6e2402 100644
--- a/java/dagger/hilt/android/internal/modules/ApplicationContextModule.java
+++ b/java/dagger/hilt/android/internal/modules/ApplicationContextModule.java
@@ -21,6 +21,7 @@ import android.content.Context;
import dagger.Module;
import dagger.Provides;
import dagger.hilt.InstallIn;
+import dagger.hilt.android.internal.Contexts;
import dagger.hilt.android.qualifiers.ApplicationContext;
import dagger.hilt.components.SingletonComponent;
@@ -42,6 +43,6 @@ public final class ApplicationContextModule {
@Provides
Application provideApplication() {
- return (Application) applicationContext.getApplicationContext();
+ return Contexts.getApplication(applicationContext);
}
}
diff --git a/java/dagger/hilt/android/internal/modules/BUILD b/java/dagger/hilt/android/internal/modules/BUILD
index c1b639dda..5967743a5 100644
--- a/java/dagger/hilt/android/internal/modules/BUILD
+++ b/java/dagger/hilt/android/internal/modules/BUILD
@@ -24,6 +24,7 @@ android_library(
"//:dagger_with_compiler",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android/components",
+ "//java/dagger/hilt/android/internal",
"//java/dagger/hilt/android/qualifiers",
"@maven//:androidx_activity_activity",
"@maven//:androidx_annotation_annotation",
diff --git a/java/dagger/hilt/android/internal/testing/BUILD b/java/dagger/hilt/android/internal/testing/BUILD
index 98a273d12..899ab94c8 100644
--- a/java/dagger/hilt/android/internal/testing/BUILD
+++ b/java/dagger/hilt/android/internal/testing/BUILD
@@ -86,6 +86,7 @@ android_library(
deps = [
":test_application_component_manager",
":test_application_component_manager_holder",
+ "//java/dagger/hilt/android/internal",
"//java/dagger/hilt/internal:component_manager",
"//java/dagger/hilt/internal:preconditions",
"@maven//:androidx_test_core",
diff --git a/java/dagger/hilt/android/internal/testing/EarlySingletonComponentCreator.java b/java/dagger/hilt/android/internal/testing/EarlySingletonComponentCreator.java
index 8e61e4aff..1dbb73ab1 100644
--- a/java/dagger/hilt/android/internal/testing/EarlySingletonComponentCreator.java
+++ b/java/dagger/hilt/android/internal/testing/EarlySingletonComponentCreator.java
@@ -23,6 +23,11 @@ public abstract class EarlySingletonComponentCreator {
private static final String EARLY_SINGLETON_COMPONENT_CREATOR_IMPL =
"dagger.hilt.android.internal.testing.EarlySingletonComponentCreatorImpl";
+ private static final String ERROR_MSG =
+ "The EarlyComponent was requested but does not exist. Check that you have annotated "
+ + "your test class with @HiltAndroidTest and that the processor is running over your "
+ + "test.";
+
static Object createComponent() {
try {
return Class.forName(EARLY_SINGLETON_COMPONENT_CREATOR_IMPL)
@@ -30,16 +35,19 @@ public abstract class EarlySingletonComponentCreator {
.getDeclaredConstructor()
.newInstance()
.create();
- } catch (ClassNotFoundException
- | NoSuchMethodException
- | IllegalAccessException
- | InstantiationException
- | InvocationTargetException e) {
- throw new RuntimeException(
- "The EarlyComponent was requested but does not exist. Check that you have annotated "
- + "your test class with @HiltAndroidTest and that the processor is running over your "
- + "test.",
- e);
+ // We catch each individual exception rather than using a multicatch because multi-catch will
+ // get compiled to the common but new super type ReflectiveOperationException, which is not
+ // allowed on API < 19. See b/187826710.
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(ERROR_MSG, e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(ERROR_MSG, e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(ERROR_MSG, e);
+ } catch (InstantiationException e) {
+ throw new RuntimeException(ERROR_MSG, e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(ERROR_MSG, e);
}
}
diff --git a/java/dagger/hilt/android/internal/testing/MarkThatRulesRanRule.java b/java/dagger/hilt/android/internal/testing/MarkThatRulesRanRule.java
index 17c40b308..192d30ae3 100644
--- a/java/dagger/hilt/android/internal/testing/MarkThatRulesRanRule.java
+++ b/java/dagger/hilt/android/internal/testing/MarkThatRulesRanRule.java
@@ -19,8 +19,9 @@ package dagger.hilt.android.internal.testing;
import static dagger.hilt.internal.Preconditions.checkNotNull;
import static dagger.hilt.internal.Preconditions.checkState;
-import android.content.Context;
+import android.app.Application;
import androidx.test.core.app.ApplicationProvider;
+import dagger.hilt.android.internal.Contexts;
import dagger.hilt.internal.GeneratedComponentManager;
import java.lang.annotation.Annotation;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -38,7 +39,8 @@ public final class MarkThatRulesRanRule implements TestRule {
private static final String HILT_ANDROID_APP = "dagger.hilt.android.HiltAndroidApp";
private static final String HILT_ANDROID_TEST = "dagger.hilt.android.testing.HiltAndroidTest";
- private final Context context = ApplicationProvider.getApplicationContext();
+ private final Application application = Contexts.getApplication(
+ ApplicationProvider.getApplicationContext());
private final Object testInstance;
private final boolean autoAddModule;
@@ -52,19 +54,19 @@ public final class MarkThatRulesRanRule implements TestRule {
"Expected %s to be annotated with @HiltAndroidTest.",
testInstance.getClass().getName());
checkState(
- context instanceof GeneratedComponentManager,
+ application instanceof GeneratedComponentManager,
"Hilt test, %s, must use a Hilt test application but found %s. To fix, configure the test "
+ "to use HiltTestApplication or a custom Hilt test application generated with "
+ "@CustomTestApplication.",
testInstance.getClass().getName(),
- context.getClass().getName());
+ application.getClass().getName());
checkState(
- !hasAnnotation(context, HILT_ANDROID_APP),
+ !hasAnnotation(application, HILT_ANDROID_APP),
"Hilt test, %s, cannot use a @HiltAndroidApp application but found %s. To fix, configure "
+ "the test to use HiltTestApplication or a custom Hilt test application generated "
+ "with @CustomTestApplication.",
testInstance.getClass().getName(),
- context.getClass().getName());
+ application.getClass().getName());
}
public void delayComponentReady() {
@@ -114,10 +116,11 @@ public final class MarkThatRulesRanRule implements TestRule {
private TestApplicationComponentManager getTestApplicationComponentManager() {
checkState(
- context instanceof TestApplicationComponentManagerHolder,
- "The context is not an instance of TestApplicationComponentManagerHolder: %s",
- context);
- Object componentManager = ((TestApplicationComponentManagerHolder) context).componentManager();
+ application instanceof TestApplicationComponentManagerHolder,
+ "The application is not an instance of TestApplicationComponentManagerHolder: %s",
+ application);
+ Object componentManager =
+ ((TestApplicationComponentManagerHolder) application).componentManager();
checkState(
componentManager instanceof TestApplicationComponentManager,
"Expected TestApplicationComponentManagerHolder to return an instance of"
diff --git a/java/dagger/hilt/android/internal/testing/TestApplicationComponentManager.java b/java/dagger/hilt/android/internal/testing/TestApplicationComponentManager.java
index c2051170d..9d08db72d 100644
--- a/java/dagger/hilt/android/internal/testing/TestApplicationComponentManager.java
+++ b/java/dagger/hilt/android/internal/testing/TestApplicationComponentManager.java
@@ -95,7 +95,7 @@ public final class TestApplicationComponentManager
if (component.get() == null) {
Preconditions.checkState(
hasHiltTestRule(),
- "The component was not created. Check that you have added the HiltAndroidRule.");
+ "The component was not created. Check that you have added the HiltAndroidRule.");
if (!registeredModules.keySet().containsAll(requiredModules())) {
Set<Class<?>> difference = new HashSet<>(requiredModules());
difference.removeAll(registeredModules.keySet());
@@ -284,8 +284,8 @@ public final class TestApplicationComponentManager
void setAutoAddModule(boolean autoAddModule) {
Preconditions.checkState(
- autoAddModuleEnabled.get() == null, "autoAddModuleEnabled is already set!");
- autoAddModuleEnabled.set(autoAddModule);
+ autoAddModuleEnabled.compareAndSet(null, autoAddModule),
+ "autoAddModuleEnabled is already set!");
}
private Set<Class<?>> requiredModules() {
@@ -318,9 +318,7 @@ public final class TestApplicationComponentManager
}
private Class<?> testClass() {
- Preconditions.checkState(
- hasHiltTestRule(),
- "Test must have an HiltAndroidRule.");
+ Preconditions.checkState(hasHiltTestRule(), "Test must have a HiltAndroidRule.");
return hasHiltTestRule.get().getTestClass();
}
diff --git a/java/dagger/hilt/android/internal/testing/TestComponentDataSupplier.java b/java/dagger/hilt/android/internal/testing/TestComponentDataSupplier.java
index b6f8b0b45..b1234ddb0 100644
--- a/java/dagger/hilt/android/internal/testing/TestComponentDataSupplier.java
+++ b/java/dagger/hilt/android/internal/testing/TestComponentDataSupplier.java
@@ -32,22 +32,31 @@ public abstract class TestComponentDataSupplier {
.getDeclaredConstructor()
.newInstance()
.get();
- } catch (ClassNotFoundException
- | NoSuchMethodException
- | IllegalAccessException
- | InstantiationException
- | InvocationTargetException e) {
- throw new RuntimeException(
- String.format(
- "Hilt test, %s, is missing generated file: %s. Check that the test class is "
- + " annotated with @HiltAndroidTest and that the processor is running over your"
- + " test.",
- testClass.getSimpleName(),
- generatedClassName),
- e);
+ // We catch each individual exception rather than using a multicatch because multi-catch will
+ // get compiled to the common but new super type ReflectiveOperationException, which is not
+ // allowed on API < 19. See b/187826710.
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(errorMessage(testClass, generatedClassName), e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(errorMessage(testClass, generatedClassName), e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(errorMessage(testClass, generatedClassName), e);
+ } catch (InstantiationException e) {
+ throw new RuntimeException(errorMessage(testClass, generatedClassName), e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(errorMessage(testClass, generatedClassName), e);
}
}
+ private static String errorMessage(Class<?> testClass, String generatedClassName) {
+ return String.format(
+ "Hilt test, %s, is missing generated file: %s. Check that the test class is "
+ + " annotated with @HiltAndroidTest and that the processor is running over your"
+ + " test.",
+ testClass.getSimpleName(),
+ generatedClassName);
+ }
+
private static String getEnclosedClassName(Class<?> testClass) {
StringBuilder sb = new StringBuilder();
Class<?> currClass = testClass;
diff --git a/java/dagger/hilt/android/lifecycle/proguard-rules.pro b/java/dagger/hilt/android/lifecycle/proguard-rules.pro
index edd3d3d79..6c647f105 100644
--- a/java/dagger/hilt/android/lifecycle/proguard-rules.pro
+++ b/java/dagger/hilt/android/lifecycle/proguard-rules.pro
@@ -1,2 +1,2 @@
# Keep class names of Hilt injected ViewModels since their name are used as a multibinding map key.
--keepnames @dagger.hilt.android.lifecycle.HiltViewModel class * extends androidx.lifecycle.ViewModel
+-keepnames @dagger.hilt.android.lifecycle.HiltViewModel class * extends androidx.lifecycle.ViewModel \ No newline at end of file
diff --git a/java/dagger/hilt/android/migration/BUILD b/java/dagger/hilt/android/migration/BUILD
index a42f0ac65..3694560b6 100644
--- a/java/dagger/hilt/android/migration/BUILD
+++ b/java/dagger/hilt/android/migration/BUILD
@@ -39,11 +39,28 @@ android_library(
],
)
+android_library(
+ name = "custom_inject",
+ srcs = [
+ "CustomInject.java",
+ "CustomInjection.java",
+ ],
+ exports = [
+ "//java/dagger/hilt/android/internal/migration:has_custom_inject",
+ ],
+ deps = [
+ ":package_info",
+ "//java/dagger/hilt/android/internal/migration:has_custom_inject",
+ "//java/dagger/hilt/internal:preconditions",
+ "@maven//:androidx_annotation_annotation",
+ ],
+)
+
java_library(
name = "package_info",
srcs = ["package-info.java"],
deps = [
- "@google_bazel_common//third_party/java/jsr305_annotations",
+ "//third_party/java/jsr305_annotations",
],
)
diff --git a/java/dagger/hilt/android/migration/CustomInject.java b/java/dagger/hilt/android/migration/CustomInject.java
new file mode 100644
index 000000000..e142609bb
--- /dev/null
+++ b/java/dagger/hilt/android/migration/CustomInject.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.migration;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * When used on a {@link dagger.hilt.android.HiltAndroidApp}-annotated application, this causes the
+ * application to no longer inject itself in onCreate and instead allows it to be injected at some
+ * other time.
+ *
+ * <p>When using this annotation, you can use {@link CustomInjection#inject} to inject the
+ * application class. Additionally, this annotation will also cause a method, {@code customInject}
+ * to be generated in the Hilt base class as well, that behaves the same as
+ * {@link CustomInjection#inject}. The method is available to users that extend the Hilt base class
+ * directly and don't use the Gradle plugin.
+ *
+ * <p> Example usage:
+ *
+ * <pre><code>
+ * {@literal @}CustomInject
+ * {@literal @}HiltAndroidApp(Application.class)
+ * public final class MyApplication extends Hilt_MyApplication {
+ *
+ * {@literal @}Inject Foo foo;
+ *
+ * {@literal @}Override
+ * public void onCreate() {
+ * // Injection would normally happen in this super.onCreate() call, but won't now because this
+ * // is using CustomInject.
+ * super.onCreate();
+ * doSomethingBeforeInjection();
+ * // This call now injects the fields in the Application, like the foo field above.
+ * CustomInject.inject(this);
+ * }
+ * }
+ * </code></pre>
+ */
+@Target(ElementType.TYPE)
+public @interface CustomInject {}
diff --git a/java/dagger/hilt/android/migration/CustomInjection.java b/java/dagger/hilt/android/migration/CustomInjection.java
new file mode 100644
index 000000000..e3d7a0c7d
--- /dev/null
+++ b/java/dagger/hilt/android/migration/CustomInjection.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.migration;
+
+import android.app.Application;
+import androidx.annotation.NonNull;
+import dagger.hilt.android.internal.migration.HasCustomInject;
+import dagger.hilt.internal.Preconditions;
+
+/**
+ * Utility methods for injecting the application when using {@link CustomInject}.
+ *
+ * @see OptionalInject
+ */
+public final class CustomInjection {
+
+ /** Injects the passed in application. */
+ public static void inject(@NonNull Application app) {
+ Preconditions.checkNotNull(app);
+ Preconditions.checkArgument(
+ app instanceof HasCustomInject,
+ "'%s' is not a custom inject application. Check that you have annotated"
+ + " the application with both @HiltAndroidApp and @CustomInject.",
+ app.getClass());
+ ((HasCustomInject) app).customInject();
+ }
+
+ private CustomInjection() {}
+}
diff --git a/java/dagger/hilt/android/migration/OptionalInjectCheck.java b/java/dagger/hilt/android/migration/OptionalInjectCheck.java
index f9d0ad8f2..6c6d30bfd 100644
--- a/java/dagger/hilt/android/migration/OptionalInjectCheck.java
+++ b/java/dagger/hilt/android/migration/OptionalInjectCheck.java
@@ -18,10 +18,10 @@ package dagger.hilt.android.migration;
import android.app.Service;
import android.content.BroadcastReceiver;
-import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.view.View;
import androidx.activity.ComponentActivity;
+import androidx.annotation.NonNull;
import dagger.hilt.android.internal.migration.InjectedByHilt;
import dagger.hilt.internal.Preconditions;
diff --git a/java/dagger/hilt/android/plugin/BUILD b/java/dagger/hilt/android/plugin/BUILD
index 7fd2c8377..ef68b63d2 100644
--- a/java/dagger/hilt/android/plugin/BUILD
+++ b/java/dagger/hilt/android/plugin/BUILD
@@ -17,6 +17,14 @@
package(default_visibility = ["//:src"])
+genrule(
+ name = "import-shared-lib",
+ srcs = ["//java/dagger/hilt/processor/internal/root/ir"],
+ outs = ["processor-shared-lib.jar"],
+ cmd = "find $(SRCS) -type f -name '*.jar' -exec cp {} $@ \\;",
+ local = True,
+)
+
filegroup(
name = "srcs_filegroup",
srcs = glob(
diff --git a/java/dagger/hilt/android/plugin/build.gradle b/java/dagger/hilt/android/plugin/build.gradle
index 480c6f0a4..c481c41ac 100644
--- a/java/dagger/hilt/android/plugin/build.gradle
+++ b/java/dagger/hilt/android/plugin/build.gradle
@@ -15,45 +15,70 @@
*/
buildscript {
+ ext {
+ kotlin_version = "1.5.32"
+ agp_version = System.getenv('AGP_VERSION') ?: "7.2.0-alpha06"
+ pluginArtifactId = 'hilt-android-gradle-plugin'
+ pluginId = 'com.google.dagger.hilt.android'
+ }
repositories {
google()
mavenCentral()
- jcenter()
}
}
plugins {
- id 'org.jetbrains.kotlin.jvm' version '1.4.20'
+ id 'org.jetbrains.kotlin.jvm' version "$kotlin_version"
id 'java-gradle-plugin'
id 'maven-publish'
+ // Use shadow version >= 7.1.1 to get log4j vulnerability patches:
+ // https://github.com/johnrengelman/shadow/releases/tag/7.1.1
+ id 'com.github.johnrengelman.shadow' version '7.1.1'
}
repositories {
google()
mavenCentral()
- jcenter()
}
configurations {
- additionalTestPlugin {
+ // Config for dependencies that will be shadowed / jarjared
+ shadowed
+ // Make all shadowed dependencies be compileOnly dependencies to not affect
+ // main compilation / configuration
+ compileOnly.extendsFrom(shadowed)
+ // Make all shadowed dependencies be included in the plugin test classpath
+ // since they are compileOnly in the main configuration
+ testPluginCompile.extendsFrom(shadowed)
+ // Config for plugin classpath to be used during tests
+ testPluginCompile {
canBeConsumed = false
canBeResolved = true
- extendsFrom implementation
}
}
+// Renames default jar to avoid using it in publications.
+jar {
+ archiveClassifier = "before-jarjar"
+}
+shadowJar {
+ archiveClassifier = ""
+ configurations = [project.configurations.shadowed]
+}
+
dependencies {
+ shadowed fileTree(dir: 'libs', include: '*.jar')
implementation gradleApi()
- compileOnly 'com.android.tools.build:gradle:4.2.0-beta04'
- // TODO(danysantiago): Make compileOnly to avoid dep for non-Kotlin projects.
- implementation 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.20'
+ compileOnly "com.android.tools.build:gradle:$agp_version"
+ compileOnly "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
implementation 'org.javassist:javassist:3.26.0-GA'
implementation 'org.ow2.asm:asm:9.0'
+ implementation "com.squareup:javapoet:1.13.0"
testImplementation gradleTestKit()
testImplementation 'junit:junit:4.12'
testImplementation 'com.google.truth:truth:1.0.1'
- additionalTestPlugin 'com.android.tools.build:gradle:4.2.0-beta04'
+ testPluginCompile 'com.android.tools.build:gradle:4.2.0'
}
// Configure the generating task of plugin-under-test-metadata.properties to
@@ -61,21 +86,91 @@ dependencies {
// are not present in the main runtime dependencies. This allows us to test
// the desired AGP version while keeping a compileOnly dep on the main source.
tasks.withType(PluginUnderTestMetadata.class).named("pluginUnderTestMetadata").configure {
- it.pluginClasspath.from(configurations.additionalTestPlugin)
+ it.pluginClasspath.from(configurations.testPluginCompile)
}
compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
+ allWarningsAsErrors = true
+ }
+}
+
+java {
+ sourceCompatibility = "1.8"
+ targetCompatibility = "1.8"
+}
+
+// Imports a shared library from the main project. The library and its classes
+// will be shadowed in the plugin's artifact.
+tasks.register("importSharedLib").configure {
+ def outputDir = file("${project.projectDir}/libs")
+ outputs.dir(outputDir)
+ doLast {
+ def buildCmd = 'bazel'
+ def buildDir = 'bazel-bin'
+ def findGenFilesParent
+ findGenFilesParent = { File dir ->
+ if (dir == null || !dir.isDirectory()) {
+ return null
+ }
+ if (new File(dir, buildDir).exists()) {
+ return dir
+ } else {
+ return findGenFilesParent(dir.parentFile)
+ }
+ }
+ // Build shared lib
+ def bazelOutput = new ByteArrayOutputStream()
+ def buildResult = exec {
+ commandLine buildCmd, 'build', 'import-shared-lib'
+ standardOutput = bazelOutput
+ errorOutput = bazelOutput
+ }
+ buildResult.assertNormalExitValue()
+ // Find shared lib Jar in build directory.
+ def genFilesDir = findGenFilesParent(project.buildFile.parentFile)
+ if (genFilesDir == null) {
+ throw new GradleException("Couldn't find build folder '$buildDir'")
+ }
+ def libPath = bazelOutput.toString().split('\n')
+ .find { line -> line.contains("$buildDir/") }.trim()
+ def inputFile = file("$genFilesDir/$libPath")
+ def outputFile = file("$outputDir/${inputFile.name}")
+ outputFile << inputFile.newInputStream()
+ }
+}
+tasks.getByName('compileKotlin').dependsOn('importSharedLib')
+
+// Task that generates a top-level property containing the version of the
+// project so that it can be used in code and at runtime.
+def pluginVersionOutDir = file("$buildDir/generated/source/plugin-version/")
+tasks.register("generatePluginVersionSource").configure {
+ def version = getPublishVersion()
+ inputs.property('version', version)
+ outputs.dir(pluginVersionOutDir)
+ doLast {
+ def versionFile =
+ file("$pluginVersionOutDir/dagger/hilt/android/plugin/Version.kt")
+ versionFile.parentFile.mkdirs()
+ versionFile.text = """
+ // Generated file. Do not edit!
+ package dagger.hilt.android.plugin
+
+ val HILT_VERSION = "${version}"
+ """.stripIndent()
}
}
+sourceSets.main.java.srcDir pluginVersionOutDir
+tasks.getByName('compileKotlin').dependsOn('generatePluginVersionSource')
// Create sources Jar from main kotlin sources
tasks.register("sourcesJar", Jar).configure {
group = JavaBasePlugin.DOCUMENTATION_GROUP
description = "Assembles sources JAR"
- classifier = "sources"
+ archiveClassifier.set("sources")
from(sourceSets["main"].allSource)
+ dependsOn('generatePluginVersionSource')
}
// Create javadoc Jar. The jar is empty since we don't really have docs
@@ -84,7 +179,7 @@ tasks.register("sourcesJar", Jar).configure {
tasks.register("javadocJar", Jar).configure {
group = JavaBasePlugin.DOCUMENTATION_GROUP
description = "Assembles javadoc JAR"
- classifier = "javadoc"
+ archiveClassifier.set("javadoc")
}
// Disable Gradle metadata publication.
@@ -96,53 +191,29 @@ tasks.withType(GenerateModuleMetadata) {
publishing {
publications {
plugin(MavenPublication) {
- artifactId = 'hilt-android-gradle-plugin'
- def publishVersion = findProperty("PublishVersion")
- version = (publishVersion != null) ? publishVersion : "LOCAL-SNAPSHOT"
+ artifactId = pluginArtifactId
+ version = getPublishVersion()
from components.kotlin
+ artifact(shadowJar)
artifact(sourcesJar)
artifact(javadocJar)
pom {
- name = 'Hilt Android Gradle Plugin'
- description = 'A fast dependency injector for Android and Java.'
- url = 'https://github.com/google/dagger'
- scm {
- url = 'https://github.com/google/dagger/'
- connection = 'scm:git:git://github.com/google/dagger.git'
- developerConnection = 'scm:git:ssh://git@github.com/google/dagger.git'
- tag = 'HEAD'
- }
- issueManagement {
- system = 'GitHub Issues'
- url = 'https://github.com/google/dagger/issues'
- }
- licenses {
- license {
- name = 'Apache 2.0'
- url = 'https://www.apache.org/licenses/LICENSE-2.0.txt'
- }
- }
- organization {
- name = 'Google, Inc.'
- url = 'https://www.google.com'
- }
+ addPomTemplate(owner)
+ }
+ }
+ // https://docs.gradle.org/current/userguide/plugins.html#sec:plugin_markers
+ pluginMarker(MavenPublication) {
+ groupId = pluginId
+ artifactId = "${pluginId}.gradle.plugin"
+ version = getPublishVersion()
+ pom {
+ addPomTemplate(owner)
withXml {
- def projectNode = asNode()
- // Adds:
- // <parent>
- // <groupId>org.sonatype.oss</groupId>
- // <artifactId>oss-parent</artifactId>
- // <version>7</version>
- // </parent>
- def parentNode = projectNode.appendNode('parent')
- parentNode.appendNode('groupId', 'org.sonatype.oss')
- parentNode.appendNode('artifactId', 'oss-parent')
- parentNode.appendNode('version', '7')
- // Adds scm->tag because for some reason the DSL API does not.
- // <scm>
- // <tag>HEAD</tag>
- // </scm>
- projectNode.get('scm').first().appendNode('tag', 'HEAD')
+ def dependencyNode =
+ asNode().appendNode("dependencies").appendNode("dependency")
+ dependencyNode.appendNode("groupId", group)
+ dependencyNode.appendNode("artifactId", pluginArtifactId)
+ dependencyNode.appendNode("version", getPublishVersion())
}
}
}
@@ -155,4 +226,54 @@ publishing {
}
}
-group='com.google.dagger'
+group = 'com.google.dagger'
+
+// TODO(danysantiago): Use POM template in tools/ to avoid duplicating lines.
+def addPomTemplate(pom) {
+ pom.name = 'Hilt Android Gradle Plugin'
+ pom.description = 'A fast dependency injector for Android and Java.'
+ pom.url = 'https://github.com/google/dagger'
+ pom.scm {
+ url = 'https://github.com/google/dagger/'
+ connection = 'scm:git:git://github.com/google/dagger.git'
+ developerConnection = 'scm:git:ssh://git@github.com/google/dagger.git'
+ tag = 'HEAD'
+ }
+ pom.issueManagement {
+ system = 'GitHub Issues'
+ url = 'https://github.com/google/dagger/issues'
+ }
+ pom.licenses {
+ license {
+ name = 'Apache 2.0'
+ url = 'https://www.apache.org/licenses/LICENSE-2.0.txt'
+ }
+ }
+ pom.organization {
+ name = 'Google, Inc.'
+ url = 'https://www.google.com'
+ }
+ pom.withXml {
+ def projectNode = asNode()
+ // Adds:
+ // <parent>
+ // <groupId>org.sonatype.oss</groupId>
+ // <artifactId>oss-parent</artifactId>
+ // <version>7</version>
+ // </parent>
+ def parentNode = projectNode.appendNode('parent')
+ parentNode.appendNode('groupId', 'org.sonatype.oss')
+ parentNode.appendNode('artifactId', 'oss-parent')
+ parentNode.appendNode('version', '7')
+ // Adds scm->tag because for some reason the DSL API does not.
+ // <scm>
+ // <tag>HEAD</tag>
+ // </scm>
+ projectNode.get('scm').first().appendNode('tag', 'HEAD')
+ }
+}
+
+def getPublishVersion() {
+ def publishVersion = findProperty("PublishVersion")
+ return (publishVersion != null) ? publishVersion : "LOCAL-SNAPSHOT"
+}
diff --git a/java/dagger/hilt/android/plugin/gradle/wrapper/gradle-wrapper.properties b/java/dagger/hilt/android/plugin/gradle/wrapper/gradle-wrapper.properties
index 4d9ca1649..ffed3a254 100644
--- a/java/dagger/hilt/android/plugin/gradle/wrapper/gradle-wrapper.properties
+++ b/java/dagger/hilt/android/plugin/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassTransformer.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassTransformer.kt
index 3bbf1e190..e9f667f3c 100644
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassTransformer.kt
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassTransformer.kt
@@ -189,6 +189,12 @@ internal class AndroidEntryPointClassTransformer(
if (currentClassRef != oldSuperclassName) {
return@forEachInstruction
}
+ // If the method reference of the instruction is a constructor, then we should not
+ // rewrite it since its an instantiation and not a `super()` call.
+ val methodRefName = constantPool.getMethodrefName(methodRef)
+ if (methodRefName == "<init>") {
+ return@forEachInstruction
+ }
val nameAndTypeRef = constantPool.getMethodrefNameAndType(methodRef)
val newSuperclassRef = constantPool.addClassInfo(newSuperclassName)
val newMethodRef = constantPool.addMethodrefInfo(newSuperclassRef, nameAndTypeRef)
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassVisitor.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassVisitor.kt
index 015bb7623..fec331817 100644
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassVisitor.kt
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassVisitor.kt
@@ -6,7 +6,7 @@ import com.android.build.api.instrumentation.ClassData
import com.android.build.api.instrumentation.InstrumentationParameters
import java.io.File
import org.gradle.api.provider.Property
-import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.Internal
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.FieldVisitor
@@ -17,18 +17,19 @@ import org.objectweb.asm.Opcodes
* ASM Adapter that transforms @AndroidEntryPoint-annotated classes to extend the Hilt
* generated android class, including the @HiltAndroidApp application class.
*/
-@Suppress("UnstableApiUsage")
class AndroidEntryPointClassVisitor(
private val apiVersion: Int,
nextClassVisitor: ClassVisitor,
private val additionalClasses: File
) : ClassVisitor(apiVersion, nextClassVisitor) {
+ @Suppress("UnstableApiUsage") // ASM Pipeline APIs
interface AndroidEntryPointParams : InstrumentationParameters {
- @get:Input
+ @get:Internal
val additionalClassesDir: Property<File>
}
+ @Suppress("UnstableApiUsage") // ASM Pipeline APIs
abstract class Factory : AsmClassVisitorFactory<AndroidEntryPointParams> {
override fun createClassVisitor(
classContext: ClassContext,
@@ -69,7 +70,8 @@ class AndroidEntryPointClassVisitor(
newSuperclassName =
packageName + "/Hilt_" + className.replace("$", "_")
oldSuperclassName = superName ?: error { "Superclass of $name is null!" }
- super.visit(version, access, name, signature, newSuperclassName, interfaces)
+ val newSignature = signature?.replaceFirst(oldSuperclassName, newSuperclassName)
+ super.visit(version, access, name, newSignature, newSuperclassName, interfaces)
}
override fun visitMethod(
@@ -80,7 +82,11 @@ class AndroidEntryPointClassVisitor(
exceptions: Array<out String>?
): MethodVisitor {
val nextMethodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions)
- val invokeSpecialVisitor = InvokeSpecialAdapter(apiVersion, nextMethodVisitor)
+ val invokeSpecialVisitor = InvokeSpecialAdapter(
+ apiVersion = apiVersion,
+ nextClassVisitor = nextMethodVisitor,
+ isConstructor = name == "<init>"
+ )
if (name == ON_RECEIVE_METHOD_NAME &&
descriptor == ON_RECEIVE_METHOD_DESCRIPTOR &&
hasOnReceiveBytecodeInjectionMarker()
@@ -104,16 +110,22 @@ class AndroidEntryPointClassVisitor(
* However, it has been observed that on APIs 19 to 22 the Android Runtime (ART) jumps over the
* direct superclass and into the method reference class, causing unexpected behaviours.
* Therefore, this method performs the additional transformation to rewrite direct super call
- * invocations to use a method reference whose class in the pool is the new superclass. Note that
- * this is not necessary for constructor calls since the Javassist library takes care of those.
+ * invocations to use a method reference whose class in the pool is the new superclass.
*
* @see: https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html#jvms-6.5.invokespecial
* @see: https://source.android.com/devices/tech/dalvik/dalvik-bytecode
*/
inner class InvokeSpecialAdapter(
apiVersion: Int,
- nextClassVisitor: MethodVisitor
+ nextClassVisitor: MethodVisitor,
+ private val isConstructor: Boolean
) : MethodVisitor(apiVersion, nextClassVisitor) {
+
+ // Flag to know that we have visited the first invokespecial instruction in a constructor call
+ // which corresponds to the `super()` constructor call required as the first statement of an
+ // overridden constructor body.
+ private var visitedSuperConstructorInvokeSpecial = false
+
override fun visitMethodInsn(
opcode: Int,
owner: String,
@@ -122,13 +134,29 @@ class AndroidEntryPointClassVisitor(
isInterface: Boolean
) {
if (opcode == Opcodes.INVOKESPECIAL && owner == oldSuperclassName) {
- // Update the owner of all INVOKESPECIAL instructions, including those found in
- // constructors.
- super.visitMethodInsn(opcode, newSuperclassName, name, descriptor, isInterface)
+ // Update the owner of INVOKESPECIAL instructions, including those found in constructors.
+ super.visitMethodInsn(opcode, getAdaptedOwner(name) ?: owner, name, descriptor, isInterface)
} else {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
}
}
+
+ // Gets the updated owner of an INVOKESPECIAL found in the method being visited.
+ private fun getAdaptedOwner(methodRefName: String): String? {
+ // If the method reference is a constructor and we are visiting a constructor then only the
+ // first INVOKESPECIAL instruction found should be transformed since that correponds to the
+ // super constructor call.
+ if (methodRefName == "<init>" && isConstructor && !visitedSuperConstructorInvokeSpecial) {
+ visitedSuperConstructorInvokeSpecial = true
+ return newSuperclassName
+ }
+ // If the method reference is not a constructor then the instruction for a super call that
+ // should be transformed.
+ if (methodRefName != "<init>") {
+ return newSuperclassName
+ }
+ return null
+ }
}
/**
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointTransform.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointTransform.kt
index 9bb5160b6..c9c6708b6 100644
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointTransform.kt
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointTransform.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:Suppress("DEPRECATION") // com.android.build.api.transform is deprecated
+
package dagger.hilt.android.plugin
import com.android.build.api.transform.DirectoryInput
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltExtension.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltExtension.kt
index 7a33836dc..bbfe2926f 100644
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltExtension.kt
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltExtension.kt
@@ -15,9 +15,7 @@
*/
package dagger.hilt.android.plugin
-/**
- * Configuration options for the Hilt Gradle Plugin
- */
+/** Configuration options for the Hilt Gradle Plugin */
interface HiltExtension {
/**
@@ -42,9 +40,28 @@ interface HiltExtension {
* deprecated in a future version.
*/
var enableTransformForLocalTests: Boolean
+
+ /**
+ * If set to `true`, Hilt will perform module and entry points aggregation in a task instead of an
+ * aggregating annotation processor. Enabling this flag improves incremental build times.
+ *
+ * When this flag is enabled, 'enableExperimentalClasspathAggregation' has no effect since
+ * classpath aggregation will be done by default.
+ */
+ var enableAggregatingTask: Boolean
+
+ /**
+ * If set to `true`, Hilt will disable cross compilation root validation.
+ *
+ * See [documentation](https://dagger.dev/hilt/flags#disable-cross-compilation-root-validation)
+ * for more information.
+ */
+ var disableCrossCompilationRootValidation: Boolean
}
internal open class HiltExtensionImpl : HiltExtension {
override var enableExperimentalClasspathAggregation: Boolean = false
override var enableTransformForLocalTests: Boolean = false
+ override var enableAggregatingTask: Boolean = true
+ override var disableCrossCompilationRootValidation: Boolean = false
}
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt
index a82826ed8..d872d66a3 100644
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt
@@ -16,8 +16,8 @@
package dagger.hilt.android.plugin
-import com.android.build.api.component.Component
-import com.android.build.api.extension.AndroidComponentsExtension
+import com.android.build.api.attributes.BuildTypeAttr
+import com.android.build.api.attributes.ProductFlavorAttr
import com.android.build.api.instrumentation.FramesComputationMode
import com.android.build.api.instrumentation.InstrumentationScope
import com.android.build.gradle.AppExtension
@@ -26,18 +26,26 @@ import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.TestExtension
import com.android.build.gradle.TestedExtension
import com.android.build.gradle.api.AndroidBasePlugin
-import com.android.build.gradle.api.BaseVariant
-import com.android.build.gradle.api.TestVariant
-import com.android.build.gradle.api.UnitTestVariant
+import dagger.hilt.android.plugin.task.AggregateDepsTask
+import dagger.hilt.android.plugin.task.HiltTransformTestClassesTask
+import dagger.hilt.android.plugin.util.AggregatedPackagesTransform
+import dagger.hilt.android.plugin.util.AndroidComponentsExtensionCompat.Companion.getAndroidComponentsExtension
+import dagger.hilt.android.plugin.util.ComponentCompat
import dagger.hilt.android.plugin.util.CopyTransform
import dagger.hilt.android.plugin.util.SimpleAGPVersion
+import dagger.hilt.android.plugin.util.capitalize
+import dagger.hilt.android.plugin.util.getSdkPath
import java.io.File
import javax.inject.Inject
+import org.gradle.api.JavaVersion
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
import org.gradle.api.attributes.Attribute
+import org.gradle.api.attributes.Usage
import org.gradle.api.provider.ProviderFactory
+import org.gradle.api.tasks.compile.JavaCompile
+import org.gradle.process.CommandLineArgumentProvider
/**
* A Gradle plugin that checks if the project is an Android project and if so, registers a
@@ -70,82 +78,92 @@ class HiltGradlePlugin @Inject constructor(
val hiltExtension = project.extensions.create(
HiltExtension::class.java, "hilt", HiltExtensionImpl::class.java
)
+ configureDependencyTransforms(project)
configureCompileClasspath(project, hiltExtension)
if (SimpleAGPVersion.ANDROID_GRADLE_PLUGIN_VERSION < SimpleAGPVersion(4, 2)) {
// Configures bytecode transform using older APIs pre AGP 4.2
- configureTransform(project, hiltExtension)
+ configureBytecodeTransform(project, hiltExtension)
} else {
// Configures bytecode transform using AGP 4.2 ASM pipeline.
- configureTransformASM(project, hiltExtension)
+ configureBytecodeTransformASM(project, hiltExtension)
+ }
+ configureAggregatingTask(project, hiltExtension)
+ configureProcessorFlags(project, hiltExtension)
+ }
+
+ // Configures Gradle dependency transforms.
+ private fun configureDependencyTransforms(project: Project) = project.dependencies.apply {
+ registerTransform(CopyTransform::class.java) { spec ->
+ // Java/Kotlin library projects offer an artifact of type 'jar'.
+ spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, "jar")
+ // Android library projects (with or without Kotlin) offer an artifact of type
+ // 'processed-jar', which AGP can offer as a jar.
+ spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, "processed-jar")
+ spec.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, DAGGER_ARTIFACT_TYPE_VALUE)
+ }
+ registerTransform(CopyTransform::class.java) { spec ->
+ // File Collection dependencies might be an artifact of type 'directory', e.g. when
+ // adding as a dep the destination directory of the JavaCompile task.
+ spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, "directory")
+ spec.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, DAGGER_ARTIFACT_TYPE_VALUE)
+ }
+ registerTransform(AggregatedPackagesTransform::class.java) { spec ->
+ spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, DAGGER_ARTIFACT_TYPE_VALUE)
+ spec.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, AGGREGATED_HILT_ARTIFACT_TYPE_VALUE)
}
- configureProcessorFlags(project)
}
private fun configureCompileClasspath(project: Project, hiltExtension: HiltExtension) {
val androidExtension = project.extensions.findByType(BaseExtension::class.java)
?: throw error("Android BaseExtension not found.")
- when (androidExtension) {
+ androidExtension.forEachRootVariant { variant ->
+ configureVariantCompileClasspath(project, hiltExtension, androidExtension, variant)
+ }
+ }
+
+ // Invokes the [block] function for each Android variant that is considered a Hilt root, where
+ // dependencies are aggregated and components are generated.
+ private fun BaseExtension.forEachRootVariant(
+ @Suppress("DEPRECATION") block: (variant: com.android.build.gradle.api.BaseVariant) -> Unit
+ ) {
+ when (this) {
is AppExtension -> {
- // For an app project we configure the app variant and both androidTest and test variants,
- // Hilt components are generated in all of them.
- androidExtension.applicationVariants.all {
- configureVariantCompileClasspath(project, hiltExtension, androidExtension, it)
- }
- androidExtension.testVariants.all {
- configureVariantCompileClasspath(project, hiltExtension, androidExtension, it)
- }
- androidExtension.unitTestVariants.all {
- configureVariantCompileClasspath(project, hiltExtension, androidExtension, it)
- }
+ // For an app project we configure the app variant and both androidTest and unitTest
+ // variants, Hilt components are generated in all of them.
+ applicationVariants.all { block(it) }
+ testVariants.all { block(it) }
+ unitTestVariants.all { block(it) }
}
is LibraryExtension -> {
- // For a library project, only the androidTest and test variant are configured since
+ // For a library project, only the androidTest and unitTest variant are configured since
// Hilt components are not generated in a library.
- androidExtension.testVariants.all {
- configureVariantCompileClasspath(project, hiltExtension, androidExtension, it)
- }
- androidExtension.unitTestVariants.all {
- configureVariantCompileClasspath(project, hiltExtension, androidExtension, it)
- }
+ testVariants.all { block(it) }
+ unitTestVariants.all { block(it) }
}
is TestExtension -> {
- androidExtension.applicationVariants.all {
- configureVariantCompileClasspath(project, hiltExtension, androidExtension, it)
- }
- }
- else -> error(
- "Hilt plugin is unable to configure the compile classpath for project with extension " +
- "'$androidExtension'"
- )
- }
-
- project.dependencies.apply {
- registerTransform(CopyTransform::class.java) { spec ->
- // Java/Kotlin library projects offer an artifact of type 'jar'.
- spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, "jar")
- // Android library projects (with or without Kotlin) offer an artifact of type
- // 'processed-jar', which AGP can offer as a jar.
- spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, "processed-jar")
- spec.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, DAGGER_ARTIFACT_TYPE_VALUE)
+ applicationVariants.all { block(it) }
}
+ else -> error("Hilt plugin does not know how to configure '$this'")
}
}
- @Suppress("UnstableApiUsage")
private fun configureVariantCompileClasspath(
project: Project,
hiltExtension: HiltExtension,
androidExtension: BaseExtension,
- variant: BaseVariant
+ @Suppress("DEPRECATION") variant: com.android.build.gradle.api.BaseVariant
) {
- if (!hiltExtension.enableExperimentalClasspathAggregation) {
+ if (
+ !hiltExtension.enableExperimentalClasspathAggregation || hiltExtension.enableAggregatingTask
+ ) {
// Option is not enabled, don't configure compile classpath. Note that the option can't be
// checked earlier (before iterating over the variants) since it would have been too early for
// the value to be populated from the build file.
return
}
- if (androidExtension.lintOptions.isCheckReleaseBuilds &&
+ if (
+ androidExtension.lintOptions.isCheckReleaseBuilds &&
SimpleAGPVersion.ANDROID_GRADLE_PLUGIN_VERSION < SimpleAGPVersion(7, 0)
) {
// Sadly we have to ask users to disable lint when enableExperimentalClasspathAggregation is
@@ -160,19 +178,22 @@ class HiltGradlePlugin @Inject constructor(
if (
listOf(
- "android.injected.build.model.only", // Sent by AS 1.0 only
- "android.injected.build.model.only.advanced", // Sent by AS 1.1+
- "android.injected.build.model.only.versioned", // Sent by AS 2.4+
- "android.injected.build.model.feature.full.dependencies", // Sent by AS 2.4+
- "android.injected.build.model.v2", // Sent by AS 4.2+
- ).any { providers.gradleProperty(it).forUseAtConfigurationTime().isPresent }
+ "android.injected.build.model.only", // Sent by AS 1.0 only
+ "android.injected.build.model.only.advanced", // Sent by AS 1.1+
+ "android.injected.build.model.only.versioned", // Sent by AS 2.4+
+ "android.injected.build.model.feature.full.dependencies", // Sent by AS 2.4+
+ "android.injected.build.model.v2", // Sent by AS 4.2+
+ ).any {
+ providers.gradleProperty(it).forUseAtConfigurationTime().isPresent
+ }
) {
// Do not configure compile classpath when AndroidStudio is building the model (syncing)
// otherwise it will cause a freeze.
return
}
- val runtimeConfiguration = if (variant is TestVariant) {
+ @Suppress("DEPRECATION") // Older variant API is deprecated
+ val runtimeConfiguration = if (variant is com.android.build.gradle.api.TestVariant) {
// For Android test variants, the tested runtime classpath is used since the test app has
// tested dependencies removed.
variant.testedVariant.runtimeConfiguration
@@ -199,10 +220,11 @@ class HiltGradlePlugin @Inject constructor(
// debugUnitTest -> testDebugCompileOnly
// release -> releaseCompileOnly
// releaseUnitTest -> testReleaseCompileOnly
+ @Suppress("DEPRECATION") // Older variant API is deprecated
val compileOnlyConfigName = when (variant) {
- is TestVariant ->
+ is com.android.build.gradle.api.TestVariant ->
"androidTest${variant.name.substringBeforeLast("AndroidTest").capitalize()}CompileOnly"
- is UnitTestVariant ->
+ is com.android.build.gradle.api.UnitTestVariant ->
"test${variant.name.substringBeforeLast("UnitTest").capitalize()}CompileOnly"
else ->
"${variant.name}CompileOnly"
@@ -210,10 +232,10 @@ class HiltGradlePlugin @Inject constructor(
project.dependencies.add(compileOnlyConfigName, artifactView.files)
}
- @Suppress("UnstableApiUsage")
- private fun configureTransformASM(project: Project, hiltExtension: HiltExtension) {
+ @Suppress("UnstableApiUsage") // ASM Pipeline APIs
+ private fun configureBytecodeTransformASM(project: Project, hiltExtension: HiltExtension) {
var warnAboutLocalTestsFlag = false
- fun registerTransform(androidComponent: Component) {
+ fun registerTransform(androidComponent: ComponentCompat) {
if (hiltExtension.enableTransformForLocalTests && !warnAboutLocalTestsFlag) {
project.logger.warn(
"The Hilt configuration option 'enableTransformForLocalTests' is no longer necessary " +
@@ -233,14 +255,10 @@ class HiltGradlePlugin @Inject constructor(
FramesComputationMode.COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS
)
}
-
- val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
- androidComponents.onVariants { registerTransform(it) }
- androidComponents.androidTests { registerTransform(it) }
- androidComponents.unitTests { registerTransform(it) }
+ getAndroidComponentsExtension(project).onAllVariants { registerTransform(it) }
}
- private fun configureTransform(project: Project, hiltExtension: HiltExtension) {
+ private fun configureBytecodeTransform(project: Project, hiltExtension: HiltExtension) {
val androidExtension = project.extensions.findByType(BaseExtension::class.java)
?: throw error("Android BaseExtension not found.")
androidExtension.registerTransform(AndroidEntryPointTransform())
@@ -256,17 +274,189 @@ class HiltGradlePlugin @Inject constructor(
}
}
- private fun configureProcessorFlags(project: Project) {
+ private fun configureAggregatingTask(project: Project, hiltExtension: HiltExtension) {
val androidExtension = project.extensions.findByType(BaseExtension::class.java)
?: throw error("Android BaseExtension not found.")
- // Pass annotation processor flag to disable @AndroidEntryPoint superclass validation.
- androidExtension.defaultConfig.apply {
- javaCompileOptions.apply {
- annotationProcessorOptions.apply {
- PROCESSOR_OPTIONS.forEach { (key, value) -> argument(key, value) }
+ androidExtension.forEachRootVariant { variant ->
+ configureVariantAggregatingTask(project, hiltExtension, androidExtension, variant)
+ }
+ }
+
+ private fun configureVariantAggregatingTask(
+ project: Project,
+ hiltExtension: HiltExtension,
+ androidExtension: BaseExtension,
+ @Suppress("DEPRECATION") variant: com.android.build.gradle.api.BaseVariant
+ ) {
+ if (!hiltExtension.enableAggregatingTask) {
+ // Option is not enabled, don't configure aggregating task.
+ return
+ }
+
+ val hiltCompileConfiguration = project.configurations.create(
+ "hiltCompileOnly${variant.name.capitalize()}"
+ ).apply {
+ // The runtime config of the test APK differs from the tested one.
+ @Suppress("DEPRECATION") // Older variant API is deprecated
+ if (variant is com.android.build.gradle.api.TestVariant) {
+ extendsFrom(variant.testedVariant.runtimeConfiguration)
+ }
+ extendsFrom(variant.runtimeConfiguration)
+ isCanBeConsumed = false
+ isCanBeResolved = true
+ attributes { attrContainer ->
+ attrContainer.attribute(
+ Usage.USAGE_ATTRIBUTE,
+ project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME)
+ )
+ attrContainer.attribute(
+ BuildTypeAttr.ATTRIBUTE,
+ project.objects.named(BuildTypeAttr::class.java, variant.buildType.name)
+ )
+ variant.productFlavors.forEach { flavor ->
+ attrContainer.attribute(
+ Attribute.of(flavor.dimension!!, ProductFlavorAttr::class.java),
+ project.objects.named(ProductFlavorAttr::class.java, flavor.name)
+ )
}
}
}
+ // Add the JavaCompile task classpath and output dir to the config, the task's classpath
+ // will contain:
+ // * compileOnly dependencies
+ // * KAPT and Kotlinc generated bytecode
+ // * R.jar
+ // * Tested classes if the variant is androidTest
+ project.dependencies.add(
+ hiltCompileConfiguration.name,
+ project.files(variant.javaCompileProvider.map { it.classpath })
+ )
+ project.dependencies.add(
+ hiltCompileConfiguration.name,
+ project.files(variant.javaCompileProvider.map {it.destinationDirectory.get() })
+ )
+
+ fun getInputClasspath(artifactAttributeValue: String) =
+ hiltCompileConfiguration.incoming.artifactView { view ->
+ view.attributes.attribute(ARTIFACT_TYPE_ATTRIBUTE, artifactAttributeValue)
+ }.files
+
+ val aggregatingTask = project.tasks.register(
+ "hiltAggregateDeps${variant.name.capitalize()}",
+ AggregateDepsTask::class.java
+ ) {
+ it.compileClasspath.setFrom(getInputClasspath(AGGREGATED_HILT_ARTIFACT_TYPE_VALUE))
+ it.outputDir.set(
+ project.file(project.buildDir.resolve("generated/hilt/component_trees/${variant.name}/"))
+ )
+ @Suppress("DEPRECATION") // Older variant API is deprecated
+ it.testEnvironment.set(
+ variant is com.android.build.gradle.api.TestVariant ||
+ variant is com.android.build.gradle.api.UnitTestVariant
+ )
+ it.crossCompilationRootValidationDisabled.set(
+ hiltExtension.disableCrossCompilationRootValidation
+ )
+ }
+
+ val componentClasses = project.files(
+ project.buildDir.resolve("intermediates/hilt/component_classes/${variant.name}/")
+ )
+ val componentsJavaCompileTask = project.tasks.register(
+ "hiltJavaCompile${variant.name.capitalize()}",
+ JavaCompile::class.java
+ ) { compileTask ->
+ compileTask.source = aggregatingTask.map { it.outputDir.asFileTree }.get()
+ // Configure the input classpath based on Java 9 compatibility, specifically for Java 9 the
+ // android.jar is now included in the input classpath instead of the bootstrapClasspath.
+ // See: com/android/build/gradle/tasks/JavaCompileUtils.kt
+ val mainBootstrapClasspath =
+ variant.javaCompileProvider.map { it.options.bootstrapClasspath ?: project.files() }.get()
+ if (
+ JavaVersion.current().isJava9Compatible &&
+ androidExtension.compileOptions.targetCompatibility.isJava9Compatible
+ ) {
+ compileTask.classpath =
+ getInputClasspath(DAGGER_ARTIFACT_TYPE_VALUE).plus(mainBootstrapClasspath)
+ // Copies argument providers from original task, which should contain the JdkImageInput
+ variant.javaCompileProvider.get().let { originalCompileTask ->
+ originalCompileTask.options.compilerArgumentProviders.forEach {
+ compileTask.options.compilerArgumentProviders.add(it)
+ }
+ }
+ compileTask.options.compilerArgs.add("-XDstringConcat=inline")
+ } else {
+ compileTask.classpath = getInputClasspath(DAGGER_ARTIFACT_TYPE_VALUE)
+ compileTask.options.bootstrapClasspath = mainBootstrapClasspath
+ }
+ compileTask.destinationDirectory.set(componentClasses.singleFile)
+ compileTask.options.apply {
+ annotationProcessorPath = project.configurations.create(
+ "hiltAnnotationProcessor${variant.name.capitalize()}"
+ ).also { config ->
+ // TODO: Consider finding the hilt-compiler dep from the user config and using it here.
+ project.dependencies.add(config.name, "com.google.dagger:hilt-compiler:$HILT_VERSION")
+ }
+ generatedSourceOutputDirectory.set(
+ project.file(
+ project.buildDir.resolve("generated/hilt/component_sources/${variant.name}/")
+ )
+ )
+ if (
+ JavaVersion.current().isJava8Compatible &&
+ androidExtension.compileOptions.targetCompatibility.isJava8Compatible
+ ) {
+ compilerArgs.add("-parameters")
+ }
+ compilerArgs.add("-Adagger.fastInit=enabled")
+ compilerArgs.add("-Adagger.hilt.internal.useAggregatingRootProcessor=false")
+ compilerArgs.add("-Adagger.hilt.android.internal.disableAndroidSuperclassValidation=true")
+ encoding = androidExtension.compileOptions.encoding
+ }
+ compileTask.sourceCompatibility =
+ androidExtension.compileOptions.sourceCompatibility.toString()
+ compileTask.targetCompatibility =
+ androidExtension.compileOptions.targetCompatibility.toString()
+ }
+ componentClasses.builtBy(componentsJavaCompileTask)
+
+ variant.registerPostJavacGeneratedBytecode(componentClasses)
+ }
+
+ private fun getAndroidJar(project: Project, compileSdkVersion: String) =
+ project.files(File(project.getSdkPath(), "platforms/$compileSdkVersion/android.jar"))
+
+ private fun configureProcessorFlags(project: Project, hiltExtension: HiltExtension) {
+ val androidExtension = project.extensions.findByType(BaseExtension::class.java)
+ ?: throw error("Android BaseExtension not found.")
+ androidExtension.defaultConfig.javaCompileOptions.annotationProcessorOptions.apply {
+ // Pass annotation processor flag to enable Dagger's fast-init, the best mode for Hilt.
+ argument("dagger.fastInit", "enabled")
+ // Pass annotation processor flag to disable @AndroidEntryPoint superclass validation.
+ argument("dagger.hilt.android.internal.disableAndroidSuperclassValidation", "true")
+ // Pass certain annotation processor flags via a CommandLineArgumentProvider so that plugin
+ // options defined in the extension are populated from the user's build file. Checking the
+ // option too early would make it seem like it is never set.
+ compilerArgumentProvider(
+ // Suppress due to https://docs.gradle.org/7.2/userguide/validation_problems.html#implementation_unknown
+ @Suppress("ObjectLiteralToLambda")
+ object : CommandLineArgumentProvider {
+ override fun asArguments() = mutableListOf<String>().apply {
+ // Pass annotation processor flag to disable the aggregating processor if aggregating
+ // task is enabled.
+ if (hiltExtension.enableAggregatingTask) {
+ add("-Adagger.hilt.internal.useAggregatingRootProcessor=false")
+ }
+ // Pass annotation processor flag to disable cross compilation root validation.
+ // The plugin option duplicates the processor flag because it is an input of the
+ // aggregating task.
+ if (hiltExtension.disableCrossCompilationRootValidation) {
+ add("-Adagger.hilt.disableCrossCompilationRootValidation=true")
+ }
+ }
+ }
+ )
+ }
}
private fun verifyDependencies(project: Project) {
@@ -280,7 +470,8 @@ class HiltGradlePlugin @Inject constructor(
if (!dependencies.contains(LIBRARY_GROUP to "hilt-android")) {
error(missingDepError("$LIBRARY_GROUP:hilt-android"))
}
- if (!dependencies.contains(LIBRARY_GROUP to "hilt-android-compiler") &&
+ if (
+ !dependencies.contains(LIBRARY_GROUP to "hilt-android-compiler") &&
!dependencies.contains(LIBRARY_GROUP to "hilt-compiler")
) {
error(missingDepError("$LIBRARY_GROUP:hilt-compiler"))
@@ -290,12 +481,10 @@ class HiltGradlePlugin @Inject constructor(
companion object {
val ARTIFACT_TYPE_ATTRIBUTE = Attribute.of("artifactType", String::class.java)
const val DAGGER_ARTIFACT_TYPE_VALUE = "jar-for-dagger"
+ const val AGGREGATED_HILT_ARTIFACT_TYPE_VALUE = "aggregated-jar-for-hilt"
const val LIBRARY_GROUP = "com.google.dagger"
- val PROCESSOR_OPTIONS = listOf(
- "dagger.fastInit" to "enabled",
- "dagger.hilt.android.internal.disableAndroidSuperclassValidation" to "true"
- )
+
val missingDepError: (String) -> String = { depCoordinate ->
"The Hilt Android Gradle plugin is applied but no $depCoordinate dependency was found."
}
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/AggregatedAnnotation.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/AggregatedAnnotation.kt
new file mode 100644
index 000000000..e08b6f1ae
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/AggregatedAnnotation.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.plugin.root
+
+// Annotations used for aggregating dependencies by the annotation processors.
+internal enum class AggregatedAnnotation(
+ private val descriptor: String,
+ private val aggregatedPackage: String
+) {
+ AGGREGATED_ROOT(
+ "Ldagger/hilt/internal/aggregatedroot/AggregatedRoot;",
+ "dagger/hilt/internal/aggregatedroot/codegen"
+ ),
+ PROCESSED_ROOT_SENTINEL(
+ "Ldagger/hilt/internal/processedrootsentinel/ProcessedRootSentinel;",
+ "dagger/hilt/internal/processedrootsentinel/codegen"
+ ),
+ DEFINE_COMPONENT(
+ "Ldagger/hilt/internal/definecomponent/DefineComponentClasses;",
+ "dagger/hilt/processor/internal/definecomponent/codegen"
+ ),
+ ALIAS_OF(
+ "Ldagger/hilt/internal/aliasof/AliasOfPropagatedData;",
+ "dagger/hilt/processor/internal/aliasof/codegen"
+ ),
+ AGGREGATED_DEP(
+ "Ldagger/hilt/processor/internal/aggregateddeps/AggregatedDeps;",
+ "hilt_aggregated_deps"
+ ),
+ AGGREGATED_DEP_PROXY(
+ "Ldagger/hilt/android/internal/legacy/AggregatedElementProxy;",
+ "", // Proxies share the same package name as the elements they are proxying.
+ ),
+ AGGREGATED_UNINSTALL_MODULES(
+ "Ldagger/hilt/android/internal/uninstallmodules/AggregatedUninstallModules;",
+ "dagger/hilt/android/internal/uninstallmodules/codegen"
+ ),
+ AGGREGATED_EARLY_ENTRY_POINT(
+ "Ldagger/hilt/android/internal/earlyentrypoint/AggregatedEarlyEntryPoint;",
+ "dagger/hilt/android/internal/earlyentrypoint/codegen"
+ ),
+ NONE("", "");
+
+ companion object {
+ fun fromString(str: String) = values().firstOrNull { it.descriptor == str } ?: NONE
+
+ val AGGREGATED_PACKAGES = values().map { it.aggregatedPackage }.filter { it.isNotEmpty() }
+ }
+}
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/AggregatedElementProxyGenerator.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/AggregatedElementProxyGenerator.kt
new file mode 100644
index 000000000..248976ef4
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/AggregatedElementProxyGenerator.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.plugin.root
+
+import com.squareup.javapoet.AnnotationSpec
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.JavaFile
+import com.squareup.javapoet.TypeSpec
+import dagger.hilt.processor.internal.root.ir.AggregatedElementProxyIr
+import java.io.File
+import javax.lang.model.element.Modifier
+
+internal class AggregatedElementProxyGenerator(
+ private val outputDir: File,
+) {
+
+ fun generate(aggregatedElementProxy: AggregatedElementProxyIr) {
+ val typeSpec = TypeSpec.classBuilder(aggregatedElementProxy.fqName)
+ .addAnnotation(
+ AnnotationSpec.builder(AGGREGATED_ELEMENT_PROXY_ANNOTATION)
+ .addMember("value", "\$T.class", aggregatedElementProxy.value)
+ .build()
+ )
+ .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+ .build()
+ JavaFile.builder(aggregatedElementProxy.fqName.packageName(), typeSpec)
+ .build()
+ .writeTo(outputDir)
+ }
+
+ companion object {
+ val AGGREGATED_ELEMENT_PROXY_ANNOTATION =
+ ClassName.get("dagger.hilt.android.internal.legacy", "AggregatedElementProxy")
+ }
+}
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/Aggregator.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/Aggregator.kt
new file mode 100644
index 000000000..b3cb737e6
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/Aggregator.kt
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.plugin.task
+
+import com.squareup.javapoet.ClassName
+import dagger.hilt.android.plugin.root.AggregatedAnnotation
+import dagger.hilt.android.plugin.util.forEachZipEntry
+import dagger.hilt.android.plugin.util.isClassFile
+import dagger.hilt.android.plugin.util.isJarFile
+import dagger.hilt.processor.internal.root.ir.AggregatedDepsIr
+import dagger.hilt.processor.internal.root.ir.AggregatedEarlyEntryPointIr
+import dagger.hilt.processor.internal.root.ir.AggregatedElementProxyIr
+import dagger.hilt.processor.internal.root.ir.AggregatedRootIr
+import dagger.hilt.processor.internal.root.ir.AggregatedUninstallModulesIr
+import dagger.hilt.processor.internal.root.ir.AliasOfPropagatedDataIr
+import dagger.hilt.processor.internal.root.ir.DefineComponentClassesIr
+import dagger.hilt.processor.internal.root.ir.ProcessedRootSentinelIr
+import java.io.File
+import java.io.InputStream
+import java.util.zip.ZipInputStream
+import org.objectweb.asm.AnnotationVisitor
+import org.objectweb.asm.ClassReader
+import org.objectweb.asm.ClassVisitor
+import org.objectweb.asm.Opcodes
+import org.objectweb.asm.Type
+import org.slf4j.Logger
+
+/** Aggregates Hilt dependencies. */
+internal class Aggregator private constructor(
+ private val logger: Logger,
+ private val asmApiVersion: Int,
+) {
+ private val classVisitor = AggregatedDepClassVisitor(logger, asmApiVersion)
+
+ val aggregatedRoots: Set<AggregatedRootIr>
+ get() = classVisitor.aggregatedRoots
+
+ val processedRoots: Set<ProcessedRootSentinelIr>
+ get() = classVisitor.processedRoots
+
+ val defineComponentDeps: Set<DefineComponentClassesIr>
+ get() = classVisitor.defineComponentDeps
+
+ val aliasOfDeps: Set<AliasOfPropagatedDataIr>
+ get() = classVisitor.aliasOfDeps
+
+ val aggregatedDeps: Set<AggregatedDepsIr>
+ get() = classVisitor.aggregatedDeps
+
+ val aggregatedDepProxies: Set<AggregatedElementProxyIr>
+ get() = classVisitor.aggregatedDepProxies
+
+ val allAggregatedDepProxies: Set<AggregatedElementProxyIr>
+ get() = classVisitor.allAggregatedDepProxies
+
+ val uninstallModulesDeps: Set<AggregatedUninstallModulesIr>
+ get() = classVisitor.uninstallModulesDeps
+
+ val earlyEntryPointDeps: Set<AggregatedEarlyEntryPointIr>
+ get() = classVisitor.earlyEntryPointDeps
+
+ private class AggregatedDepClassVisitor(
+ private val logger: Logger,
+ private val asmApiVersion: Int,
+ ) : ClassVisitor(asmApiVersion) {
+
+ val aggregatedRoots = mutableSetOf<AggregatedRootIr>()
+ val processedRoots = mutableSetOf<ProcessedRootSentinelIr>()
+ val defineComponentDeps = mutableSetOf<DefineComponentClassesIr>()
+ val aliasOfDeps = mutableSetOf<AliasOfPropagatedDataIr>()
+ val aggregatedDeps = mutableSetOf<AggregatedDepsIr>()
+ val aggregatedDepProxies = mutableSetOf<AggregatedElementProxyIr>()
+ val allAggregatedDepProxies = mutableSetOf<AggregatedElementProxyIr>()
+ val uninstallModulesDeps = mutableSetOf<AggregatedUninstallModulesIr>()
+ val earlyEntryPointDeps = mutableSetOf<AggregatedEarlyEntryPointIr>()
+
+ var accessCode: Int = Opcodes.ACC_PUBLIC
+ lateinit var annotatedClassName: ClassName
+
+ override fun visit(
+ version: Int,
+ access: Int,
+ name: String,
+ signature: String?,
+ superName: String?,
+ interfaces: Array<out String>?
+ ) {
+ accessCode = access
+ annotatedClassName = Type.getObjectType(name).toClassName()
+ super.visit(version, access, name, signature, superName, interfaces)
+ }
+
+ override fun visitAnnotation(descriptor: String, visible: Boolean): AnnotationVisitor? {
+ val nextAnnotationVisitor = super.visitAnnotation(descriptor, visible)
+ val aggregatedAnnotation = AggregatedAnnotation.fromString(descriptor)
+ val isHiltAnnotated = aggregatedAnnotation != AggregatedAnnotation.NONE
+ // For non-public deps, a proxy might be needed, make a note of it.
+ if (isHiltAnnotated && (accessCode and Opcodes.ACC_PUBLIC) != Opcodes.ACC_PUBLIC) {
+ allAggregatedDepProxies.add(
+ AggregatedElementProxyIr(
+ fqName = annotatedClassName.peerClass("_" + annotatedClassName.simpleName()),
+ value = annotatedClassName
+ )
+ )
+ }
+ when (aggregatedAnnotation) {
+ AggregatedAnnotation.AGGREGATED_ROOT -> {
+ return object : AnnotationVisitor(asmApiVersion, nextAnnotationVisitor) {
+ lateinit var rootClass: String
+ lateinit var originatingRootClass: String
+ lateinit var rootAnnotationClassName: Type
+
+ override fun visit(name: String, value: Any?) {
+ when (name) {
+ "root" -> rootClass = value as String
+ "originatingRoot" -> originatingRootClass = value as String
+ "rootAnnotation" -> rootAnnotationClassName = (value as Type)
+ }
+ super.visit(name, value)
+ }
+
+ override fun visitEnd() {
+ aggregatedRoots.add(
+ AggregatedRootIr(
+ fqName = annotatedClassName,
+ root = rootClass.toClassName(),
+ originatingRoot = originatingRootClass.toClassName(),
+ rootAnnotation = rootAnnotationClassName.toClassName()
+ )
+ )
+ super.visitEnd()
+ }
+ }
+ }
+ AggregatedAnnotation.PROCESSED_ROOT_SENTINEL -> {
+ return object : AnnotationVisitor(asmApiVersion, nextAnnotationVisitor) {
+ val rootClasses = mutableListOf<String>()
+
+ override fun visitArray(name: String): AnnotationVisitor? {
+ return when (name) {
+ "roots" -> visitValue { value -> rootClasses.add(value as String) }
+ else -> super.visitArray(name)
+ }
+ }
+
+ override fun visitEnd() {
+ processedRoots.add(
+ ProcessedRootSentinelIr(
+ fqName = annotatedClassName,
+ roots = rootClasses.map { it.toClassName() }
+ )
+ )
+ super.visitEnd()
+ }
+ }
+ }
+ AggregatedAnnotation.DEFINE_COMPONENT -> {
+ return object : AnnotationVisitor(asmApiVersion, nextAnnotationVisitor) {
+ lateinit var componentClass: String
+
+ override fun visit(name: String, value: Any?) {
+ when (name) {
+ "component", "builder" -> componentClass = value as String
+ }
+ super.visit(name, value)
+ }
+
+ override fun visitEnd() {
+ defineComponentDeps.add(
+ DefineComponentClassesIr(
+ fqName = annotatedClassName,
+ component = componentClass.toClassName()
+ )
+ )
+ super.visitEnd()
+ }
+ }
+ }
+ AggregatedAnnotation.ALIAS_OF -> {
+ return object : AnnotationVisitor(asmApiVersion, nextAnnotationVisitor) {
+ val defineComponentScopeClassNames = mutableSetOf<Type>()
+ lateinit var aliasClassName: Type
+
+ // visit() handles both array and non-array values.
+ // For array values, each value in the array will be visited individually.
+ override fun visit(name: String, value: Any?) {
+ when (name) {
+ // Older versions of AliasOfPropagatedData only passed a single defineComponentScope
+ // class value. Fall back on reading the single value if we get old propagated data.
+ "defineComponentScope",
+ "defineComponentScopes" -> defineComponentScopeClassNames.add(value as Type)
+ "alias" -> aliasClassName = (value as Type)
+ }
+ super.visit(name, value)
+ }
+
+ override fun visitEnd() {
+ aliasOfDeps.add(
+ AliasOfPropagatedDataIr(
+ fqName = annotatedClassName,
+ defineComponentScopes =
+ defineComponentScopeClassNames.map({ it.toClassName() }).toList(),
+ alias = aliasClassName.toClassName(),
+ )
+ )
+ super.visitEnd()
+ }
+ }
+ }
+ AggregatedAnnotation.AGGREGATED_DEP -> {
+ return object : AnnotationVisitor(asmApiVersion, nextAnnotationVisitor) {
+ val componentClasses = mutableListOf<String>()
+ var testClass: String? = null
+ val replacesClasses = mutableListOf<String>()
+ var moduleClass: String? = null
+ var entryPoint: String? = null
+ var componentEntryPoint: String? = null
+
+ override fun visit(name: String, value: Any?) {
+ when (name) {
+ "test" -> testClass = value as String
+ }
+ super.visit(name, value)
+ }
+
+ override fun visitArray(name: String): AnnotationVisitor? {
+ return when (name) {
+ "components" ->
+ visitValue { value -> componentClasses.add(value as String) }
+ "replaces" ->
+ visitValue { value -> replacesClasses.add(value as String) }
+ "modules" ->
+ visitValue { value -> moduleClass = value as String }
+ "entryPoints" ->
+ visitValue { value -> entryPoint = value as String }
+ "componentEntryPoints" ->
+ visitValue { value -> componentEntryPoint = value as String }
+ else -> super.visitArray(name)
+ }
+ }
+
+ override fun visitEnd() {
+ aggregatedDeps.add(
+ AggregatedDepsIr(
+ fqName = annotatedClassName,
+ components = componentClasses.map { it.toClassName() },
+ test = testClass?.toClassName(),
+ replaces = replacesClasses.map { it.toClassName() },
+ module = moduleClass?.toClassName(),
+ entryPoint = entryPoint?.toClassName(),
+ componentEntryPoint = componentEntryPoint?.toClassName()
+ )
+ )
+ super.visitEnd()
+ }
+ }
+ }
+ AggregatedAnnotation.AGGREGATED_DEP_PROXY -> {
+ return object : AnnotationVisitor(asmApiVersion, nextAnnotationVisitor) {
+ lateinit var valueClassName: Type
+
+ override fun visit(name: String, value: Any?) {
+ when (name) {
+ "value" -> valueClassName = (value as Type)
+ }
+ super.visit(name, value)
+ }
+
+ override fun visitEnd() {
+ aggregatedDepProxies.add(
+ AggregatedElementProxyIr(
+ fqName = annotatedClassName,
+ value = valueClassName.toClassName(),
+ )
+ )
+ super.visitEnd()
+ }
+ }
+ }
+ AggregatedAnnotation.AGGREGATED_UNINSTALL_MODULES -> {
+ return object : AnnotationVisitor(asmApiVersion, nextAnnotationVisitor) {
+ lateinit var testClass: String
+ val uninstallModulesClasses = mutableListOf<String>()
+
+ override fun visit(name: String, value: Any?) {
+ when (name) {
+ "test" -> testClass = value as String
+ }
+ super.visit(name, value)
+ }
+
+ override fun visitArray(name: String): AnnotationVisitor? {
+ return when (name) {
+ "uninstallModules" ->
+ visitValue { value -> uninstallModulesClasses.add(value as String) }
+ else -> super.visitArray(name)
+ }
+ }
+
+ override fun visitEnd() {
+ uninstallModulesDeps.add(
+ AggregatedUninstallModulesIr(
+ fqName = annotatedClassName,
+ test = testClass.toClassName(),
+ uninstallModules = uninstallModulesClasses.map { it.toClassName() }
+ )
+ )
+ super.visitEnd()
+ }
+ }
+ }
+ AggregatedAnnotation.AGGREGATED_EARLY_ENTRY_POINT -> {
+ return object : AnnotationVisitor(asmApiVersion, nextAnnotationVisitor) {
+ lateinit var earlyEntryPointClass: String
+
+ override fun visit(name: String, value: Any?) {
+ when (name) {
+ "earlyEntryPoint" -> earlyEntryPointClass = value as String
+ }
+ super.visit(name, value)
+ }
+
+ override fun visitEnd() {
+ earlyEntryPointDeps.add(
+ AggregatedEarlyEntryPointIr(
+ fqName = annotatedClassName,
+ earlyEntryPoint = earlyEntryPointClass.toClassName()
+ )
+ )
+ super.visitEnd()
+ }
+ }
+ }
+ else -> {
+ logger.warn("Found an unknown annotation in Hilt aggregated packages: $descriptor")
+ }
+ }
+ return nextAnnotationVisitor
+ }
+
+ fun visitValue(block: (value: Any) -> Unit) =
+ object : AnnotationVisitor(asmApiVersion) {
+ override fun visit(nullName: String?, value: Any) {
+ block(value)
+ }
+ }
+ }
+
+ private fun process(files: Iterable<File>) {
+ files.forEach { file ->
+ when {
+ file.isFile -> visitFile(file)
+ file.isDirectory -> file.walkTopDown().filter { it.isFile }.forEach { visitFile(it) }
+ else -> logger.warn("Can't process file/directory that doesn't exist: $file")
+ }
+ }
+ }
+
+ private fun visitFile(file: File) {
+ when {
+ file.isJarFile() -> ZipInputStream(file.inputStream()).forEachZipEntry { inputStream, entry ->
+ if (entry.isClassFile()) {
+ visitClass(inputStream)
+ }
+ }
+ file.isClassFile() -> file.inputStream().use { visitClass(it) }
+ else -> logger.debug("Don't know how to process file: $file")
+ }
+ }
+
+ private fun visitClass(classFileInputStream: InputStream) {
+ ClassReader(classFileInputStream).accept(
+ classVisitor,
+ ClassReader.SKIP_CODE and ClassReader.SKIP_DEBUG and ClassReader.SKIP_FRAMES
+ )
+ }
+
+ companion object {
+ fun from(
+ logger: Logger,
+ asmApiVersion: Int,
+ input: Iterable<File>
+ ) = Aggregator(logger, asmApiVersion).apply { process(input) }
+
+ // Converts this Type to a ClassName, used instead of ClassName.bestGuess() because ASM class
+ // names are based off descriptors and uses 'reflection' naming, i.e. inner classes are split
+ // by '$' instead of '.'
+ fun Type.toClassName(): ClassName {
+ val binaryName = this.className
+ val packageNameEndIndex = binaryName.lastIndexOf('.')
+ val packageName = if (packageNameEndIndex != -1) {
+ binaryName.substring(0, packageNameEndIndex)
+ } else {
+ ""
+ }
+ val shortNames = binaryName.substring(packageNameEndIndex + 1).split('$')
+ return ClassName.get(packageName, shortNames.first(), *shortNames.drop(1).toTypedArray())
+ }
+
+ // Converts this String representing the canonical name of a class to a ClassName.
+ fun String.toClassName(): ClassName {
+ return ClassName.bestGuess(this)
+ }
+ }
+}
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/ComponentTreeDepsGenerator.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/ComponentTreeDepsGenerator.kt
new file mode 100644
index 000000000..705528a87
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/ComponentTreeDepsGenerator.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.plugin.root
+
+import com.squareup.javapoet.AnnotationSpec
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.JavaFile
+import com.squareup.javapoet.TypeSpec
+import dagger.hilt.processor.internal.root.ir.ComponentTreeDepsIr
+import java.io.File
+import javax.lang.model.element.Modifier
+
+/** Generates @ComponentTreeDeps annotated sources. */
+internal class ComponentTreeDepsGenerator(
+ private val proxies: Map<ClassName, ClassName>,
+ private val outputDir: File,
+) {
+ fun generate(componentTree: ComponentTreeDepsIr) {
+ val typeSpec = TypeSpec.classBuilder(componentTree.name)
+ .addAnnotation(
+ AnnotationSpec.builder(COMPONENT_TREE_DEPS_ANNOTATION).apply {
+ componentTree.rootDeps.toMaybeProxies().forEach {
+ addMember("rootDeps", "\$T.class", it)
+ }
+ componentTree.defineComponentDeps.toMaybeProxies().forEach {
+ addMember("defineComponentDeps", "\$T.class", it)
+ }
+ componentTree.aliasOfDeps.toMaybeProxies().forEach {
+ addMember("aliasOfDeps", "\$T.class", it)
+ }
+ componentTree.aggregatedDeps.toMaybeProxies().forEach {
+ addMember("aggregatedDeps", "\$T.class", it)
+ }
+ componentTree.uninstallModulesDeps.toMaybeProxies().forEach {
+ addMember("uninstallModulesDeps", "\$T.class", it)
+ }
+ componentTree.earlyEntryPointDeps.toMaybeProxies().forEach {
+ addMember("earlyEntryPointDeps", "\$T.class", it)
+ }
+ }.build()
+ )
+ .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+ .build()
+ JavaFile.builder(componentTree.name.packageName(), typeSpec)
+ .build()
+ .writeTo(outputDir)
+ }
+
+ private fun Collection<ClassName>.toMaybeProxies() =
+ sorted().map { fqName -> proxies[fqName] ?: fqName }
+
+ companion object {
+ val COMPONENT_TREE_DEPS_ANNOTATION: ClassName =
+ ClassName.get("dagger.hilt.internal.componenttreedeps", "ComponentTreeDeps")
+ }
+}
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/ProcessedRootSentinelGenerator.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/ProcessedRootSentinelGenerator.kt
new file mode 100644
index 000000000..931b424ed
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/root/ProcessedRootSentinelGenerator.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.plugin.root
+
+import com.squareup.javapoet.AnnotationSpec
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.JavaFile
+import com.squareup.javapoet.TypeSpec
+import java.io.File
+import javax.lang.model.element.Modifier
+
+internal class ProcessedRootSentinelGenerator(
+ private val outputDir: File,
+) {
+
+ fun generate(processedRootName: ClassName) {
+ val className = ClassName.get(
+ PROCESSED_ROOT_SENTINEL_GEN_PACKAGE,
+ "_" + processedRootName.toString().replace('.', '_')
+ )
+ val typeSpec = TypeSpec.classBuilder(className)
+ .addAnnotation(
+ AnnotationSpec.builder(PROCESSED_ROOT_SENTINEL_ANNOTATION)
+ .addMember("roots", "\$S", processedRootName)
+ .build()
+ )
+ .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+ .build()
+ JavaFile.builder(PROCESSED_ROOT_SENTINEL_GEN_PACKAGE, typeSpec)
+ .build()
+ .writeTo(outputDir)
+ }
+
+ companion object {
+ val PROCESSED_ROOT_SENTINEL_GEN_PACKAGE = "dagger.hilt.internal.processedrootsentinel.codegen"
+ val PROCESSED_ROOT_SENTINEL_ANNOTATION =
+ ClassName.get("dagger.hilt.internal.processedrootsentinel", "ProcessedRootSentinel")
+ }
+}
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/task/AggregateDepsTask.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/task/AggregateDepsTask.kt
new file mode 100644
index 000000000..f3939fc49
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/task/AggregateDepsTask.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.plugin.task
+
+import dagger.hilt.android.plugin.root.AggregatedElementProxyGenerator
+import dagger.hilt.android.plugin.root.ComponentTreeDepsGenerator
+import dagger.hilt.android.plugin.root.ProcessedRootSentinelGenerator
+import dagger.hilt.processor.internal.root.ir.AggregatedRootIrValidator
+import dagger.hilt.processor.internal.root.ir.ComponentTreeDepsIrCreator
+import javax.inject.Inject
+import org.gradle.api.DefaultTask
+import org.gradle.api.file.ConfigurableFileCollection
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.CacheableTask
+import org.gradle.api.tasks.Classpath
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.Optional
+import org.gradle.api.tasks.OutputDirectory
+import org.gradle.api.tasks.TaskAction
+import org.gradle.work.InputChanges
+import org.gradle.workers.WorkAction
+import org.gradle.workers.WorkParameters
+import org.gradle.workers.WorkerExecutor
+import org.objectweb.asm.Opcodes
+import org.slf4j.LoggerFactory
+
+/**
+ * Aggregates Hilt component dependencies from the compile classpath and outputs Java sources
+ * with shareable component trees.
+ *
+ * The [compileClasspath] input is expected to contain jars or classes transformed by
+ * [dagger.hilt.android.plugin.util.AggregatedPackagesTransform].
+ */
+@CacheableTask
+abstract class AggregateDepsTask @Inject constructor(
+ private val workerExecutor: WorkerExecutor
+) : DefaultTask() {
+
+ // TODO(danysantiago): Make @Incremental and try to use @CompileClasspath
+ @get:Classpath
+ abstract val compileClasspath: ConfigurableFileCollection
+
+ @get:Input
+ @get:Optional
+ abstract val asmApiVersion: Property<Int>
+
+ @get:OutputDirectory
+ abstract val outputDir: DirectoryProperty
+
+ @get:Input
+ abstract val testEnvironment: Property<Boolean>
+
+ @get:Input
+ abstract val crossCompilationRootValidationDisabled: Property<Boolean>
+
+ @TaskAction
+ internal fun taskAction(@Suppress("UNUSED_PARAMETER") inputs: InputChanges) {
+ workerExecutor.noIsolation().submit(WorkerAction::class.java) {
+ it.compileClasspath.from(compileClasspath)
+ it.asmApiVersion.set(asmApiVersion)
+ it.outputDir.set(outputDir)
+ it.testEnvironment.set(testEnvironment)
+ it.crossCompilationRootValidationDisabled.set(crossCompilationRootValidationDisabled)
+ }
+ }
+
+ internal interface Parameters : WorkParameters {
+ val compileClasspath: ConfigurableFileCollection
+ val asmApiVersion: Property<Int>
+ val outputDir: DirectoryProperty
+ val testEnvironment: Property<Boolean>
+ val crossCompilationRootValidationDisabled: Property<Boolean>
+ }
+
+ abstract class WorkerAction : WorkAction<Parameters> {
+ override fun execute() {
+ // Logger is not an injectable service yet: https://github.com/gradle/gradle/issues/16991
+ val logger = LoggerFactory.getLogger(AggregateDepsTask::class.java)
+ val aggregator = Aggregator.from(
+ logger = logger,
+ asmApiVersion = parameters.asmApiVersion.getOrNull() ?: Opcodes.ASM7,
+ input = parameters.compileClasspath
+ )
+ val rootsToProcess = AggregatedRootIrValidator.rootsToProcess(
+ isCrossCompilationRootValidationDisabled =
+ parameters.crossCompilationRootValidationDisabled.get(),
+ processedRoots = aggregator.processedRoots,
+ aggregatedRoots = aggregator.aggregatedRoots
+ )
+ if (rootsToProcess.isEmpty()) {
+ return
+ }
+ val componentTrees = ComponentTreeDepsIrCreator.components(
+ isTest = parameters.testEnvironment.get(),
+ isSharedTestComponentsEnabled = true,
+ aggregatedRoots = rootsToProcess,
+ defineComponentDeps = aggregator.defineComponentDeps,
+ aliasOfDeps = aggregator.aliasOfDeps,
+ aggregatedDeps = aggregator.aggregatedDeps,
+ aggregatedUninstallModulesDeps = aggregator.uninstallModulesDeps,
+ aggregatedEarlyEntryPointDeps = aggregator.earlyEntryPointDeps,
+ )
+ ComponentTreeDepsGenerator(
+ proxies = aggregator.allAggregatedDepProxies.associate { it.value to it.fqName },
+ outputDir = parameters.outputDir.get().asFile
+ ).let { generator ->
+ componentTrees.forEach { generator.generate(it) }
+ }
+ AggregatedElementProxyGenerator(parameters.outputDir.get().asFile).let { generator ->
+ (aggregator.allAggregatedDepProxies - aggregator.aggregatedDepProxies).forEach {
+ generator.generate(it)
+ }
+ }
+ ProcessedRootSentinelGenerator(parameters.outputDir.get().asFile).let { generator ->
+ rootsToProcess.map { it.root }.forEach { generator.generate(it) }
+ }
+ }
+ }
+}
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltTransformTestClassesTask.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/task/HiltTransformTestClassesTask.kt
index 84b35b1c7..e2e4e7c56 100644
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltTransformTestClassesTask.kt
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/task/HiltTransformTestClassesTask.kt
@@ -13,9 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package dagger.hilt.android.plugin
+package dagger.hilt.android.plugin.task
-import com.android.build.gradle.api.UnitTestVariant
+import dagger.hilt.android.plugin.AndroidEntryPointClassTransformer
+import dagger.hilt.android.plugin.HiltExtension
+import dagger.hilt.android.plugin.util.capitalize
+import dagger.hilt.android.plugin.util.getCompileKotlin
import dagger.hilt.android.plugin.util.isClassFile
import dagger.hilt.android.plugin.util.isJarFile
import java.io.File
@@ -31,18 +34,15 @@ import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.TaskProvider
-import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.testing.Test
import org.gradle.workers.WorkAction
import org.gradle.workers.WorkParameters
import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.gradle.plugin.KotlinBasePluginWrapper
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
/**
* Task that transform classes used by host-side unit tests. See b/37076369
*/
-@Suppress("UnstableApiUsage")
abstract class HiltTransformTestClassesTask @Inject constructor(
private val workerExecutor: WorkerExecutor
) : DefaultTask() {
@@ -113,7 +113,7 @@ abstract class HiltTransformTestClassesTask @Inject constructor(
fun create(
project: Project,
- unitTestVariant: UnitTestVariant,
+ @Suppress("DEPRECATION") unitTestVariant: com.android.build.gradle.api.UnitTestVariant,
extension: HiltExtension
) {
if (!extension.enableTransformForLocalTests) {
@@ -126,24 +126,18 @@ abstract class HiltTransformTestClassesTask @Inject constructor(
// registerPreJavacGeneratedBytecode() API that would have otherwise given us a key to get
// a classpath up to the generated bytecode associated with the key.
val inputClasspath =
- project.objects.fileCollection().from(unitTestVariant.getCompileClasspath(null))
+ project.files(unitTestVariant.getCompileClasspath(null))
// Find the test sources Java compile task and add its output directory into our input
// classpath file collection. This also makes the transform task depend on the test compile
// task.
- @Suppress("UNCHECKED_CAST")
- val testCompileTaskProvider = project.tasks.named(
- "compile${unitTestVariant.name.capitalize()}JavaWithJavac"
- ) as TaskProvider<JavaCompile>
+ val testCompileTaskProvider = unitTestVariant.javaCompileProvider
inputClasspath.from(testCompileTaskProvider.map { it.destinationDirectory })
// Similarly, if the Kotlin plugin is configured, find the test sources Kotlin compile task
// and add its output directory to our input classpath file collection.
project.plugins.withType(KotlinBasePluginWrapper::class.java) {
- @Suppress("UNCHECKED_CAST")
- val kotlinCompileTaskProvider = project.tasks.named(
- "compile${unitTestVariant.name.capitalize()}Kotlin"
- ) as TaskProvider<KotlinCompile>
+ val kotlinCompileTaskProvider = getCompileKotlin(unitTestVariant, project)
inputClasspath.from(kotlinCompileTaskProvider.map { it.destinationDirectory })
}
@@ -157,11 +151,12 @@ abstract class HiltTransformTestClassesTask @Inject constructor(
)
// Map the transform task's output to a file collection.
val outputFileCollection =
- project.objects.fileCollection().from(hiltTransformProvider.map { it.outputDir })
+ project.files(hiltTransformProvider.map { it.outputDir })
// Configure test classpath by appending the transform output file collection to the start of
// the test classpath so they override the original ones. This also makes test task (the one
// that runs the tests) depend on the transform task.
+
@Suppress("UNCHECKED_CAST")
val testTaskProvider = project.tasks.named(
"test${unitTestVariant.name.capitalize()}"
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/AggregatedPackagesTransform.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/AggregatedPackagesTransform.kt
new file mode 100644
index 000000000..6dfa84264
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/AggregatedPackagesTransform.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.plugin.util
+
+import dagger.hilt.android.plugin.root.AggregatedAnnotation
+import java.io.ByteArrayOutputStream
+import java.io.File
+import java.util.zip.ZipEntry
+import java.util.zip.ZipInputStream
+import java.util.zip.ZipOutputStream
+import org.gradle.api.artifacts.transform.CacheableTransform
+import org.gradle.api.artifacts.transform.InputArtifact
+import org.gradle.api.artifacts.transform.TransformAction
+import org.gradle.api.artifacts.transform.TransformOutputs
+import org.gradle.api.artifacts.transform.TransformParameters
+import org.gradle.api.file.FileSystemLocation
+import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.Classpath
+
+/**
+ * A transform that outputs classes and jars containing only classes in key aggregating Hilt
+ * packages that are used to pass dependencies between compilation units.
+ */
+@CacheableTransform
+abstract class AggregatedPackagesTransform : TransformAction<TransformParameters.None> {
+ // TODO(danysantiago): Make incremental by using InputChanges and try to use @CompileClasspath
+ @get:Classpath
+ @get:InputArtifact
+ abstract val inputArtifactProvider: Provider<FileSystemLocation>
+
+ override fun transform(outputs: TransformOutputs) {
+ val input = inputArtifactProvider.get().asFile
+ when {
+ input.isFile -> transformFile(outputs, input)
+ input.isDirectory -> input.walkTopDown().filter { it.isFile }.forEach {
+ transformFile(outputs, it)
+ }
+ else -> error("File/directory does not exist: ${input.absolutePath}")
+ }
+ }
+
+ private fun transformFile(outputs: TransformOutputs, file: File) {
+ if (file.isJarFile()) {
+ var atLeastOneEntry = false
+ // TODO(danysantiago): This is an in-memory buffer stream, consider using a temp file.
+ val tmpOutputStream = ByteArrayOutputStream()
+ ZipOutputStream(tmpOutputStream).use { outputStream ->
+ ZipInputStream(file.inputStream()).forEachZipEntry { inputStream, inputEntry ->
+ if (inputEntry.isClassFile()) {
+ val parentDirectory = inputEntry.name.substringBeforeLast('/')
+ val match = AggregatedAnnotation.AGGREGATED_PACKAGES.any { aggregatedPackage ->
+ parentDirectory.endsWith(aggregatedPackage)
+ }
+ if (match) {
+ outputStream.putNextEntry(ZipEntry(inputEntry.name))
+ inputStream.copyTo(outputStream)
+ outputStream.closeEntry()
+ atLeastOneEntry = true
+ }
+ }
+ }
+ }
+ if (atLeastOneEntry) {
+ outputs.file(JAR_NAME).outputStream().use { tmpOutputStream.writeTo(it) }
+ }
+ } else if (file.isClassFile()) {
+ // If transforming a file, check if the parent directory matches one of the known aggregated
+ // packages structure. File and Path APIs are used to avoid OS-specific issues when comparing
+ // paths.
+ val parentDirectory: File = file.parentFile
+ val match = AggregatedAnnotation.AGGREGATED_PACKAGES.any { aggregatedPackage ->
+ parentDirectory.endsWith(aggregatedPackage)
+ }
+ if (match) {
+ outputs.file(file)
+ }
+ }
+ }
+
+ companion object {
+ // The output file name containing classes in the aggregated packages.
+ val JAR_NAME = "hiltAggregated.jar"
+ }
+}
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidGradleCompat.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidGradleCompat.kt
new file mode 100644
index 000000000..209005ad3
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidGradleCompat.kt
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.plugin.util
+
+import com.android.build.api.AndroidPluginVersion
+import com.android.build.api.instrumentation.AsmClassVisitorFactory
+import com.android.build.api.instrumentation.FramesComputationMode
+import com.android.build.api.instrumentation.InstrumentationParameters
+import com.android.build.api.instrumentation.InstrumentationScope
+import com.android.build.api.variant.AndroidComponentsExtension
+import com.android.build.api.variant.ApplicationVariant
+import com.android.build.api.variant.Component
+import com.android.build.api.variant.LibraryVariant
+import com.android.build.api.variant.Variant
+import org.gradle.api.Project
+
+/**
+ * Compatibility version of [com.android.build.api.variant.AndroidComponentsExtension]
+ * - In AGP 4.2 its package is 'com.android.build.api.extension'
+ * - In AGP 7.0 its packages is 'com.android.build.api.variant'
+ */
+sealed class AndroidComponentsExtensionCompat {
+
+ /**
+ * A combined compatibility function of
+ * [com.android.build.api.variant.AndroidComponentsExtension.onVariants] that includes also
+ * [AndroidTest] and [UnitTest] variants.
+ */
+ abstract fun onAllVariants(block: (ComponentCompat) -> Unit)
+
+ class Api70Impl(
+ private val actual: AndroidComponentsExtension<*, *, *>
+ ) : AndroidComponentsExtensionCompat() {
+
+ private val componentInit: (component: Component) -> ComponentCompat = {
+ if (actual.pluginVersion < AndroidPluginVersion(7, 2)) {
+ ComponentCompat.Api70Impl(it)
+ } else {
+ ComponentCompat.Api72Impl(it)
+ }
+ }
+
+ override fun onAllVariants(block: (ComponentCompat) -> Unit) {
+ actual.onVariants { variant ->
+ // Use reflection to get the AndroidTest component out of the variant because a binary
+ // incompatible change was introduced in AGP 7.0-beta05 that changed the return type of the
+ // method.
+ fun ApplicationVariant.getAndroidTest() =
+ this::class.java.getDeclaredMethod("getAndroidTest").invoke(this) as? Component
+ fun LibraryVariant.getAndroidTest() =
+ this::class.java.getDeclaredMethod("getAndroidTest").invoke(this) as? Component
+ block.invoke(componentInit(variant))
+ when (variant) {
+ is ApplicationVariant -> variant.getAndroidTest()
+ is LibraryVariant -> variant.getAndroidTest()
+ else -> null
+ }?.let { block.invoke(componentInit(it)) }
+ // Use reflection too to get the UnitTest component since in 7.2
+ // com.android.build.api.component.UnitTest was removed and replaced by
+ // com.android.build.api.variant.UnitTest causing the return type of Variant#getUnitTest()
+ // to change and break ABI.
+ fun Variant.getUnitTest() =
+ this::class.java.getDeclaredMethod("getUnitTest").invoke(this) as? Component
+ variant.getUnitTest()?.let { block.invoke(componentInit(it)) }
+ }
+ }
+ }
+
+ class Api42Impl(private val actual: Any) : AndroidComponentsExtensionCompat() {
+
+ private val extensionClazz =
+ Class.forName("com.android.build.api.extension.AndroidComponentsExtension")
+
+ private val variantSelectorClazz =
+ Class.forName("com.android.build.api.extension.VariantSelector")
+
+ override fun onAllVariants(block: (ComponentCompat) -> Unit) {
+ val selector = extensionClazz.getDeclaredMethod("selector").invoke(actual)
+ val allSelector = variantSelectorClazz.getDeclaredMethod("all").invoke(selector)
+ val wrapFunction: (Any) -> Unit = {
+ block.invoke(ComponentCompat.Api42Impl(it))
+ }
+ listOf("onVariants", "androidTests", "unitTests").forEach { methodName ->
+ extensionClazz.getDeclaredMethod(
+ methodName, variantSelectorClazz, Function1::class.java
+ ).invoke(actual, allSelector, wrapFunction)
+ }
+ }
+ }
+
+ companion object {
+ fun getAndroidComponentsExtension(project: Project): AndroidComponentsExtensionCompat {
+ return if (
+ findClass("com.android.build.api.variant.AndroidComponentsExtension") != null
+ ) {
+ val actualExtension = project.extensions.getByType(AndroidComponentsExtension::class.java)
+ Api70Impl(actualExtension)
+ } else {
+ val actualExtension = project.extensions.getByType(
+ Class.forName("com.android.build.api.extension.AndroidComponentsExtension")
+ )
+ Api42Impl(actualExtension)
+ }
+ }
+ }
+}
+
+/**
+ * Compatibility version of [com.android.build.api.variant.Component]
+ * - In AGP 4.2 its package is 'com.android.build.api.component'
+ * - In AGP 7.0 its packages is 'com.android.build.api.variant'
+ */
+@Suppress("UnstableApiUsage") // ASM Pipeline APIs
+sealed class ComponentCompat {
+
+ /**
+ * Redeclaration of [com.android.build.api.variant.ComponentIdentity.name]
+ */
+ abstract val name: String
+
+ /**
+ * Redeclaration of [com.android.build.api.variant.Component.transformClassesWith]
+ */
+ abstract fun <ParamT : InstrumentationParameters> transformClassesWith(
+ classVisitorFactoryImplClass: Class<out AsmClassVisitorFactory<ParamT>>,
+ scope: InstrumentationScope,
+ instrumentationParamsConfig: (ParamT) -> Unit
+ )
+
+ /**
+ * Redeclaration of [com.android.build.api.variant.Component.setAsmFramesComputationMode]
+ */
+ abstract fun setAsmFramesComputationMode(mode: FramesComputationMode)
+
+ class Api72Impl(private val component: Component) : ComponentCompat() {
+
+ override val name: String
+ get() = component.name
+
+ override fun <ParamT : InstrumentationParameters> transformClassesWith(
+ classVisitorFactoryImplClass: Class<out AsmClassVisitorFactory<ParamT>>,
+ scope: InstrumentationScope,
+ instrumentationParamsConfig: (ParamT) -> Unit
+ ) {
+ component.instrumentation.transformClassesWith(
+ classVisitorFactoryImplClass, scope, instrumentationParamsConfig
+ )
+ }
+
+ override fun setAsmFramesComputationMode(mode: FramesComputationMode) {
+ component.instrumentation.setAsmFramesComputationMode(mode)
+ }
+ }
+
+ class Api70Impl(private val component: Component) : ComponentCompat() {
+
+ override val name: String
+ get() = component.name
+
+ override fun <ParamT : InstrumentationParameters> transformClassesWith(
+ classVisitorFactoryImplClass: Class<out AsmClassVisitorFactory<ParamT>>,
+ scope: InstrumentationScope,
+ instrumentationParamsConfig: (ParamT) -> Unit
+ ) {
+ Component::class.java.getDeclaredMethod(
+ "transformClassesWith",
+ Class::class.java,
+ InstrumentationScope::class.java,
+ Function1::class.java
+ ).invoke(component, classVisitorFactoryImplClass, scope, instrumentationParamsConfig)
+ }
+
+ override fun setAsmFramesComputationMode(mode: FramesComputationMode) {
+ Component::class.java.getDeclaredMethod(
+ "setAsmFramesComputationMode",
+ FramesComputationMode::class.java
+ ).invoke(component, mode)
+ }
+ }
+
+ class Api42Impl(private val actual: Any) : ComponentCompat() {
+
+ private val componentClazz = Class.forName("com.android.build.api.component.Component")
+
+ override val name: String
+ get() = componentClazz.getMethod("getName").invoke(actual) as String
+
+ override fun <ParamT : InstrumentationParameters> transformClassesWith(
+ classVisitorFactoryImplClass: Class<out AsmClassVisitorFactory<ParamT>>,
+ scope: InstrumentationScope,
+ instrumentationParamsConfig: (ParamT) -> Unit
+ ) {
+ componentClazz.getDeclaredMethod(
+ "transformClassesWith",
+ Class::class.java, InstrumentationScope::class.java, Function1::class.java
+ ).invoke(actual, classVisitorFactoryImplClass, scope, instrumentationParamsConfig)
+ }
+
+ override fun setAsmFramesComputationMode(mode: FramesComputationMode) {
+ componentClazz.getDeclaredMethod(
+ "setAsmFramesComputationMode", FramesComputationMode::class.java
+ ).invoke(actual, mode)
+ }
+ }
+}
+
+fun findClass(fqName: String) = try {
+ Class.forName(fqName)
+} catch (ex: ClassNotFoundException) {
+ null
+}
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/CopyTransform.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/CopyTransform.kt
index 39a2d3a89..1b1b58342 100644
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/CopyTransform.kt
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/CopyTransform.kt
@@ -9,9 +9,10 @@ import org.gradle.api.file.FileSystemLocation
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Classpath
-// A transform that registers the input jar file as an output and thus changing from one artifact
-// type to another.
-// TODO: Improve to only copy classes that need to be visible by Hilt & Dagger.
+/**
+ * A transform that registers the input file (usually a jar or a class) as an output and thus
+ * changing from one artifact type to another.
+ */
@CacheableTransform
abstract class CopyTransform : TransformAction<TransformParameters.None> {
@get:Classpath
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/Files.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/Files.kt
index e5a101e34..c83d6354d 100644
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/Files.kt
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/Files.kt
@@ -1,14 +1,59 @@
package dagger.hilt.android.plugin.util
-import com.android.SdkConstants
import java.io.File
+import java.io.InputStream
+import java.util.Properties
import java.util.zip.ZipEntry
+import java.util.zip.ZipInputStream
+import org.gradle.api.Project
/* Checks if a file is a .class file. */
-fun File.isClassFile() = this.isFile && this.extension == SdkConstants.EXT_CLASS
+fun File.isClassFile() = this.isFile && this.extension == "class"
/* Checks if a Zip entry is a .class file. */
-fun ZipEntry.isClassFile() = !this.isDirectory && this.name.endsWith(SdkConstants.DOT_CLASS)
+fun ZipEntry.isClassFile() = !this.isDirectory && this.name.endsWith(".class")
-/* CHecks if a file is a .jar file. */
-fun File.isJarFile() = this.isFile && this.extension == SdkConstants.EXT_JAR
+/* Checks if a file is a .jar file. */
+fun File.isJarFile() = this.isFile && this.extension == "jar"
+
+/* Executes the given [block] function over each [ZipEntry] in this [ZipInputStream]. */
+fun ZipInputStream.forEachZipEntry(block: (InputStream, ZipEntry) -> Unit) = use {
+ var inputEntry = nextEntry
+ while (inputEntry != null) {
+ block(this, inputEntry)
+ inputEntry = nextEntry
+ }
+}
+
+/* Gets the Android Sdk Path. */
+fun Project.getSdkPath(): File {
+ val localPropsFile = rootProject.projectDir.resolve("local.properties")
+ if (localPropsFile.exists()) {
+ val localProps = Properties()
+ localPropsFile.inputStream().use { localProps.load(it) }
+ val localSdkDir = localProps["sdk.dir"]?.toString()
+ if (localSdkDir != null) {
+ val sdkDirectory = File(localSdkDir)
+ if (sdkDirectory.isDirectory) {
+ return sdkDirectory
+ }
+ }
+ }
+ return getSdkPathFromEnvironmentVariable()
+}
+
+private fun getSdkPathFromEnvironmentVariable(): File {
+ // Check for environment variables, in the order AGP checks.
+ listOf("ANDROID_HOME", "ANDROID_SDK_ROOT").forEach {
+ val envValue = System.getenv(it)
+ if (envValue != null) {
+ val sdkDirectory = File(envValue)
+ if (sdkDirectory.isDirectory) {
+ return sdkDirectory
+ }
+ }
+ }
+ // Only print the error for SDK ROOT since ANDROID_HOME is deprecated but we first check
+ // it because it is prioritized according to the documentation.
+ error("ANDROID_SDK_ROOT environment variable is not set")
+}
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/SimpleAGPVersion.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/SimpleAGPVersion.kt
index 339c83e1a..cb442b234 100644
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/SimpleAGPVersion.kt
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/SimpleAGPVersion.kt
@@ -46,11 +46,5 @@ internal data class SimpleAGPVersion(
return SimpleAGPVersion(parts[0].toInt(), parts[1].toInt())
}
-
- private fun findClass(fqName: String) = try {
- Class.forName(fqName)
- } catch (ex: ClassNotFoundException) {
- null
- }
}
}
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/Model.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/Strings.kt
index 4fe168db8..82acc26ec 100644
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/Model.kt
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/Strings.kt
@@ -14,11 +14,14 @@
* limitations under the License.
*/
-package dagger.hilt.android.example.gradle.simpleKotlin
+package dagger.hilt.android.plugin.util
-import javax.inject.Qualifier
+import java.util.Locale
-/** Qualifies bindings relating to [android.os.Build.MODEL]. */
-@Qualifier
-@Retention(AnnotationRetention.RUNTIME)
-internal annotation class Model
+fun String.capitalize(
+ locale: Locale = Locale.getDefault()
+): String = if (isNotEmpty() && this[0].isLowerCase()) {
+ substring(0, 1).uppercase(locale) + substring(1)
+} else {
+ this
+}
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/Tasks.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/Tasks.kt
new file mode 100644
index 000000000..b46c3d60a
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/Tasks.kt
@@ -0,0 +1,16 @@
+package dagger.hilt.android.plugin.util
+
+import org.gradle.api.Project
+import org.gradle.api.tasks.TaskProvider
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+/**
+ * Gets [KotlinCompile] task of an Android variant.
+ */
+@Suppress("UNCHECKED_CAST")
+internal fun getCompileKotlin(
+ @Suppress("DEPRECATION") variant: com.android.build.gradle.api.BaseVariant,
+ project: Project
+) = project.tasks.named(
+ "compile${variant.name.capitalize()}Kotlin"
+) as TaskProvider<KotlinCompile>
diff --git a/java/dagger/hilt/android/plugin/src/main/resources/META-INF/gradle-plugins/com.google.dagger.hilt.android.properties b/java/dagger/hilt/android/plugin/src/main/resources/META-INF/gradle-plugins/com.google.dagger.hilt.android.properties
new file mode 100644
index 000000000..5d2b9dfc8
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/main/resources/META-INF/gradle-plugins/com.google.dagger.hilt.android.properties
@@ -0,0 +1 @@
+implementation-class=dagger.hilt.android.plugin.HiltGradlePlugin \ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/src/test/data/flavored-project/app/build.gradle b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/app/build.gradle
new file mode 100644
index 000000000..c42caf9c4
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/app/build.gradle
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+plugins {
+ id 'com.android.application'
+ id 'dagger.hilt.android.plugin'
+}
+
+android {
+ compileSdkVersion 30
+ buildToolsVersion "30.0.2"
+
+ flavorDimensions 'api', 'version'
+ productFlavors {
+ demo {
+ dimension 'version'
+ }
+ full {
+ dimension 'version'
+ }
+ minApi24 {
+ dimension 'api'
+ minSdkVersion '24'
+ versionNameSuffix "-minApi24"
+ }
+ minApi21 {
+ dimension "api"
+ minSdkVersion '21'
+ versionNameSuffix "-minApi21"
+ }
+ }
+
+ defaultConfig {
+ applicationId "simple.app"
+ minSdkVersion 21
+ targetSdkVersion 30
+ }
+
+ compileOptions {
+ sourceCompatibility 1.8
+ targetCompatibility 1.8
+ }
+}
+
+dependencies {
+ implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
+ annotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
+ implementation project(':feature')
+}
+
+hilt {
+ enableAggregatingTask = true
+} \ No newline at end of file
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/res/values/strings.xml b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/app/src/main/AndroidManifest.xml
index c1e4f272f..0ce231537 100644
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/res/values/strings.xml
+++ b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/app/src/main/AndroidManifest.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright (C) 2020 The Dagger Authors.
+ ~ Copyright (C) 2021 The Dagger Authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -13,11 +13,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<resources>
- <!--The app name [CHAR_LIMIT=40]-->
- <string name="app_name">Simple Hilt Kotlin Android App</string>
-
- <!--The greeting message [CHAR_LIMIT=100]-->
- <string name="welcome">Hello, %1$s! You are on build %2$s.</string>
-</resources>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="simple.app">
+ <application android:name=".SimpleApp" android:label="Flavored App">
+ </application>
+</manifest> \ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/App.kt b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/app/src/main/java/simple/app/SimpleApp.java
index 1cbd4b062..39cf48ecf 100644
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/App.kt
+++ b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/app/src/main/java/simple/app/SimpleApp.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Dagger Authors.
+ * Copyright (C) 2021 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,10 +14,12 @@
* limitations under the License.
*/
-package dagger.hilt.android.gradleConfigCache
+package simple.app;
-import androidx.multidex.MultiDexApplication
-import dagger.hilt.android.HiltAndroidApp
+import android.app.Application;
+import dagger.hilt.android.HiltAndroidApp;
+/** Just an application. */
@HiltAndroidApp
-class App : MultiDexApplication()
+public class SimpleApp extends Application {
+} \ No newline at end of file
diff --git a/java/dagger/example/gradle/android/simple/build.gradle b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/build.gradle
index 50f8f0baa..ec95fa9dd 100644
--- a/java/dagger/example/gradle/android/simple/build.gradle
+++ b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/build.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Dagger Authors.
+ * Copyright (C) 2021 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,19 +17,14 @@
buildscript {
repositories {
google()
- jcenter()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:4.1.1'
+ mavenCentral()
}
}
allprojects {
repositories {
- google()
- jcenter()
- mavenCentral()
- mavenLocal()
+ mavenLocal()
+ google()
+ mavenCentral()
}
-}
-
+} \ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/src/test/data/flavored-project/feature/build.gradle b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/feature/build.gradle
new file mode 100644
index 000000000..218a22434
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/feature/build.gradle
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+plugins {
+ id 'com.android.library'
+ id 'dagger.hilt.android.plugin'
+}
+
+android {
+ compileSdkVersion 30
+ buildToolsVersion "30.0.2"
+
+ flavorDimensions 'api', 'version'
+ productFlavors {
+ demo {
+ dimension 'version'
+ }
+ full {
+ dimension 'version'
+ }
+ minApi24 {
+ dimension 'api'
+ minSdkVersion '24'
+ versionNameSuffix "-minApi24"
+ }
+ minApi21 {
+ dimension "api"
+ minSdkVersion '21'
+ versionNameSuffix "-minApi21"
+ }
+ }
+
+ defaultConfig {
+ minSdkVersion 16
+ targetSdkVersion 30
+ }
+
+ compileOptions {
+ sourceCompatibility 1.8
+ targetCompatibility 1.8
+ }
+}
+
+dependencies {
+ implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
+ annotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
+} \ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/res/values/strings.xml b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/feature/src/main/AndroidManifest.xml
index 05afdbf55..fc219c877 100644
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/res/values/strings.xml
+++ b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/feature/src/main/AndroidManifest.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright (C) 2020 The Dagger Authors.
+ ~ Copyright (C) 2021 The Dagger Authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -13,8 +13,6 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<resources>
- <!--The app name [CHAR_LIMIT=40]-->
- <string name="app_name">Gradle Configuration Cache App</string>
-</resources>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="simple.library">
+</manifest> \ No newline at end of file
diff --git a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureCounter.kt b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/feature/src/main/java/simple/library/LibraryCode.java
index 0fd3db369..e3bb9dd80 100644
--- a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureCounter.kt
+++ b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/feature/src/main/java/simple/library/LibraryCode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Dagger Authors.
+ * Copyright (C) 2021 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,8 @@
* limitations under the License.
*/
-package dagger.hilt.android.example.gradle.simple.feature
+package simple.library;
-class FeatureCounter(var count: Int)
+/** Just some 'Library' code */
+public class LibraryCode {
+} \ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/src/test/data/flavored-project/gradle.properties b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/gradle.properties
new file mode 100644
index 000000000..5bac8ac50
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/gradle.properties
@@ -0,0 +1 @@
+android.useAndroidX=true
diff --git a/java/dagger/hilt/android/plugin/src/test/data/flavored-project/settings.gradle b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/settings.gradle
new file mode 100644
index 000000000..d3cc2b0ae
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/test/data/flavored-project/settings.gradle
@@ -0,0 +1,3 @@
+rootProject.name='Flavored Project'
+include ':app'
+include ':feature' \ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity1.java b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity1.java
index a6e5d936d..4c7ba88d3 100644
--- a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity1.java
+++ b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity1.java
@@ -21,8 +21,8 @@ import dagger.hilt.android.AndroidEntryPoint;
import javax.inject.Inject;
/** Just an activity. */
-@AndroidEntryPoint(AppCompatActivity.class)
-public class Activity1 extends Hilt_Activity1 {
+@AndroidEntryPoint
+public class Activity1 extends AppCompatActivity {
@Inject String data;
// Insert-change
diff --git a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity2.java b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity2.java
index f7793be08..9c271c673 100644
--- a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity2.java
+++ b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity2.java
@@ -21,8 +21,8 @@ import dagger.hilt.android.AndroidEntryPoint;
import javax.inject.Inject;
/** Just an activity. */
-@AndroidEntryPoint(AppCompatActivity.class)
-public class Activity2 extends Hilt_Activity2 {
+@AndroidEntryPoint
+public class Activity2 extends AppCompatActivity {
@Inject String data;
// Insert-change
diff --git a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/SimpleApp.java b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/SimpleApp.java
index 5a9224194..ded0b7dd6 100644
--- a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/SimpleApp.java
+++ b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/SimpleApp.java
@@ -20,7 +20,7 @@ import android.app.Application;
import dagger.hilt.android.HiltAndroidApp;
/** Just an application. */
-@HiltAndroidApp(Application.class)
-public class SimpleApp extends Hilt_SimpleApp {
+@HiltAndroidApp
+public class SimpleApp extends Application {
// Insert-change
}
diff --git a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/test/java/simple/Test1.java b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/test/java/simple/Test1.java
new file mode 100644
index 000000000..0ed15c753
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/test/java/simple/Test1.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package simple;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import dagger.Module;
+import dagger.Provides;
+import dagger.hilt.InstallIn;
+import dagger.hilt.android.testing.HiltAndroidRule;
+import dagger.hilt.android.testing.HiltAndroidTest;
+import dagger.hilt.android.testing.HiltTestApplication;
+import dagger.hilt.components.SingletonComponent;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+/** Just a test. */
+@HiltAndroidTest
+@RunWith(AndroidJUnit4.class)
+@Config(application = HiltTestApplication.class)
+public class Test1 {
+
+ @Rule
+ public HiltAndroidRule hiltRule = new HiltAndroidRule(this);
+
+ @Test
+ public void emptyTest() {
+
+ }
+
+ // Insert-change
+
+ /** An inner test module. */
+ @Module
+ @InstallIn(SingletonComponent.class)
+ public static final class TestModule {
+ @Provides
+ public static double provideDouble() {
+ return 0.0;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/test/java/simple/Test2.java b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/test/java/simple/Test2.java
new file mode 100644
index 000000000..a812ed667
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/test/java/simple/Test2.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package simple;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import dagger.Module;
+import dagger.Provides;
+import dagger.hilt.InstallIn;
+import dagger.hilt.android.testing.HiltAndroidRule;
+import dagger.hilt.android.testing.HiltAndroidTest;
+import dagger.hilt.android.testing.HiltTestApplication;
+import dagger.hilt.components.SingletonComponent;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+/** Just a test. */
+@HiltAndroidTest
+@RunWith(AndroidJUnit4.class)
+@Config(application = HiltTestApplication.class)
+public class Test2 {
+
+ @Rule
+ public HiltAndroidRule hiltRule = new HiltAndroidRule(this);
+
+ @Test
+ public void emptyTest() {
+
+ }
+
+ /** An inner test module. */
+ @Module
+ @InstallIn(SingletonComponent.class)
+ public static final class TestModule {
+ @Provides
+ public static double provideDouble() {
+ return 0.0;
+ }
+ }
+} \ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/src/test/kotlin/BuildCacheTest.kt b/java/dagger/hilt/android/plugin/src/test/kotlin/BuildCacheTest.kt
new file mode 100644
index 000000000..517032d24
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/test/kotlin/BuildCacheTest.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2020 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.UUID
+import org.gradle.testkit.runner.TaskOutcome.FROM_CACHE
+import org.gradle.testkit.runner.TaskOutcome.SUCCESS
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+// Test that verifies the hilt class transform does not break the Gradle's remote build cache.
+@RunWith(Parameterized::class)
+class BuildCacheTest(private val enableAggregatingTask: Boolean) {
+ @get:Rule val gradleHomeFolder = TemporaryFolder()
+
+ @get:Rule val firstProjectDir = TemporaryFolder()
+ lateinit var firstGradleRunner: GradleTestRunner
+
+ @get:Rule val secondProjectDir = TemporaryFolder()
+ lateinit var secondGradleRunner: GradleTestRunner
+
+ private val testId = UUID.randomUUID().toString()
+
+ @Before
+ fun setup() {
+ firstGradleRunner = createGradleRunner(firstProjectDir)
+ secondGradleRunner = createGradleRunner(secondProjectDir)
+ }
+
+ private fun createGradleRunner(folder: TemporaryFolder): GradleTestRunner {
+ val gradleRunner = GradleTestRunner(folder)
+ gradleRunner.addDependencies(
+ "implementation 'androidx.appcompat:appcompat:1.1.0'",
+ "implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'",
+ "annotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'",
+ )
+ gradleRunner.runAdditionalTasks("--build-cache")
+ gradleRunner.addSrc(
+ srcPath = "minimal/MyApp.java",
+ srcContent =
+ """
+ package minimal;
+
+ import android.app.Application;
+
+ @dagger.hilt.android.HiltAndroidApp
+ public class MyApp extends Application {
+ // random id inserted into the code to ensure that the first is never a cache hit and the
+ // second run always is
+ public static String RANDOM_ID = "$testId";
+ }
+ """.trimIndent()
+ )
+ gradleRunner.setAppClassName(".MyApp")
+ gradleRunner.addHiltOption("enableAggregatingTask = $enableAggregatingTask")
+ return gradleRunner
+ }
+
+ // Verifies that library B and library C injected classes are available in the root classpath.
+ @Test
+ fun test_buildCacheHitOnRelocatedProject() {
+ val firstResult = firstGradleRunner.build()
+ assertEquals(firstResult.getTask(":transformDebugClassesWithAsm").outcome, SUCCESS)
+
+ val secondResult = secondGradleRunner.build()
+ val cacheableTasks: List<String> = mutableListOf<String>().apply {
+ add(":checkDebugAarMetadata")
+ add(":checkDebugDuplicateClasses")
+ add(":compileDebugJavaWithJavac")
+ add(":compressDebugAssets")
+ add(":extractDeepLinksDebug")
+ add(":generateDebugBuildConfig")
+ add(":generateDebugResValues")
+ // When aggregating task is enabled, the plugin adds two more tasks that should be
+ // cacheable.
+ if (enableAggregatingTask) {
+ add(":hiltAggregateDepsDebug")
+ add(":hiltJavaCompileDebug")
+ }
+ add(":javaPreCompileDebug")
+ add(":mergeDebugAssets")
+ add(":mergeDebugJavaResource")
+ add(":mergeDebugJniLibFolders")
+ add(":mergeDebugNativeLibs")
+ add(":mergeDebugShaders")
+ add(":mergeExtDexDebug")
+ add(":mergeLibDexDebug")
+ add(":mergeProjectDexDebug")
+ add(":processDebugManifestForPackage")
+ add(":transformDebugClassesWithAsm")
+ add(":validateSigningDebug")
+ add(":writeDebugAppMetadata")
+ add(":writeDebugSigningConfigVersions")
+ }
+
+ val tasksFromCache =
+ secondResult.tasks.filter { it.outcome == FROM_CACHE }.map { it.path }.sorted()
+ assertEquals(cacheableTasks, tasksFromCache)
+ }
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "enableAggregatingTask = {0}")
+ fun parameters() = listOf(false, true)
+ }
+}
diff --git a/java/dagger/hilt/android/plugin/src/test/kotlin/CompileClasspathTest.kt b/java/dagger/hilt/android/plugin/src/test/kotlin/CompileClasspathTest.kt
index 614125081..d61b37011 100644
--- a/java/dagger/hilt/android/plugin/src/test/kotlin/CompileClasspathTest.kt
+++ b/java/dagger/hilt/android/plugin/src/test/kotlin/CompileClasspathTest.kt
@@ -21,8 +21,12 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
-class CompileClasspathTest {
+// Test that verifies compile classpath aggregation done by the plugin.
+@RunWith(Parameterized::class)
+class CompileClasspathTest(private val pluginFlagName: String) {
@get:Rule
val testProjectDir = TemporaryFolder()
@@ -31,11 +35,13 @@ class CompileClasspathTest {
@Before
fun setup() {
gradleRunner = GradleTestRunner(testProjectDir)
- gradleRunner.addAndroidOption(
- "lintOptions.checkReleaseBuilds = false"
- )
+ if (pluginFlagName == "enableExperimentalClasspathAggregation") {
+ gradleRunner.addAndroidOption(
+ "lintOptions.checkReleaseBuilds = false"
+ )
+ }
gradleRunner.addHiltOption(
- "enableExperimentalClasspathAggregation = true"
+ "$pluginFlagName = true"
)
gradleRunner.addDependencies(
"implementation 'androidx.appcompat:appcompat:1.1.0'",
@@ -108,4 +114,13 @@ class CompileClasspathTest {
val assembleTask = result.getTask(":assembleDebug")
assertEquals(TaskOutcome.SUCCESS, assembleTask.outcome)
}
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun parameters() = listOf(
+ "enableExperimentalClasspathAggregation",
+ "enableAggregatingTask"
+ )
+ }
}
diff --git a/java/dagger/hilt/android/plugin/src/test/kotlin/CrossCompilationRootValidationTest.kt b/java/dagger/hilt/android/plugin/src/test/kotlin/CrossCompilationRootValidationTest.kt
new file mode 100644
index 000000000..e0848dd56
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/test/kotlin/CrossCompilationRootValidationTest.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+
+class CrossCompilationRootValidationTest {
+ @get:Rule
+ val testProjectDir = TemporaryFolder()
+
+ lateinit var gradleRunner: GradleTestRunner
+
+ @Before
+ fun setup() {
+ gradleRunner = GradleTestRunner(testProjectDir)
+ gradleRunner.addHiltOption(
+ "enableAggregatingTask = true"
+ )
+ gradleRunner.addDependencies(
+ "implementation 'androidx.appcompat:appcompat:1.1.0'",
+ "implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'",
+ "annotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'",
+ "testImplementation 'com.google.dagger:hilt-android-testing:LOCAL-SNAPSHOT'",
+ "testAnnotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'",
+ )
+ gradleRunner.addSrc(
+ srcPath = "minimal/MyApp.java",
+ srcContent =
+ """
+ package minimal;
+
+ import android.app.Application;
+
+ @dagger.hilt.android.HiltAndroidApp
+ public class MyApp extends Application { }
+ """.trimIndent()
+ )
+ gradleRunner.setAppClassName(".MyApp")
+ }
+
+ @Test
+ fun multipleAppRootsFailure() {
+ gradleRunner.addSrc(
+ srcPath = "minimal/MyApp2.java",
+ srcContent =
+ """
+ package minimal;
+
+ import android.app.Application;
+
+ @dagger.hilt.android.HiltAndroidApp
+ public class MyApp2 extends Application { }
+ """.trimIndent()
+ )
+
+ val result = gradleRunner.buildAndFail()
+ assertThat(result.getOutput()).contains(
+ "Cannot process multiple app roots in the same compilation unit: " +
+ "minimal.MyApp, minimal.MyApp2"
+ )
+ }
+
+ @Test
+ fun testRootsAndAppRootsFailure() {
+ gradleRunner.addTestSrc(
+ srcPath = "minimal/MyTest.java",
+ srcContent =
+ """
+ package minimal;
+
+ @dagger.hilt.android.testing.HiltAndroidTest
+ public class MyTest { }
+ """.trimIndent()
+ )
+ gradleRunner.addTestSrc(
+ srcPath = "minimal/BadApp.java",
+ srcContent =
+ """
+ package minimal;
+
+ import android.app.Application;
+
+ @dagger.hilt.android.HiltAndroidApp
+ public class BadApp extends Application { }
+ """.trimIndent()
+ )
+
+ gradleRunner.runAdditionalTasks("testDebug")
+ val result = gradleRunner.buildAndFail()
+ assertThat(result.getOutput()).contains(
+ "Cannot process test roots and app roots in the same compilation unit:"
+ )
+ assertThat(result.getOutput()).contains(
+ "App root in this compilation unit: minimal.BadApp"
+ )
+ assertThat(result.getOutput()).contains(
+ "Test roots in this compilation unit: minimal.MyTest"
+ )
+ }
+}
diff --git a/java/dagger/hilt/android/plugin/src/test/kotlin/GradleTestRunner.kt b/java/dagger/hilt/android/plugin/src/test/kotlin/GradleTestRunner.kt
index 2d58766d8..d32b40eac 100644
--- a/java/dagger/hilt/android/plugin/src/test/kotlin/GradleTestRunner.kt
+++ b/java/dagger/hilt/android/plugin/src/test/kotlin/GradleTestRunner.kt
@@ -16,6 +16,7 @@
import java.io.File
import org.gradle.testkit.runner.BuildResult
+import org.gradle.testkit.runner.BuildTask
import org.gradle.testkit.runner.GradleRunner
import org.junit.rules.TemporaryFolder
@@ -31,9 +32,11 @@ class GradleTestRunner(val tempFolder: TemporaryFolder) {
private var buildFile: File? = null
private var gradlePropertiesFile: File? = null
private var manifestFile: File? = null
+ private var additionalTasks = mutableListOf<String>()
init {
tempFolder.newFolder("src", "main", "java", "minimal")
+ tempFolder.newFolder("src", "test", "java", "minimal")
tempFolder.newFolder("src", "main", "res")
}
@@ -68,6 +71,12 @@ class GradleTestRunner(val tempFolder: TemporaryFolder) {
return tempFolder.newFile("/src/main/java/$srcPath").apply { writeText(srcContent) }
}
+ // Adds a test source file to the project. The source path is relative to 'src/test/java'.
+ fun addTestSrc(srcPath: String, srcContent: String): File {
+ File(tempFolder.root, "src/test/java/${srcPath.substringBeforeLast(File.separator)}").mkdirs()
+ return tempFolder.newFile("/src/test/java/$srcPath").apply { writeText(srcContent) }
+ }
+
// Adds a resource file to the project. The source path is relative to 'src/main/res'.
fun addRes(resPath: String, resContent: String): File {
File(tempFolder.root, "src/main/res/${resPath.substringBeforeLast(File.separator)}").mkdirs()
@@ -78,6 +87,10 @@ class GradleTestRunner(val tempFolder: TemporaryFolder) {
appClassName = name
}
+ fun runAdditionalTasks(taskName: String) {
+ additionalTasks.add(taskName)
+ }
+
// Executes a Gradle builds and expects it to succeed.
fun build(): Result {
setupFiles()
@@ -104,10 +117,10 @@ class GradleTestRunner(val tempFolder: TemporaryFolder) {
buildscript {
repositories {
google()
- jcenter()
+ mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.2.0-beta04'
+ classpath 'com.android.tools.build:gradle:4.2.0'
}
}
@@ -137,7 +150,7 @@ class GradleTestRunner(val tempFolder: TemporaryFolder) {
repositories {
mavenLocal()
google()
- jcenter()
+ mavenCentral()
}
}
@@ -184,7 +197,7 @@ class GradleTestRunner(val tempFolder: TemporaryFolder) {
private fun createRunner() = GradleRunner.create()
.withProjectDir(tempFolder.root)
- .withArguments("assembleDebug", "--stacktrace")
+ .withArguments(listOf("--stacktrace", "assembleDebug") + additionalTasks)
.withPluginClasspath()
// .withDebug(true) // Add this line to enable attaching a debugger to the gradle test invocation
.forwardOutput()
@@ -194,6 +207,9 @@ class GradleTestRunner(val tempFolder: TemporaryFolder) {
private val projectRoot: File,
private val buildResult: BuildResult
) {
+
+ val tasks: List<BuildTask> get() = buildResult.tasks
+
// Finds a task by name.
fun getTask(name: String) = buildResult.task(name) ?: error("Task '$name' not found.")
diff --git a/java/dagger/hilt/android/plugin/src/test/kotlin/IncrementalProcessorTest.kt b/java/dagger/hilt/android/plugin/src/test/kotlin/IncrementalProcessorTest.kt
index cab50aab0..0b60bfe4f 100644
--- a/java/dagger/hilt/android/plugin/src/test/kotlin/IncrementalProcessorTest.kt
+++ b/java/dagger/hilt/android/plugin/src/test/kotlin/IncrementalProcessorTest.kt
@@ -23,13 +23,16 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
/**
* Tests to verify Gradle annotation processor incremental compilation.
*
* To run these tests first deploy artifacts to local maven via util/install-local-snapshot.sh.
*/
-class IncrementalProcessorTest {
+@RunWith(Parameterized::class)
+class IncrementalProcessorTest(private val incapMode: String) {
@get:Rule
val testProjectDir = TemporaryFolder()
@@ -43,6 +46,8 @@ class IncrementalProcessorTest {
private lateinit var srcActivity2: File
private lateinit var srcModule1: File
private lateinit var srcModule2: File
+ private lateinit var srcTest1: File
+ private lateinit var srcTest2: File
// Generated source files
private lateinit var genHiltApp: File
@@ -56,8 +61,15 @@ class IncrementalProcessorTest {
private lateinit var genActivityInjectorDeps2: File
private lateinit var genModuleDeps1: File
private lateinit var genModuleDeps2: File
+ private lateinit var genComponentTreeDeps: File
private lateinit var genHiltComponents: File
private lateinit var genDaggerHiltApplicationComponent: File
+ private lateinit var genTest1ComponentTreeDeps: File
+ private lateinit var genTest2ComponentTreeDeps: File
+ private lateinit var genTest1HiltComponents: File
+ private lateinit var genTest2HiltComponents: File
+ private lateinit var genTest1DaggerHiltApplicationComponent: File
+ private lateinit var genTest2DaggerHiltApplicationComponent: File
// Compiled classes
private lateinit var classSrcApp: File
@@ -65,6 +77,8 @@ class IncrementalProcessorTest {
private lateinit var classSrcActivity2: File
private lateinit var classSrcModule1: File
private lateinit var classSrcModule2: File
+ private lateinit var classSrcTest1: File
+ private lateinit var classSrcTest2: File
private lateinit var classGenHiltApp: File
private lateinit var classGenHiltActivity1: File
private lateinit var classGenHiltActivity2: File
@@ -76,8 +90,15 @@ class IncrementalProcessorTest {
private lateinit var classGenActivityInjectorDeps2: File
private lateinit var classGenModuleDeps1: File
private lateinit var classGenModuleDeps2: File
+ private lateinit var classGenComponentTreeDeps: File
private lateinit var classGenHiltComponents: File
private lateinit var classGenDaggerHiltApplicationComponent: File
+ private lateinit var classGenTest1ComponentTreeDeps: File
+ private lateinit var classGenTest2ComponentTreeDeps: File
+ private lateinit var classGenTest1HiltComponents: File
+ private lateinit var classGenTest2HiltComponents: File
+ private lateinit var classGenTest1DaggerHiltApplicationComponent: File
+ private lateinit var classGenTest2DaggerHiltApplicationComponent: File
// Timestamps of files
private lateinit var fileToTimestampMap: Map<File, Long>
@@ -87,6 +108,19 @@ class IncrementalProcessorTest {
private lateinit var unchangedFiles: Set<File>
private lateinit var deletedFiles: Set<File>
+ private val compileTaskName = if (incapMode == ISOLATING_MODE) {
+ ":hiltJavaCompileDebug"
+ } else {
+ ":compileDebugJavaWithJavac"
+ }
+ private val testCompileTaskName = if (incapMode == ISOLATING_MODE) {
+ ":hiltJavaCompileDebugUnitTest"
+ } else {
+ ":compileDebugUnitTestJavaWithJavac"
+ }
+ private val aggregatingTaskName = ":hiltAggregateDepsDebug"
+ private val testAggregatingTaskName = ":hiltAggregateDepsDebugUnitTest"
+
@Before
fun setup() {
val projectRoot = testProjectDir.root
@@ -99,15 +133,16 @@ class IncrementalProcessorTest {
buildscript {
repositories {
google()
- jcenter()
+ mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.5.3'
+ classpath 'com.android.tools.build:gradle:4.2.0'
}
}
plugins {
id 'com.android.application'
+ id 'dagger.hilt.android.plugin'
}
android {
@@ -118,6 +153,11 @@ class IncrementalProcessorTest {
applicationId "hilt.simple"
minSdkVersion 21
targetSdkVersion 30
+ javaCompileOptions {
+ annotationProcessorOptions {
+ arguments += ["dagger.hilt.shareTestComponents" : "true"]
+ }
+ }
}
compileOptions {
@@ -129,7 +169,7 @@ class IncrementalProcessorTest {
repositories {
mavenLocal()
google()
- jcenter()
+ mavenCentral()
}
dependencies {
@@ -138,84 +178,194 @@ class IncrementalProcessorTest {
annotationProcessor 'com.google.dagger:dagger-compiler:LOCAL-SNAPSHOT'
implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
annotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
+
+ testImplementation 'junit:junit:4.12'
+ testImplementation 'androidx.test.ext:junit:1.1.2'
+ testImplementation 'androidx.test:runner:1.3.0'
+ testImplementation 'org.robolectric:robolectric:4.4'
+ testImplementation 'com.google.dagger:hilt-android-testing:LOCAL-SNAPSHOT'
+ testAnnotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
+ }
+
+ hilt {
+ enableAggregatingTask = ${if (incapMode == ISOLATING_MODE) "true" else "false"}
}
""".trimIndent()
)
+ // Compute directory paths
+ val defaultGenSrcDir = "build/generated/ap_generated_sources/debug/out/"
+ val testDefaultGenSrcDir = "build/generated/ap_generated_sources/debugUnitTest/out/"
+ fun getComponentTreeDepsGenSrcDir(variant: String) = if (incapMode == ISOLATING_MODE) {
+ "build/generated/hilt/component_trees/$variant/"
+ } else {
+ "build/generated/ap_generated_sources/$variant/out/"
+ }
+ val componentTreeDepsGenSrcDir = getComponentTreeDepsGenSrcDir("debug")
+ val testComponentTreeDepsGenSrcDir = getComponentTreeDepsGenSrcDir("debugUnitTest")
+ fun getRootGenSrcDir(variant: String) = if (incapMode == ISOLATING_MODE) {
+ "build/generated/hilt/component_sources/$variant/"
+ } else {
+ "build/generated/ap_generated_sources/$variant/out/"
+ }
+ val rootGenSrcDir = getRootGenSrcDir("debug")
+ val testRootGenSrcDir = getRootGenSrcDir("debugUnitTest")
+ val defaultClassesDir = "build/intermediates/javac/debug/classes"
+ val testDefaultClassesDir = "build/intermediates/javac/debugUnitTest/classes"
+ fun getRootClassesDir(variant: String) = if (incapMode == ISOLATING_MODE) {
+ "build/intermediates/hilt/component_classes/$variant/"
+ } else {
+ "build/intermediates/javac/$variant/classes"
+ }
+ val rootClassesDir = getRootClassesDir("debug")
+ val testRootClassesDir = getRootClassesDir("debugUnitTest")
+
// Compute file paths
- srcApp = File(projectRoot, "$SRC_DIR/simple/SimpleApp.java")
- srcActivity1 = File(projectRoot, "$SRC_DIR/simple/Activity1.java")
- srcActivity2 = File(projectRoot, "$SRC_DIR/simple/Activity2.java")
- srcModule1 = File(projectRoot, "$SRC_DIR/simple/Module1.java")
- srcModule2 = File(projectRoot, "$SRC_DIR/simple/Module2.java")
-
- genHiltApp = File(projectRoot, "$GEN_SRC_DIR/simple/Hilt_SimpleApp.java")
- genHiltActivity1 = File(projectRoot, "$GEN_SRC_DIR/simple/Hilt_Activity1.java")
- genHiltActivity2 = File(projectRoot, "$GEN_SRC_DIR/simple/Hilt_Activity2.java")
- genAppInjector = File(projectRoot, "$GEN_SRC_DIR/simple/SimpleApp_GeneratedInjector.java")
- genActivityInjector1 = File(projectRoot, "$GEN_SRC_DIR/simple/Activity1_GeneratedInjector.java")
- genActivityInjector2 = File(projectRoot, "$GEN_SRC_DIR/simple/Activity2_GeneratedInjector.java")
+ srcApp = File(projectRoot, "$MAIN_SRC_DIR/simple/SimpleApp.java")
+ srcActivity1 = File(projectRoot, "$MAIN_SRC_DIR/simple/Activity1.java")
+ srcActivity2 = File(projectRoot, "$MAIN_SRC_DIR/simple/Activity2.java")
+ srcModule1 = File(projectRoot, "$MAIN_SRC_DIR/simple/Module1.java")
+ srcModule2 = File(projectRoot, "$MAIN_SRC_DIR/simple/Module2.java")
+ srcTest1 = File(projectRoot, "$TEST_SRC_DIR/simple/Test1.java")
+ srcTest2 = File(projectRoot, "$TEST_SRC_DIR/simple/Test2.java")
+
+ genHiltApp = File(projectRoot, "$rootGenSrcDir/simple/Hilt_SimpleApp.java")
+ genHiltActivity1 = File(projectRoot, "$defaultGenSrcDir/simple/Hilt_Activity1.java")
+ genHiltActivity2 = File(projectRoot, "$defaultGenSrcDir/simple/Hilt_Activity2.java")
+ genAppInjector = File(projectRoot, "$defaultGenSrcDir/simple/SimpleApp_GeneratedInjector.java")
+ genActivityInjector1 =
+ File(projectRoot, "$defaultGenSrcDir/simple/Activity1_GeneratedInjector.java")
+ genActivityInjector2 =
+ File(projectRoot, "$defaultGenSrcDir/simple/Activity2_GeneratedInjector.java")
genAppInjectorDeps = File(
projectRoot,
- "$GEN_SRC_DIR/hilt_aggregated_deps/_simple_SimpleApp_GeneratedInjector.java"
+ "$defaultGenSrcDir/hilt_aggregated_deps/_simple_SimpleApp_GeneratedInjector.java"
)
genActivityInjectorDeps1 = File(
projectRoot,
- "$GEN_SRC_DIR/hilt_aggregated_deps/_simple_Activity1_GeneratedInjector.java"
+ "$defaultGenSrcDir/hilt_aggregated_deps/_simple_Activity1_GeneratedInjector.java"
)
genActivityInjectorDeps2 = File(
projectRoot,
- "$GEN_SRC_DIR/hilt_aggregated_deps/_simple_Activity2_GeneratedInjector.java"
+ "$defaultGenSrcDir/hilt_aggregated_deps/_simple_Activity2_GeneratedInjector.java"
)
genModuleDeps1 = File(
projectRoot,
- "$GEN_SRC_DIR/hilt_aggregated_deps/_simple_Module1.java"
+ "$defaultGenSrcDir/hilt_aggregated_deps/_simple_Module1.java"
)
- genModuleDeps2 = File(projectRoot, "$GEN_SRC_DIR/hilt_aggregated_deps/_simple_Module2.java")
- genHiltComponents = File(projectRoot, "$GEN_SRC_DIR/simple/SimpleApp_HiltComponents.java")
+ genModuleDeps2 =
+ File(projectRoot, "$defaultGenSrcDir/hilt_aggregated_deps/_simple_Module2.java")
+ genComponentTreeDeps =
+ File(projectRoot, "$componentTreeDepsGenSrcDir/simple/SimpleApp_ComponentTreeDeps.java")
+ genHiltComponents = File(projectRoot, "$rootGenSrcDir/simple/SimpleApp_HiltComponents.java")
genDaggerHiltApplicationComponent = File(
projectRoot,
- "$GEN_SRC_DIR/simple/DaggerSimpleApp_HiltComponents_SingletonC.java"
- )
-
- classSrcApp = File(projectRoot, "$CLASS_DIR/simple/SimpleApp.class")
- classSrcActivity1 = File(projectRoot, "$CLASS_DIR/simple/Activity1.class")
- classSrcActivity2 = File(projectRoot, "$CLASS_DIR/simple/Activity2.class")
- classSrcModule1 = File(projectRoot, "$CLASS_DIR/simple/Module1.class")
- classSrcModule2 = File(projectRoot, "$CLASS_DIR/simple/Module2.class")
- classGenHiltApp = File(projectRoot, "$CLASS_DIR/simple/Hilt_SimpleApp.class")
- classGenHiltActivity1 = File(projectRoot, "$CLASS_DIR/simple/Hilt_Activity1.class")
- classGenHiltActivity2 = File(projectRoot, "$CLASS_DIR/simple/Hilt_Activity2.class")
- classGenAppInjector = File(projectRoot, "$CLASS_DIR/simple/SimpleApp_GeneratedInjector.class")
+ "$rootGenSrcDir/simple/DaggerSimpleApp_HiltComponents_SingletonC.java"
+ )
+ genTest1ComponentTreeDeps = File(
+ projectRoot,
+ testComponentTreeDepsGenSrcDir +
+ "/dagger/hilt/android/internal/testing/root/Test1_ComponentTreeDeps.java"
+ )
+ genTest2ComponentTreeDeps = File(
+ projectRoot,
+ testComponentTreeDepsGenSrcDir +
+ "/dagger/hilt/android/internal/testing/root/Test2_ComponentTreeDeps.java"
+ )
+ genTest1HiltComponents = File(
+ projectRoot,
+ "$testRootGenSrcDir/dagger/hilt/android/internal/testing/root/Test1_HiltComponents.java"
+ )
+ genTest2HiltComponents = File(
+ projectRoot,
+ "$testRootGenSrcDir/dagger/hilt/android/internal/testing/root/Test2_HiltComponents.java"
+ )
+ genTest1DaggerHiltApplicationComponent = File(
+ projectRoot,
+ testRootGenSrcDir +
+ "/dagger/hilt/android/internal/testing/root/DaggerTest1_HiltComponents_SingletonC.java"
+ )
+ genTest2DaggerHiltApplicationComponent = File(
+ projectRoot,
+ testRootGenSrcDir +
+ "/dagger/hilt/android/internal/testing/root/DaggerTest2_HiltComponents_SingletonC.java"
+ )
+
+ classSrcApp = File(projectRoot, "$defaultClassesDir/simple/SimpleApp.class")
+ classSrcActivity1 = File(projectRoot, "$defaultClassesDir/simple/Activity1.class")
+ classSrcActivity2 = File(projectRoot, "$defaultClassesDir/simple/Activity2.class")
+ classSrcModule1 = File(projectRoot, "$defaultClassesDir/simple/Module1.class")
+ classSrcModule2 = File(projectRoot, "$defaultClassesDir/simple/Module2.class")
+ classSrcTest1 = File(projectRoot, "$testDefaultClassesDir/simple/Test1.class")
+ classSrcTest2 = File(projectRoot, "$testDefaultClassesDir/simple/Test2.class")
+ classGenHiltApp = File(projectRoot, "$rootClassesDir/simple/Hilt_SimpleApp.class")
+ classGenHiltActivity1 = File(projectRoot, "$defaultClassesDir/simple/Hilt_Activity1.class")
+ classGenHiltActivity2 = File(projectRoot, "$defaultClassesDir/simple/Hilt_Activity2.class")
+ classGenAppInjector =
+ File(projectRoot, "$defaultClassesDir/simple/SimpleApp_GeneratedInjector.class")
classGenActivityInjector1 = File(
projectRoot,
- "$CLASS_DIR/simple/Activity1_GeneratedInjector.class"
+ "$defaultClassesDir/simple/Activity1_GeneratedInjector.class"
)
classGenActivityInjector2 = File(
projectRoot,
- "$CLASS_DIR/simple/Activity2_GeneratedInjector.class"
+ "$defaultClassesDir/simple/Activity2_GeneratedInjector.class"
)
classGenAppInjectorDeps = File(
projectRoot,
- "$CLASS_DIR/hilt_aggregated_deps/_simple_SimpleApp_GeneratedInjector.class"
+ "$defaultClassesDir/hilt_aggregated_deps/_simple_SimpleApp_GeneratedInjector.class"
)
classGenActivityInjectorDeps1 = File(
projectRoot,
- "$CLASS_DIR/hilt_aggregated_deps/_simple_Activity1_GeneratedInjector.class"
+ "$defaultClassesDir/hilt_aggregated_deps/_simple_Activity1_GeneratedInjector.class"
)
classGenActivityInjectorDeps2 = File(
projectRoot,
- "$CLASS_DIR/hilt_aggregated_deps/_simple_Activity2_GeneratedInjector.class"
+ "$defaultClassesDir/hilt_aggregated_deps/_simple_Activity2_GeneratedInjector.class"
+ )
+ classGenModuleDeps1 =
+ File(projectRoot, "$defaultClassesDir/hilt_aggregated_deps/_simple_Module1.class")
+ classGenModuleDeps2 =
+ File(projectRoot, "$defaultClassesDir/hilt_aggregated_deps/_simple_Module2.class")
+ classGenComponentTreeDeps = File(
+ projectRoot,
+ "$rootClassesDir/simple/SimpleApp_ComponentTreeDeps.class"
)
- classGenModuleDeps1 = File(projectRoot, "$CLASS_DIR/hilt_aggregated_deps/_simple_Module1.class")
- classGenModuleDeps2 = File(projectRoot, "$CLASS_DIR/hilt_aggregated_deps/_simple_Module2.class")
classGenHiltComponents = File(
projectRoot,
- "$CLASS_DIR/simple/SimpleApp_HiltComponents.class"
+ "$rootClassesDir/simple/SimpleApp_HiltComponents.class"
)
classGenDaggerHiltApplicationComponent = File(
projectRoot,
- "$CLASS_DIR/simple/DaggerSimpleApp_HiltComponents_SingletonC.class"
+ "$rootClassesDir/simple/DaggerSimpleApp_HiltComponents_SingletonC.class"
+ )
+ classGenTest1ComponentTreeDeps = File(
+ projectRoot,
+ testRootClassesDir +
+ "/dagger/hilt/android/internal/testing/root/Test1_ComponentTreeDeps.class"
+ )
+ classGenTest2ComponentTreeDeps = File(
+ projectRoot,
+ testRootClassesDir +
+ "/dagger/hilt/android/internal/testing/root/Test2_ComponentTreeDeps.class"
+ )
+ classGenTest1HiltComponents = File(
+ projectRoot,
+ "$testRootClassesDir/dagger/hilt/android/internal/testing/root/Test1_HiltComponents.class"
+ )
+ classGenTest2HiltComponents = File(
+ projectRoot,
+ "$testRootClassesDir/dagger/hilt/android/internal/testing/root/Test2_HiltComponents.class"
+ )
+ classGenTest1DaggerHiltApplicationComponent = File(
+ projectRoot,
+ testRootClassesDir +
+ "/dagger/hilt/android/internal/testing/root/DaggerTest1_HiltComponents_SingletonC.class"
+ )
+ classGenTest2DaggerHiltApplicationComponent = File(
+ projectRoot,
+ testRootClassesDir +
+ "/dagger/hilt/android/internal/testing/root/DaggerTest2_HiltComponents_SingletonC.class"
)
}
@@ -224,51 +374,58 @@ class IncrementalProcessorTest {
// This test verifies the results of the first full (non-incremental) build. The other tests
// verify the results of the second incremental build based on different change scenarios.
val result = runFullBuild()
- expect.that(result.task(COMPILE_TASK)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
+ expect.that(result.task(compileTaskName)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
// Check annotation processing outputs
assertFilesExist(
- genHiltApp,
- genHiltActivity1,
- genHiltActivity2,
- genAppInjector,
- genActivityInjector1,
- genActivityInjector2,
- genAppInjectorDeps,
- genActivityInjectorDeps1,
- genActivityInjectorDeps2,
- genModuleDeps1,
- genModuleDeps2,
- genHiltComponents,
- genDaggerHiltApplicationComponent
+ listOf(
+ genHiltApp,
+ genHiltActivity1,
+ genHiltActivity2,
+ genAppInjector,
+ genActivityInjector1,
+ genActivityInjector2,
+ genAppInjectorDeps,
+ genActivityInjectorDeps1,
+ genActivityInjectorDeps2,
+ genModuleDeps1,
+ genModuleDeps2,
+ genComponentTreeDeps,
+ genHiltComponents,
+ genDaggerHiltApplicationComponent
+ )
)
// Check compilation outputs
assertFilesExist(
- classSrcApp,
- classSrcActivity1,
- classSrcActivity2,
- classSrcModule1,
- classSrcModule2,
- classGenHiltApp,
- classGenHiltActivity1,
- classGenHiltActivity2,
- classGenAppInjector,
- classGenActivityInjector1,
- classGenActivityInjector2,
- classGenAppInjectorDeps,
- classGenActivityInjectorDeps1,
- classGenActivityInjectorDeps2,
- classGenModuleDeps1,
- classGenModuleDeps2,
- classGenHiltComponents,
- classGenDaggerHiltApplicationComponent
+ listOf(
+ classSrcApp,
+ classSrcActivity1,
+ classSrcActivity2,
+ classSrcModule1,
+ classSrcModule2,
+ classGenHiltApp,
+ classGenHiltActivity1,
+ classGenHiltActivity2,
+ classGenAppInjector,
+ classGenActivityInjector1,
+ classGenActivityInjector2,
+ classGenAppInjectorDeps,
+ classGenActivityInjectorDeps1,
+ classGenActivityInjectorDeps2,
+ classGenModuleDeps1,
+ classGenModuleDeps2,
+ classGenComponentTreeDeps,
+ classGenHiltComponents,
+ classGenDaggerHiltApplicationComponent
+ )
)
}
@Test
- fun changeActivitySource() {
+ fun changeActivitySource_addPublicMethod() {
runFullBuild()
+ val componentTreeDepsFullBuild = genComponentTreeDeps.readText(Charsets.UTF_8)
// Change Activity 1 source
searchAndReplace(
@@ -282,43 +439,158 @@ class IncrementalProcessorTest {
)
val result = runIncrementalBuild()
- expect.that(result.task(COMPILE_TASK)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
+ expect.that(result.task(compileTaskName)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
// Check annotation processing outputs
// * Only activity 1 sources are re-generated, isolation in modules and from other activities
- // * Root classes along with components are always re-generated (aggregated processor)
- assertChangedFiles(
- FileType.JAVA,
- genHiltApp,
- genHiltActivity1,
- genAppInjector,
- genActivityInjector1,
- genAppInjectorDeps,
- genActivityInjectorDeps1,
- genHiltComponents,
- genDaggerHiltApplicationComponent
- )
+ val regeneratedSourceFiles = if (incapMode == ISOLATING_MODE) {
+ // * Aggregating task did not run, no change in deps
+ expect.that(result.task(aggregatingTaskName)!!.outcome).isEqualTo(TaskOutcome.UP_TO_DATE)
+ // * Components are re-generated due to a recompilation of a dep
+ listOf(
+ genHiltApp, // Re-gen because components got re-gen
+ genHiltActivity1,
+ genActivityInjector1,
+ genActivityInjectorDeps1,
+ genHiltComponents,
+ genDaggerHiltApplicationComponent
+ )
+ } else {
+ // * Root classes along with components are always re-generated (aggregated processor)
+ listOf(
+ genHiltApp,
+ genHiltActivity1,
+ genAppInjector,
+ genActivityInjector1,
+ genAppInjectorDeps,
+ genActivityInjectorDeps1,
+ genComponentTreeDeps,
+ genHiltComponents,
+ genDaggerHiltApplicationComponent
+ )
+ }
+ assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
+
+ val componentTreeDepsIncrementalBuild = genComponentTreeDeps.readText(Charsets.UTF_8)
+ expect.withMessage("Full build")
+ .that(componentTreeDepsFullBuild)
+ .isEqualTo(componentTreeDepsIncrementalBuild)
// Check compilation outputs
// * Gen sources from activity 1 are re-compiled
- // * All aggregating processor gen sources are re-compiled
- assertChangedFiles(
- FileType.CLASS,
- classSrcActivity1,
- classGenHiltApp,
- classGenHiltActivity1,
- classGenAppInjector,
- classGenActivityInjector1,
- classGenAppInjectorDeps,
- classGenActivityInjectorDeps1,
- classGenHiltComponents,
- classGenDaggerHiltApplicationComponent
+ val recompiledClassFiles = if (incapMode == ISOLATING_MODE) {
+ listOf(
+ classSrcActivity1,
+ classGenHiltApp,
+ classGenHiltActivity1,
+ classGenActivityInjector1,
+ classGenActivityInjectorDeps1,
+ classGenComponentTreeDeps, // Re-compiled because reference to activity injector
+ classGenHiltComponents,
+ classGenDaggerHiltApplicationComponent,
+ )
+ } else {
+ // * All aggregating processor gen sources are re-compiled
+ listOf(
+ classSrcActivity1,
+ classGenHiltApp,
+ classGenHiltActivity1,
+ classGenAppInjector,
+ classGenActivityInjector1,
+ classGenAppInjectorDeps,
+ classGenActivityInjectorDeps1,
+ classGenComponentTreeDeps,
+ classGenHiltComponents,
+ classGenDaggerHiltApplicationComponent
+ )
+ }
+ assertChangedFiles(FileType.CLASS, recompiledClassFiles)
+ }
+
+ @Test
+ fun changeActivitySource_addPrivateMethod() {
+ runFullBuild()
+ val componentTreeDepsFullBuild = genComponentTreeDeps.readText(Charsets.UTF_8)
+
+ // Change Activity 1 source
+ searchAndReplace(
+ srcActivity1, "// Insert-change",
+ """
+ private void foo() { }
+ """.trimIndent()
)
+
+ val result = runIncrementalBuild()
+ val expectedOutcome = if (incapMode == ISOLATING_MODE) {
+ // In isolating mode, changes that do not affect ABI will not cause re-compilation.
+ TaskOutcome.UP_TO_DATE
+ } else {
+ TaskOutcome.SUCCESS
+ }
+ expect.that(result.task(compileTaskName)!!.outcome).isEqualTo(expectedOutcome)
+
+ // Check annotation processing outputs
+ // * Only activity 1 sources are re-generated, isolation in modules and from other activities
+ val regeneratedSourceFiles = if (incapMode == ISOLATING_MODE) {
+ // * Aggregating task did not run, no change in deps
+ expect.that(result.task(aggregatingTaskName)!!.outcome).isEqualTo(TaskOutcome.UP_TO_DATE)
+ listOf(
+ genHiltActivity1,
+ genActivityInjector1,
+ genActivityInjectorDeps1,
+ )
+ } else {
+ // * Root classes along with components are always re-generated (aggregated processor)
+ listOf(
+ genHiltApp,
+ genHiltActivity1,
+ genAppInjector,
+ genActivityInjector1,
+ genAppInjectorDeps,
+ genActivityInjectorDeps1,
+ genComponentTreeDeps,
+ genHiltComponents,
+ genDaggerHiltApplicationComponent
+ )
+ }
+ assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
+
+ val componentTreeDepsIncrementalBuild = genComponentTreeDeps.readText(Charsets.UTF_8)
+ expect.withMessage("Full build")
+ .that(componentTreeDepsFullBuild)
+ .isEqualTo(componentTreeDepsIncrementalBuild)
+
+ // Check compilation outputs
+ // * Gen sources from activity 1 are re-compiled
+ val recompiledClassFiles = if (incapMode == ISOLATING_MODE) {
+ listOf(
+ classSrcActivity1,
+ classGenHiltActivity1,
+ classGenActivityInjector1,
+ classGenActivityInjectorDeps1
+ )
+ } else {
+ // * All aggregating processor gen sources are re-compiled
+ listOf(
+ classSrcActivity1,
+ classGenHiltApp,
+ classGenHiltActivity1,
+ classGenAppInjector,
+ classGenActivityInjector1,
+ classGenAppInjectorDeps,
+ classGenActivityInjectorDeps1,
+ classGenComponentTreeDeps,
+ classGenHiltComponents,
+ classGenDaggerHiltApplicationComponent
+ )
+ }
+ assertChangedFiles(FileType.CLASS, recompiledClassFiles)
}
@Test
fun changeModuleSource() {
runFullBuild()
+ val componentTreeDepsFullBuild = genComponentTreeDeps.readText(Charsets.UTF_8)
// Change Module 1 source
searchAndReplace(
@@ -332,39 +604,70 @@ class IncrementalProcessorTest {
)
val result = runIncrementalBuild()
- expect.that(result.task(COMPILE_TASK)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
+ expect.that(result.task(compileTaskName)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
// Check annotation processing outputs
// * Only module 1 sources are re-generated, isolation from other modules
- // * Root classes along with components are always re-generated (aggregated processor)
- assertChangedFiles(
- FileType.JAVA,
- genHiltApp,
- genAppInjector,
- genAppInjectorDeps,
- genModuleDeps1,
- genHiltComponents,
- genDaggerHiltApplicationComponent
- )
+ val regeneratedSourceFiles = if (incapMode == ISOLATING_MODE) {
+ // * Aggregating task did not run, no change in deps
+ expect.that(result.task(aggregatingTaskName)!!.outcome).isEqualTo(TaskOutcome.UP_TO_DATE)
+ // * Components are re-generated due to a recompilation of a dep
+ listOf(
+ genHiltApp, // Re-generated because components got re-generated
+ genModuleDeps1,
+ genHiltComponents,
+ genDaggerHiltApplicationComponent
+ )
+ } else {
+ // * Root classes along with components are always re-generated (aggregated processor)
+ listOf(
+ genHiltApp,
+ genAppInjector,
+ genAppInjectorDeps,
+ genModuleDeps1,
+ genComponentTreeDeps,
+ genHiltComponents,
+ genDaggerHiltApplicationComponent
+ )
+ }
+ assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
+
+ val componentTreeDepsIncrementalBuild = genComponentTreeDeps.readText(Charsets.UTF_8)
+ expect.withMessage("Full build")
+ .that(componentTreeDepsFullBuild)
+ .isEqualTo(componentTreeDepsIncrementalBuild)
// Check compilation outputs
// * Gen sources from module 1 are re-compiled
- // * All aggregating processor gen sources are re-compiled
- assertChangedFiles(
- FileType.CLASS,
- classSrcModule1,
- classGenHiltApp,
- classGenAppInjector,
- classGenAppInjectorDeps,
- classGenModuleDeps1,
- classGenHiltComponents,
- classGenDaggerHiltApplicationComponent
- )
+ val recompiledClassFiles = if (incapMode == ISOLATING_MODE) {
+ listOf(
+ classSrcModule1,
+ classGenHiltApp,
+ classGenModuleDeps1,
+ classGenComponentTreeDeps,
+ classGenHiltComponents,
+ classGenDaggerHiltApplicationComponent
+ )
+ } else {
+ // * All aggregating processor gen sources are re-compiled
+ listOf(
+ classSrcModule1,
+ classGenHiltApp,
+ classGenAppInjector,
+ classGenAppInjectorDeps,
+ classGenModuleDeps1,
+ classGenComponentTreeDeps,
+ classGenHiltComponents,
+ classGenDaggerHiltApplicationComponent
+ )
+ }
+ assertChangedFiles(FileType.CLASS, recompiledClassFiles)
}
@Test
fun changeAppSource() {
runFullBuild()
+ val componentTreeDepsFullBuild = genComponentTreeDeps.readText(Charsets.UTF_8)
// Change Application source
searchAndReplace(
@@ -378,31 +681,63 @@ class IncrementalProcessorTest {
)
val result = runIncrementalBuild()
- expect.that(result.task(COMPILE_TASK)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
+ expect.that(result.task(compileTaskName)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
// Check annotation processing outputs
// * No modules or activities (or any other non-root) classes should be generated
- // * Root classes along with components are always re-generated (aggregated processor)
- assertChangedFiles(
- FileType.JAVA,
- genHiltApp,
- genAppInjector,
- genAppInjectorDeps,
- genHiltComponents,
- genDaggerHiltApplicationComponent
- )
+ val regeneratedSourceFiles = if (incapMode == ISOLATING_MODE) {
+ // * Aggregating task did not run, no change in deps
+ expect.that(result.task(aggregatingTaskName)!!.outcome).isEqualTo(TaskOutcome.UP_TO_DATE)
+ // * Components are re-generated due to a recompilation of a dep
+ listOf(
+ genHiltApp, // Re-generated because components got re-generated
+ genAppInjector,
+ genAppInjectorDeps,
+ genHiltComponents,
+ genDaggerHiltApplicationComponent
+ )
+ } else {
+ // * Root classes along with components are always re-generated (aggregated processor)
+ listOf(
+ genHiltApp,
+ genAppInjector,
+ genAppInjectorDeps,
+ genComponentTreeDeps,
+ genHiltComponents,
+ genDaggerHiltApplicationComponent
+ )
+ }
+ assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
+
+ val componentTreeDepsIncrementalBuild = genComponentTreeDeps.readText(Charsets.UTF_8)
+ expect.withMessage("Full build")
+ .that(componentTreeDepsFullBuild)
+ .isEqualTo(componentTreeDepsIncrementalBuild)
// Check compilation outputs
- // * All aggregating processor gen sources are re-compiled
- assertChangedFiles(
- FileType.CLASS,
- classSrcApp, // re-compiles because superclass re-compiled
- classGenHiltApp,
- classGenAppInjector,
- classGenAppInjectorDeps,
- classGenHiltComponents,
- classGenDaggerHiltApplicationComponent
- )
+ val recompiledClassFiles = if (incapMode == ISOLATING_MODE) {
+ listOf(
+ classSrcApp,
+ classGenHiltApp,
+ classGenAppInjector,
+ classGenAppInjectorDeps,
+ classGenComponentTreeDeps,
+ classGenHiltComponents,
+ classGenDaggerHiltApplicationComponent
+ )
+ } else {
+ // * All aggregating processor gen sources are re-compiled
+ listOf(
+ classSrcApp,
+ classGenHiltApp,
+ classGenAppInjector,
+ classGenAppInjectorDeps,
+ classGenComponentTreeDeps,
+ classGenHiltComponents,
+ classGenDaggerHiltApplicationComponent
+ )
+ }
+ assertChangedFiles(FileType.CLASS, recompiledClassFiles)
}
@Test
@@ -412,43 +747,70 @@ class IncrementalProcessorTest {
srcActivity2.delete()
val result = runIncrementalBuild()
- expect.that(result.task(COMPILE_TASK)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
+ expect.that(result.task(compileTaskName)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
// Check annotation processing outputs
// * All related gen classes from activity 2 should be deleted
// * Unrelated activities and modules are in isolation and should be unchanged
// * Root classes along with components are always re-generated (aggregated processor)
assertDeletedFiles(
- genHiltActivity2,
- genActivityInjector2,
- genActivityInjectorDeps2
- )
- assertChangedFiles(
- FileType.JAVA,
- genHiltApp,
- genAppInjector,
- genAppInjectorDeps,
- genHiltComponents,
- genDaggerHiltApplicationComponent
+ listOf(
+ genHiltActivity2,
+ genActivityInjector2,
+ genActivityInjectorDeps2
+ )
)
+ val regeneratedSourceFiles = if (incapMode == ISOLATING_MODE) {
+ // * Aggregating task ran due to a change in dep
+ expect.that(result.task(aggregatingTaskName)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
+ // * Components are re-generated since there was a change in dep
+ listOf(
+ genHiltApp, // Re-generated because components got re-generated
+ genComponentTreeDeps,
+ genHiltComponents,
+ genDaggerHiltApplicationComponent
+ )
+ } else {
+ listOf(
+ genHiltApp,
+ genAppInjector,
+ genAppInjectorDeps,
+ genComponentTreeDeps,
+ genHiltComponents,
+ genDaggerHiltApplicationComponent
+ )
+ }
+ assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
// Check compilation outputs
// * All compiled classes from activity 2 should be deleted
// * Unrelated activities and modules are in isolation and should be unchanged
assertDeletedFiles(
- classSrcActivity2,
- classGenHiltActivity2,
- classGenActivityInjector2,
- classGenActivityInjectorDeps2
- )
- assertChangedFiles(
- FileType.CLASS,
- classGenHiltApp,
- classGenAppInjector,
- classGenAppInjectorDeps,
- classGenHiltComponents,
- classGenDaggerHiltApplicationComponent
+ listOf(
+ classSrcActivity2,
+ classGenHiltActivity2,
+ classGenActivityInjector2,
+ classGenActivityInjectorDeps2
+ )
)
+ val recompiledClassFiles = if (incapMode == ISOLATING_MODE) {
+ listOf(
+ classGenHiltApp,
+ classGenComponentTreeDeps,
+ classGenHiltComponents,
+ classGenDaggerHiltApplicationComponent
+ )
+ } else {
+ listOf(
+ classGenHiltApp,
+ classGenAppInjector,
+ classGenAppInjectorDeps,
+ classGenComponentTreeDeps,
+ classGenHiltComponents,
+ classGenDaggerHiltApplicationComponent
+ )
+ }
+ assertChangedFiles(FileType.CLASS, recompiledClassFiles)
}
@Test
@@ -458,39 +820,277 @@ class IncrementalProcessorTest {
srcModule2.delete()
val result = runIncrementalBuild()
- expect.that(result.task(COMPILE_TASK)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
+ expect.that(result.task(compileTaskName)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
// Check annotation processing outputs
// * All related gen classes from module 2 should be deleted
// * Unrelated activities and modules are in isolation and should be unchanged
- // * Root classes along with components are always re-generated (aggregated processor)
+
assertDeletedFiles(
- genModuleDeps2
- )
- assertChangedFiles(
- FileType.JAVA,
- genHiltApp,
- genAppInjector,
- genAppInjectorDeps,
- genHiltComponents,
- genDaggerHiltApplicationComponent
+ listOf(genModuleDeps2)
)
+ val regeneratedSourceFiles = if (incapMode == ISOLATING_MODE) {
+ // * Aggregating task ran due to a change in dep
+ expect.that(result.task(aggregatingTaskName)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
+ // * Components are re-generated since there was a change in dep
+ listOf(
+ genHiltApp, // Re-generated because components got re-generated
+ genComponentTreeDeps,
+ genHiltComponents,
+ genDaggerHiltApplicationComponent
+ )
+ } else {
+ // * Root classes along with components are always re-generated (aggregated processor)
+ listOf(
+ genHiltApp,
+ genAppInjector,
+ genAppInjectorDeps,
+ genComponentTreeDeps,
+ genHiltComponents,
+ genDaggerHiltApplicationComponent
+ )
+ }
+ assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
// Check compilation outputs
// * All compiled classes from module 2 should be deleted
// * Unrelated activities and modules are in isolation and should be unchanged
assertDeletedFiles(
- classSrcModule2,
- classGenModuleDeps2
+ listOf(
+ classSrcModule2,
+ classGenModuleDeps2
+ )
)
- assertChangedFiles(
- FileType.CLASS,
- classGenHiltApp,
- classGenAppInjector,
- classGenAppInjectorDeps,
- classGenHiltComponents,
- classGenDaggerHiltApplicationComponent
+ val recompiledClassFiles = if (incapMode == ISOLATING_MODE) {
+ listOf(
+ classGenHiltApp,
+ classGenComponentTreeDeps,
+ classGenHiltComponents,
+ classGenDaggerHiltApplicationComponent
+ )
+ } else {
+ listOf(
+ classGenHiltApp,
+ classGenAppInjector,
+ classGenAppInjectorDeps,
+ classGenComponentTreeDeps,
+ classGenHiltComponents,
+ classGenDaggerHiltApplicationComponent
+ )
+ }
+ assertChangedFiles(FileType.CLASS, recompiledClassFiles)
+ }
+
+ @Test
+ fun addNewSource() {
+ runFullBuild()
+
+ val newSource = File(testProjectDir.root, "$MAIN_SRC_DIR/simple/Foo.java")
+ newSource.writeText(
+ """
+ package simple;
+
+ public class Foo { }
+ """.trimIndent()
)
+
+ val result = runIncrementalBuild()
+ val expectedOutcome = if (incapMode == ISOLATING_MODE) {
+ // In isolating mode, component compile task does not re-compile.
+ TaskOutcome.UP_TO_DATE
+ } else {
+ TaskOutcome.SUCCESS
+ }
+ expect.that(result.task(compileTaskName)!!.outcome).isEqualTo(expectedOutcome)
+
+ val regeneratedSourceFiles = if (incapMode == ISOLATING_MODE) {
+ // * Aggregating task did not run, no change in deps
+ expect.that(result.task(aggregatingTaskName)!!.outcome).isEqualTo(TaskOutcome.UP_TO_DATE)
+ // * Non-DI related source causes no files to be generated
+ emptyList()
+ } else {
+ // * Root classes are always re-generated (aggregated processor)
+ listOf(
+ genHiltApp,
+ genAppInjector,
+ genAppInjectorDeps,
+ )
+ }
+ assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
+
+ val recompiledClassFiles = if (incapMode == ISOLATING_MODE) {
+ emptyList()
+ } else {
+ listOf(
+ classGenHiltApp,
+ classGenAppInjector,
+ classGenAppInjectorDeps,
+ )
+ }
+ assertChangedFiles(FileType.CLASS, recompiledClassFiles)
+ }
+
+ @Test
+ fun firstTestFullBuild() {
+ val result = runFullTestBuild()
+ expect.that(result.task(testCompileTaskName)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
+
+ assertFilesExist(
+ listOf(
+ genTest1ComponentTreeDeps,
+ genTest2ComponentTreeDeps,
+ genTest1HiltComponents,
+ genTest2HiltComponents,
+ genTest1DaggerHiltApplicationComponent,
+ genTest2DaggerHiltApplicationComponent,
+ )
+ )
+
+ assertFilesExist(
+ listOf(
+ classSrcTest1,
+ classSrcTest2,
+ classGenTest1ComponentTreeDeps,
+ classGenTest2ComponentTreeDeps,
+ classGenTest1HiltComponents,
+ classGenTest2HiltComponents,
+ classGenTest1DaggerHiltApplicationComponent,
+ classGenTest2DaggerHiltApplicationComponent,
+ )
+ )
+ }
+
+ @Test
+ fun changeTestSource_addPublicMethod() {
+ runFullTestBuild()
+ val test1ComponentTreeDepsFullBuild = genTest1ComponentTreeDeps.readText(Charsets.UTF_8)
+ val test2ComponentTreeDepsFullBuild = genTest2ComponentTreeDeps.readText(Charsets.UTF_8)
+
+ // Change Test 1 source
+ searchAndReplace(
+ srcTest1, "// Insert-change",
+ """
+ @Test
+ public void newTest() { }
+ """.trimIndent()
+ )
+
+ val result = runIncrementalTestBuild()
+ expect.that(result.task(testCompileTaskName)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
+
+ // Check annotation processing outputs
+ // * Unrelated test components should be unchanged
+
+ val regeneratedSourceFiles = if (incapMode == ISOLATING_MODE) {
+ listOf(
+ genTest1HiltComponents,
+ genTest1DaggerHiltApplicationComponent,
+ )
+ } else {
+ listOf(
+ genTest1ComponentTreeDeps,
+ genTest2ComponentTreeDeps,
+ genTest1HiltComponents,
+ genTest2HiltComponents,
+ genTest1DaggerHiltApplicationComponent,
+ genTest2DaggerHiltApplicationComponent,
+ )
+ }
+ assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
+
+ val test1ComponentTreeDepsIncrementalBuild = genTest1ComponentTreeDeps.readText(Charsets.UTF_8)
+ val test2ComponentTreeDepsIncrementalBuild = genTest2ComponentTreeDeps.readText(Charsets.UTF_8)
+ expect.withMessage("Full build")
+ .that(test1ComponentTreeDepsFullBuild)
+ .isEqualTo(test1ComponentTreeDepsIncrementalBuild)
+ expect.withMessage("Full build")
+ .that(test2ComponentTreeDepsFullBuild)
+ .isEqualTo(test2ComponentTreeDepsIncrementalBuild)
+
+ val recompiledClassFiles = if (incapMode == ISOLATING_MODE) {
+ listOf(
+ classSrcTest1,
+ classGenTest1ComponentTreeDeps,
+ classGenTest1HiltComponents,
+ classGenTest1DaggerHiltApplicationComponent,
+ )
+ } else {
+ listOf(
+ classSrcTest1,
+ classGenTest1ComponentTreeDeps,
+ classGenTest2ComponentTreeDeps,
+ classGenTest1HiltComponents,
+ classGenTest2HiltComponents,
+ classGenTest1DaggerHiltApplicationComponent,
+ classGenTest2DaggerHiltApplicationComponent,
+ )
+ }
+ assertChangedFiles(FileType.CLASS, recompiledClassFiles)
+ }
+
+ @Test
+ fun changeTestSource_addPrivateMethod() {
+ runFullTestBuild()
+ val test1ComponentTreeDepsFullBuild = genTest1ComponentTreeDeps.readText(Charsets.UTF_8)
+ val test2ComponentTreeDepsFullBuild = genTest2ComponentTreeDeps.readText(Charsets.UTF_8)
+
+ // Change Test 1 source
+ searchAndReplace(
+ srcTest1, "// Insert-change",
+ """
+ private void newMethod() { }
+ """.trimIndent()
+ )
+
+ val result = runIncrementalTestBuild()
+ val expectedOutcome = if (incapMode == ISOLATING_MODE) {
+ // In isolating mode, changes that do not affect ABI will not cause re-compilation.
+ TaskOutcome.UP_TO_DATE
+ } else {
+ TaskOutcome.SUCCESS
+ }
+ expect.that(result.task(testCompileTaskName)!!.outcome).isEqualTo(expectedOutcome)
+
+ // Check annotation processing outputs
+ // * Unrelated test components should be unchanged
+
+ val regeneratedSourceFiles = if (incapMode == ISOLATING_MODE) {
+ emptyList()
+ } else {
+ listOf(
+ genTest1ComponentTreeDeps,
+ genTest2ComponentTreeDeps,
+ genTest1HiltComponents,
+ genTest2HiltComponents,
+ genTest1DaggerHiltApplicationComponent,
+ genTest2DaggerHiltApplicationComponent,
+ )
+ }
+ assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
+
+ val test1ComponentTreeDepsIncrementalBuild = genTest1ComponentTreeDeps.readText(Charsets.UTF_8)
+ val test2ComponentTreeDepsIncrementalBuild = genTest2ComponentTreeDeps.readText(Charsets.UTF_8)
+ expect.withMessage("Full build")
+ .that(test1ComponentTreeDepsFullBuild)
+ .isEqualTo(test1ComponentTreeDepsIncrementalBuild)
+ expect.withMessage("Full build")
+ .that(test2ComponentTreeDepsFullBuild)
+ .isEqualTo(test2ComponentTreeDepsIncrementalBuild)
+
+ val recompiledClassFiles = if (incapMode == ISOLATING_MODE) {
+ listOf(classSrcTest1)
+ } else {
+ listOf(
+ classSrcTest1,
+ classGenTest1ComponentTreeDeps,
+ classGenTest2ComponentTreeDeps,
+ classGenTest1HiltComponents,
+ classGenTest2HiltComponents,
+ classGenTest1DaggerHiltApplicationComponent,
+ classGenTest2DaggerHiltApplicationComponent,
+ )
+ }
+ assertChangedFiles(FileType.CLASS, recompiledClassFiles)
}
private fun runGradleTasks(vararg args: String): BuildResult {
@@ -503,16 +1103,30 @@ class IncrementalProcessorTest {
}
private fun runFullBuild(): BuildResult {
- val result = runGradleTasks(CLEAN_TASK, COMPILE_TASK)
+ val result = runGradleTasks(CLEAN_TASK, compileTaskName)
+ recordTimestamps()
+ return result
+ }
+
+ private fun runFullTestBuild(): BuildResult {
+ runFullBuild()
+ val result = runIncrementalTestBuild()
recordTimestamps()
return result
}
private fun runIncrementalBuild(): BuildResult {
- val result = runGradleTasks(COMPILE_TASK)
+ val result = runGradleTasks(compileTaskName)
recordFileChanges()
return result
}
+
+ private fun runIncrementalTestBuild(): BuildResult {
+ val result = runGradleTasks(testCompileTaskName)
+ recordFileChanges()
+ return result
+ }
+
private fun recordTimestamps() {
val files = listOf(
genHiltApp,
@@ -526,13 +1140,22 @@ class IncrementalProcessorTest {
genActivityInjectorDeps2,
genModuleDeps1,
genModuleDeps2,
+ genComponentTreeDeps,
genHiltComponents,
genDaggerHiltApplicationComponent,
+ genTest1ComponentTreeDeps,
+ genTest2ComponentTreeDeps,
+ genTest1HiltComponents,
+ genTest2HiltComponents,
+ genTest1DaggerHiltApplicationComponent,
+ genTest2DaggerHiltApplicationComponent,
classSrcApp,
classSrcActivity1,
classSrcActivity2,
classSrcModule1,
classSrcModule2,
+ classSrcTest1,
+ classSrcTest2,
classGenHiltApp,
classGenHiltActivity1,
classGenHiltActivity2,
@@ -544,8 +1167,15 @@ class IncrementalProcessorTest {
classGenActivityInjectorDeps2,
classGenModuleDeps1,
classGenModuleDeps2,
+ classGenComponentTreeDeps,
classGenHiltComponents,
- classGenDaggerHiltApplicationComponent
+ classGenDaggerHiltApplicationComponent,
+ classGenTest1ComponentTreeDeps,
+ classGenTest2ComponentTreeDeps,
+ classGenTest1HiltComponents,
+ classGenTest2HiltComponents,
+ classGenTest1DaggerHiltApplicationComponent,
+ classGenTest2DaggerHiltApplicationComponent,
)
fileToTimestampMap = mutableMapOf<File, Long>().apply {
@@ -567,19 +1197,19 @@ class IncrementalProcessorTest {
deletedFiles = fileToTimestampMap.filter { (file, _) -> !file.exists() }.keys
}
- private fun assertFilesExist(vararg files: File) {
+ private fun assertFilesExist(files: Collection<File>) {
expect.withMessage("Existing files")
.that(files.filter { it.exists() })
.containsExactlyElementsIn(files)
}
- private fun assertChangedFiles(type: FileType, vararg files: File) {
+ private fun assertChangedFiles(type: FileType, files: Collection<File>) {
expect.withMessage("Changed files")
.that(changedFiles.filter { it.name.endsWith(type.extension) })
.containsExactlyElementsIn(files)
}
- private fun assertDeletedFiles(vararg files: File) {
+ private fun assertDeletedFiles(files: Collection<File>) {
expect.withMessage("Deleted files").that(deletedFiles).containsAtLeastElementsIn(files)
}
@@ -593,11 +1223,19 @@ class IncrementalProcessorTest {
}
companion object {
- private const val SRC_DIR = "src/main/java"
- private const val GEN_SRC_DIR = "build/generated/ap_generated_sources/debug/out/"
- private const val CLASS_DIR = "build/intermediates/javac/debug/classes"
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun parameters() = listOf(
+ ISOLATING_MODE,
+ AGGREGATING_MODE
+ )
+
+ private const val ISOLATING_MODE = "isolating"
+ private const val AGGREGATING_MODE = "aggregating"
+
+ private const val MAIN_SRC_DIR = "src/main/java"
+ private const val TEST_SRC_DIR = "src/test/java"
private const val CLEAN_TASK = ":clean"
- private const val COMPILE_TASK = ":compileDebugJavaWithJavac"
}
}
diff --git a/java/dagger/hilt/android/plugin/src/test/kotlin/NoTransformTest.kt b/java/dagger/hilt/android/plugin/src/test/kotlin/NoTransformTest.kt
new file mode 100644
index 000000000..cb67c2c12
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/test/kotlin/NoTransformTest.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+
+class NoTransformTest {
+
+ @get:Rule
+ val testProjectDir = TemporaryFolder()
+
+ lateinit var gradleRunner: GradleTestRunner
+
+ @Before
+ fun setup() {
+ gradleRunner = GradleTestRunner(testProjectDir)
+ }
+
+ // Simple functional test to verify transformation.
+ @Test
+ fun testAssemble() {
+ gradleRunner.addDependencies(
+ "implementation 'androidx.appcompat:appcompat:1.1.0'",
+ "implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'",
+ "annotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'"
+ )
+ gradleRunner.addAndroidOption(
+ "buildFeatures.buildConfig = false"
+ )
+
+ val result = gradleRunner.build()
+ val assembleTask = result.getTask(":assembleDebug")
+ Assert.assertEquals(TaskOutcome.SUCCESS, assembleTask.outcome)
+ }
+}
diff --git a/java/dagger/hilt/android/plugin/src/test/kotlin/TransformTest.kt b/java/dagger/hilt/android/plugin/src/test/kotlin/TransformTest.kt
index 0b8400214..d45dc3ec4 100644
--- a/java/dagger/hilt/android/plugin/src/test/kotlin/TransformTest.kt
+++ b/java/dagger/hilt/android/plugin/src/test/kotlin/TransformTest.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
+import com.google.common.truth.Truth.assertThat
import java.io.DataInputStream
import java.io.FileInputStream
import javassist.bytecode.ByteArray
import javassist.bytecode.ClassFile
-import junit.framework.Assert.assertEquals
+import javassist.bytecode.SignatureAttribute
import org.gradle.testkit.runner.TaskOutcome
import org.junit.Assert
import org.junit.Before
@@ -278,12 +279,12 @@ class TransformTest {
gradleRunner.build().let {
val assembleTask = it.getTask(TRANSFORM_TASK_NAME)
- assertEquals(TaskOutcome.SUCCESS, assembleTask.outcome)
+ assertThat(assembleTask.outcome).isEqualTo(TaskOutcome.SUCCESS)
}
gradleRunner.build().let {
val assembleTask = it.getTask(TRANSFORM_TASK_NAME)
- assertEquals(TaskOutcome.UP_TO_DATE, assembleTask.outcome)
+ assertThat(assembleTask.outcome).isEqualTo(TaskOutcome.UP_TO_DATE)
}
gradleRunner.addSrc(
@@ -303,7 +304,94 @@ class TransformTest {
val result = gradleRunner.build()
val assembleTask = result.getTask(TRANSFORM_TASK_NAME)
- assertEquals(TaskOutcome.SUCCESS, assembleTask.outcome)
+ assertThat(assembleTask.outcome).isEqualTo(TaskOutcome.SUCCESS)
+ }
+
+ // Verifies the Signature attribute in the ClassFile is updated when the superclass uses type
+ // variables or parameterized types.
+ // See: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.9
+ @Test
+ fun testTransform_genericSuperclass() {
+ gradleRunner.addDependencies(
+ "implementation 'androidx.appcompat:appcompat:1.1.0'",
+ "implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'",
+ "annotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'"
+ )
+
+ gradleRunner.addSrc(
+ srcPath = "minimal/BaseActivity.java",
+ srcContent =
+ """
+ package minimal;
+
+ import androidx.appcompat.app.AppCompatActivity;
+
+ public abstract class BaseActivity<T> extends AppCompatActivity {
+ }
+ """.trimIndent()
+ )
+
+ gradleRunner.addSrc(
+ srcPath = "minimal/SimpleActivity.java",
+ srcContent =
+ """
+ package minimal;
+
+ @dagger.hilt.android.AndroidEntryPoint
+ public class SimpleActivity extends BaseActivity<String> {
+ }
+ """.trimIndent()
+ )
+
+ gradleRunner.addSrc(
+ srcPath = "minimal/BasicActivityThing.java",
+ srcContent =
+ """
+ package minimal;
+
+ public class BasicActivityThing {
+ }
+ """.trimIndent()
+ )
+
+ gradleRunner.addSrc(
+ srcPath = "minimal/BasicActivity.java",
+ srcContent =
+ """
+ package minimal;
+
+ @dagger.hilt.android.AndroidEntryPoint
+ public class BasicActivity extends BaseActivity<BasicActivityThing> {
+ }
+ """.trimIndent()
+ )
+
+ val result = gradleRunner.build()
+ val assembleTask = result.getTask(":assembleDebug")
+ Assert.assertEquals(TaskOutcome.SUCCESS, assembleTask.outcome)
+
+ val transformedClass1 = result.getTransformedFile("minimal/SimpleActivity.class")
+ FileInputStream(transformedClass1).use { fileInput ->
+ ClassFile(DataInputStream(fileInput)).let { classFile ->
+ Assert.assertEquals("minimal.Hilt_SimpleActivity", classFile.superclass)
+ val signatureAttr = classFile.getAttribute(SignatureAttribute.tag) as SignatureAttribute
+ Assert.assertEquals(
+ "Lminimal/Hilt_SimpleActivity<Ljava/lang/String;>;",
+ signatureAttr.signature
+ )
+ }
+ }
+
+ val transformedClass2 = result.getTransformedFile("minimal/BasicActivity.class")
+ FileInputStream(transformedClass2).use { fileInput ->
+ ClassFile(DataInputStream(fileInput)).let { classFile ->
+ val signatureAttr = classFile.getAttribute(SignatureAttribute.tag) as SignatureAttribute
+ Assert.assertEquals(
+ "Lminimal/Hilt_BasicActivity<Lminimal/BasicActivityThing;>;",
+ signatureAttr.signature
+ )
+ }
+ }
}
companion object {
diff --git a/java/dagger/hilt/android/plugin/src/test/kotlin/VariantsConfigurationTest.kt b/java/dagger/hilt/android/plugin/src/test/kotlin/VariantsConfigurationTest.kt
new file mode 100644
index 000000000..fb4c9c3b2
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/src/test/kotlin/VariantsConfigurationTest.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.google.common.truth.Expect
+import java.io.File
+import org.gradle.testkit.runner.BuildResult
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+
+// Verifies the aggregated task is configured correctly in a multi-module flavored project.
+class VariantsConfigurationTest {
+ @get:Rule
+ val testProjectDir = TemporaryFolder()
+
+ @get:Rule
+ val expect: Expect = Expect.create()
+
+ @Before
+ fun setup() {
+ val projectRoot = testProjectDir.root
+ File("src/test/data/flavored-project").copyRecursively(projectRoot)
+ }
+
+ @Test
+ fun verifyFlavorConfiguration_demoDebug() {
+ val result = runGradleTasks(":app:assembleMinApi21DemoDebug")
+ expect.that(result.task(":app:assembleMinApi21DemoDebug")!!.outcome)
+ .isEqualTo(TaskOutcome.SUCCESS)
+ }
+
+ @Test
+ fun verifyFlavorConfiguration_fullRelease() {
+ val result = runGradleTasks(":app:assembleMinApi24FullRelease")
+ expect.that(result.task(":app:assembleMinApi24FullRelease")!!.outcome)
+ .isEqualTo(TaskOutcome.SUCCESS)
+ }
+
+ private fun runGradleTasks(vararg args: String): BuildResult {
+ return GradleRunner.create()
+ .withProjectDir(testProjectDir.root)
+ .withArguments(*args)
+ .withPluginClasspath()
+ .forwardOutput()
+ .build()
+ }
+}
diff --git a/java/dagger/hilt/android/processor/BUILD b/java/dagger/hilt/android/processor/BUILD
index ccf21033d..869e3e23c 100644
--- a/java/dagger/hilt/android/processor/BUILD
+++ b/java/dagger/hilt/android/processor/BUILD
@@ -66,9 +66,11 @@ gen_maven_artifact(
"//java/dagger/hilt/processor/internal/generatesrootinput:generates_root_inputs",
"//java/dagger/hilt/processor/internal/generatesrootinput:processor_lib",
"//java/dagger/hilt/processor/internal/originatingelement:processor_lib",
- "//java/dagger/hilt/processor/internal/root:processor_lib",
+ "//java/dagger/hilt/processor/internal/root:component_tree_deps_processor_lib",
+ "//java/dagger/hilt/processor/internal/root:root_processor_lib",
"//java/dagger/hilt/processor/internal/root:root_metadata",
"//java/dagger/hilt/processor/internal/root:root_type",
+ "//java/dagger/hilt/processor/internal/root/ir:ir",
"//java/dagger/hilt/processor/internal/uninstallmodules:processor_lib",
"//java/dagger/hilt/processor/internal/uninstallmodules:aggregated_uninstall_modules_metadata",
],
@@ -85,6 +87,7 @@ gen_maven_artifact(
"javax.inject:javax.inject",
"net.ltgt.gradle.incap:incap",
"org.jetbrains.kotlin:kotlin-stdlib",
+ "org.jetbrains.kotlin:kotlin-stdlib-jdk8",
"org.jetbrains.kotlinx:kotlinx-metadata-jvm",
],
javadoc_android_api_level = 30,
@@ -95,8 +98,10 @@ gen_maven_artifact(
javadoc_srcs = [
"//java/dagger/hilt:hilt_processing_filegroup",
],
- shaded_deps = ["@maven//:com_google_auto_auto_common"],
- shaded_rules = ["rule com.google.auto.common.** dagger.hilt.android.shaded.auto.common.@1"],
+ # The shaded deps are added using jarjar, but they won't be shaded until later
+ # due to: https://github.com/google/dagger/issues/2765. For the shaded rules see
+ # util/deploy-hilt.sh
+ shaded_deps = ["//third_party/java/auto:common"],
)
filegroup(
diff --git a/java/dagger/hilt/android/processor/internal/AndroidClassNames.java b/java/dagger/hilt/android/processor/internal/AndroidClassNames.java
index d37092003..2d954481a 100644
--- a/java/dagger/hilt/android/processor/internal/AndroidClassNames.java
+++ b/java/dagger/hilt/android/processor/internal/AndroidClassNames.java
@@ -58,6 +58,10 @@ public final class AndroidClassNames {
get("dagger.hilt.android", "WithFragmentBindings");
public static final ClassName HILT_ANDROID_APP =
get("dagger.hilt.android", "HiltAndroidApp");
+ public static final ClassName CUSTOM_INJECT =
+ get("dagger.hilt.android.migration", "CustomInject");
+ public static final ClassName CUSTOM_INJECTION =
+ get("dagger.hilt.android.migration", "CustomInjection");
public static final ClassName OPTIONAL_INJECT =
get("dagger.hilt.android.migration", "OptionalInject");
@@ -78,6 +82,9 @@ public final class AndroidClassNames {
public static final ClassName VIEW_MODEL_COMPONENT =
get("dagger.hilt.android.components", "ViewModelComponent");
+ public static final ClassName FRAGMENT_GET_CONTEXT_FIX =
+ get("dagger.hilt.android.flags", "FragmentGetContextFix");
+
public static final ClassName ACTIVITY_COMPONENT_MANAGER =
get("dagger.hilt.android.internal.managers", "ActivityComponentManager");
public static final ClassName APPLICATION_COMPONENT_MANAGER =
@@ -93,6 +100,8 @@ public final class AndroidClassNames {
public static final ClassName VIEW_COMPONENT_MANAGER =
get("dagger.hilt.android.internal.managers", "ViewComponentManager");
+ public static final ClassName HAS_CUSTOM_INJECT =
+ get("dagger.hilt.android.internal.migration", "HasCustomInject");
public static final ClassName INJECTED_BY_HILT =
get("dagger.hilt.android.internal.migration", "InjectedByHilt");
diff --git a/java/dagger/hilt/android/processor/internal/BUILD b/java/dagger/hilt/android/processor/internal/BUILD
index aaf8b8916..dfd73337e 100644
--- a/java/dagger/hilt/android/processor/internal/BUILD
+++ b/java/dagger/hilt/android/processor/internal/BUILD
@@ -23,7 +23,7 @@ java_library(
"AndroidClassNames.java",
],
deps = [
- "@google_bazel_common//third_party/java/javapoet",
+ "//third_party/java/javapoet",
],
)
@@ -34,8 +34,8 @@ java_library(
"MoreTypes.java",
],
deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
],
)
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGenerator.java
index 86fbaa712..f933a9030 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGenerator.java
@@ -67,6 +67,7 @@ public final class ActivityGenerator {
Generators.addComponentOverride(metadata, builder);
Generators.copyLintAnnotations(metadata.element(), builder);
+ Generators.copySuppressAnnotations(metadata.element(), builder);
Generators.addInjectionMethods(metadata, builder);
@@ -112,10 +113,19 @@ public final class ActivityGenerator {
// this, super.getDefaultViewModelProviderFactory());
// }
private MethodSpec getDefaultViewModelProviderFactory() {
- return MethodSpec.methodBuilder("getDefaultViewModelProviderFactory")
+ MethodSpec.Builder builder = MethodSpec.methodBuilder("getDefaultViewModelProviderFactory")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
- .returns(AndroidClassNames.VIEW_MODEL_PROVIDER_FACTORY)
+ .returns(AndroidClassNames.VIEW_MODEL_PROVIDER_FACTORY);
+
+ if (metadata.allowsOptionalInjection()) {
+ builder
+ .beginControlFlow("if (!optionalInjectParentUsesHilt(optionalInjectGetParent()))")
+ .addStatement("return super.getDefaultViewModelProviderFactory()")
+ .endControlFlow();
+ }
+
+ return builder
.addStatement(
"return $T.getActivityFactory(this, super.getDefaultViewModelProviderFactory())",
AndroidClassNames.DEFAULT_VIEW_MODEL_FACTORIES)
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java
index c94f6a977..44c7ae1a0 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java
@@ -158,8 +158,7 @@ public abstract class AndroidEntryPointMetadata {
}
private static ClassName generatedClassName(TypeElement element) {
- String prefix = "Hilt_";
- return Processors.prepend(Processors.getEnclosedClassName(ClassName.get(element)), prefix);
+ return Processors.prepend(Processors.getEnclosedClassName(ClassName.get(element)), "Hilt_");
}
private static final ImmutableSet<ClassName> HILT_ANNOTATION_NAMES =
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessor.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessor.java
index cd3290b48..c755bbd1a 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessor.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessor.java
@@ -16,12 +16,14 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
+import static dagger.hilt.processor.internal.HiltCompilerOptions.useAggregatingRootProcessor;
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
import dagger.hilt.android.processor.internal.AndroidClassNames;
import dagger.hilt.processor.internal.BaseProcessor;
+import dagger.hilt.processor.internal.ProcessorErrors;
import java.util.Set;
import javax.annotation.processing.Processor;
import javax.lang.model.element.Element;
@@ -54,7 +56,29 @@ public final class AndroidEntryPointProcessor extends BaseProcessor {
new InjectorEntryPointGenerator(getProcessingEnv(), metadata).generate();
switch (metadata.androidType()) {
case APPLICATION:
- new ApplicationGenerator(getProcessingEnv(), metadata).generate();
+ // The generated application references the generated component so they must be generated
+ // in the same build unit. Thus, we only generate the application here if we're using the
+ // aggregating root processor. If we're using the Hilt Gradle plugin's aggregating task, we
+ // need to generate the application within ComponentTreeDepsProcessor instead.
+ if (useAggregatingRootProcessor(getProcessingEnv())) {
+ // While we could always generate the application in ComponentTreeDepsProcessor, even if
+ // we're using the aggregating root processor, it can lead to extraneous errors when
+ // things fail before ComponentTreeDepsProcessor runs so we generate it here to avoid that
+ new ApplicationGenerator(getProcessingEnv(), metadata).generate();
+ } else {
+ // If we're not using the aggregating root processor, then make sure the root application
+ // does not extend the generated application directly, and instead uses bytecode injection
+ ProcessorErrors.checkState(
+ metadata.requiresBytecodeInjection(),
+ metadata.element(),
+ "'enableAggregatingTask=true' cannot be used when the application directly "
+ + "references the generated Hilt class, %s. Either extend %s directly (relying "
+ + "on the Gradle plugin described in "
+ + "https://dagger.dev/hilt/gradle-setup#why-use-the-plugin or set "
+ + "'enableAggregatingTask=false'.",
+ metadata.generatedClassName(),
+ metadata.baseClassName());
+ }
break;
case ACTIVITY:
new ActivityGenerator(getProcessingEnv(), metadata).generate();
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/ApplicationGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/ApplicationGenerator.java
index 8d63cdbea..8347b0ea7 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/ApplicationGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/ApplicationGenerator.java
@@ -16,7 +16,10 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PROTECTED;
+import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
@@ -28,10 +31,16 @@ import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
import dagger.hilt.android.processor.internal.AndroidClassNames;
import dagger.hilt.processor.internal.ComponentNames;
+import dagger.hilt.processor.internal.ProcessorErrors;
import dagger.hilt.processor.internal.Processors;
import java.io.IOException;
+import java.util.Set;
+import java.util.stream.Collectors;
import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
+import javax.lang.model.util.ElementFilter;
/** Generates an Hilt Application for an @AndroidEntryPoint app class. */
public final class ApplicationGenerator {
@@ -68,15 +77,49 @@ public final class ApplicationGenerator {
.forEachOrdered(typeSpecBuilder::addTypeVariable);
Generators.copyLintAnnotations(metadata.element(), typeSpecBuilder);
+ Generators.copySuppressAnnotations(metadata.element(), typeSpecBuilder);
Generators.addComponentOverride(metadata, typeSpecBuilder);
+ if (hasCustomInject()) {
+ typeSpecBuilder.addSuperinterface(AndroidClassNames.HAS_CUSTOM_INJECT);
+ typeSpecBuilder.addMethod(customInjectMethod());
+ } else {
typeSpecBuilder.addMethod(onCreateMethod());
+ }
JavaFile.builder(metadata.elementClassName().packageName(), typeSpecBuilder.build())
.build()
.writeTo(env.getFiler());
}
+ private boolean hasCustomInject() {
+ boolean hasCustomInject =
+ Processors.hasAnnotation(metadata.element(), AndroidClassNames.CUSTOM_INJECT);
+ if (hasCustomInject) {
+ // Check that the Hilt base class does not already define a customInject implementation.
+ Set<ExecutableElement> customInjectMethods =
+ ElementFilter.methodsIn(
+ ImmutableSet.<Element>builder()
+ .addAll(metadata.element().getEnclosedElements())
+ .addAll(env.getElementUtils().getAllMembers(metadata.baseElement()))
+ .build())
+ .stream()
+ .filter(method -> method.getSimpleName().contentEquals("customInject"))
+ .filter(method -> method.getParameters().isEmpty())
+ .collect(Collectors.toSet());
+
+ for (ExecutableElement customInjectMethod : customInjectMethods) {
+ ProcessorErrors.checkState(
+ customInjectMethod.getModifiers().containsAll(ImmutableSet.of(ABSTRACT, PROTECTED)),
+ customInjectMethod,
+ "%s#%s, must have modifiers `abstract` and `protected` when using @CustomInject.",
+ customInjectMethod.getEnclosingElement(),
+ customInjectMethod);
+ }
+ }
+ return hasCustomInject;
+ }
+
// private final ApplicationComponentManager<ApplicationComponent> componentManager =
// new ApplicationComponentManager(/* creatorType */);
private FieldSpec componentManagerField() {
@@ -108,9 +151,6 @@ public final class ApplicationGenerator {
// }
// }
private TypeSpec creatorType() {
- ClassName component =
- componentNames.generatedComponent(
- metadata.elementClassName(), AndroidClassNames.SINGLETON_COMPONENT);
return TypeSpec.anonymousClassBuilder("")
.addSuperinterface(AndroidClassNames.COMPONENT_SUPPLIER)
.addMethod(
@@ -118,17 +158,27 @@ public final class ApplicationGenerator {
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.returns(TypeName.OBJECT)
- .addStatement(
- "return $T.builder()\n"
- + ".applicationContextModule(new $T($T.this))\n"
- + ".build()",
- Processors.prepend(Processors.getEnclosedClassName(component), "Dagger"),
- AndroidClassNames.APPLICATION_CONTEXT_MODULE,
- wrapperClassName)
+ .addCode(componentBuilder())
.build())
.build();
}
+ // return DaggerApplicationComponent.builder()
+ // .applicationContextModule(new ApplicationContextModule(Hilt_$APP.this))
+ // .build();
+ private CodeBlock componentBuilder() {
+ ClassName component =
+ componentNames.generatedComponent(
+ metadata.elementClassName(), AndroidClassNames.SINGLETON_COMPONENT);
+ return CodeBlock.builder()
+ .addStatement(
+ "return $T.builder()$Z" + ".applicationContextModule(new $T($T.this))$Z" + ".build()",
+ Processors.prepend(Processors.getEnclosedClassName(component), "Dagger"),
+ AndroidClassNames.APPLICATION_CONTEXT_MODULE,
+ wrapperClassName)
+ .build();
+ }
+
// @CallSuper
// @Override
// public void onCreate() {
@@ -147,7 +197,21 @@ public final class ApplicationGenerator {
.build();
}
- // // This is a known unsafe cast but should be fine if the only use is
+ // @Override
+ // public final void customInject() {
+ // // This is a known unsafe cast but is safe in the only correct use case:
+ // // $APP extends Hilt_$APP
+ // generatedComponent().inject(($APP) this);
+ // }
+ private MethodSpec customInjectMethod() {
+ return MethodSpec.methodBuilder("customInject")
+ .addAnnotation(Override.class)
+ .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+ .addCode(injectCodeBlock())
+ .build();
+ }
+
+ // // This is a known unsafe cast but is safe in the only correct use case:
// // $APP extends Hilt_$APP
// generatedComponent().inject$APP(($APP) this);
private CodeBlock injectCodeBlock() {
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD b/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
index efbf9e47a..46bcdd6d3 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
@@ -38,9 +38,12 @@ java_library(
":metadata",
"//java/dagger/hilt/android/processor/internal:android_classnames",
"//java/dagger/hilt/processor/internal:base_processor",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
+ "//java/dagger/hilt/processor/internal:compiler_options",
+ "//java/dagger/hilt/processor/internal:processor_errors",
+ "//java/dagger/hilt/processor/internal:processors",
+ "//third_party/java/auto:service",
+ "//third_party/java/guava/collect",
+ "//third_party/java/incap",
],
)
@@ -61,15 +64,16 @@ java_library(
"//java/dagger/hilt/android/processor/internal:android_classnames",
"//java/dagger/hilt/android/processor/internal:utils",
"//java/dagger/hilt/processor/internal:classnames",
+ "//java/dagger/hilt/processor/internal:compiler_options",
"//java/dagger/hilt/processor/internal:component_names",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/internal/codegen/extension",
"//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
@@ -88,11 +92,11 @@ java_library(
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/internal/codegen/extension",
"//java/dagger/internal/codegen/kotlin",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java
index f8e9f6078..a8eb7a6b2 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java
@@ -78,6 +78,7 @@ public final class BroadcastReceiverGenerator {
Generators.addInjectionMethods(metadata, builder);
Generators.copyLintAnnotations(metadata.element(), builder);
+ Generators.copySuppressAnnotations(metadata.element(), builder);
// Add an unused field used as a marker to let the bytecode injector know this receiver will
// need to be injected with a super.onReceive call. This is only necessary if no concrete
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java
index 81b2b6156..e7a70268c 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java
@@ -16,10 +16,12 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
+import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
import dagger.hilt.android.processor.internal.AndroidClassNames;
@@ -36,6 +38,11 @@ public final class FragmentGenerator {
.addModifiers(Modifier.PRIVATE)
.build();
+ private static final FieldSpec DISABLE_GET_CONTEXT_FIX_FIELD =
+ FieldSpec.builder(TypeName.BOOLEAN, "disableGetContextFix")
+ .addModifiers(Modifier.PRIVATE)
+ .build();
+
private final ProcessingEnvironment env;
private final AndroidEntryPointMetadata metadata;
private final ClassName generatedClassName;
@@ -69,12 +76,13 @@ public final class FragmentGenerator {
.addMethod(onAttachActivityMethod())
.addMethod(initializeComponentContextMethod())
.addMethod(getContextMethod())
- .addMethod(inflatorMethod());
+ .addMethod(inflatorMethod())
+ .addField(DISABLE_GET_CONTEXT_FIX_FIELD);
Generators.addGeneratedBaseClassJavadoc(builder, AndroidClassNames.ANDROID_ENTRY_POINT);
Processors.addGeneratedAnnotation(builder, env, getClass());
Generators.copyLintAnnotations(metadata.element(), builder);
- Generators.addSuppressAnnotation(builder, "deprecation");
+ Generators.copySuppressAnnotations(metadata.element(), builder);
Generators.copyConstructors(metadata.baseElement(), builder);
metadata.baseElement().getTypeParameters().stream()
@@ -94,9 +102,10 @@ public final class FragmentGenerator {
// @CallSuper
// @Override
- // public void onAttach(Activity activity) {
- // super.onAttach(activity);
+ // public void onAttach(Context context) {
+ // super.onAttach(context);
// initializeComponentContext();
+ // inject();
// }
private static MethodSpec onAttachContextMethod() {
return MethodSpec.methodBuilder("onAttach")
@@ -106,21 +115,29 @@ public final class FragmentGenerator {
.addParameter(AndroidClassNames.CONTEXT, "context")
.addStatement("super.onAttach(context)")
.addStatement("initializeComponentContext()")
+ // The inject method will internally check if injected already
+ .addStatement("inject()")
.build();
}
// @CallSuper
// @Override
+ // @SuppressWarnings("deprecation")
// public void onAttach(Activity activity) {
// super.onAttach(activity);
// Preconditions.checkState(
// componentContext == null || FragmentComponentManager.findActivity(
// componentContext) == activity, "...");
// initializeComponentContext();
+ // inject();
// }
private static MethodSpec onAttachActivityMethod() {
return MethodSpec.methodBuilder("onAttach")
.addAnnotation(Override.class)
+ .addAnnotation(
+ AnnotationSpec.builder(ClassNames.SUPPRESS_WARNINGS)
+ .addMember("value", "\"deprecation\"")
+ .build())
.addAnnotation(AndroidClassNames.CALL_SUPER)
.addAnnotation(AndroidClassNames.MAIN_THREAD)
.addModifiers(Modifier.PUBLIC)
@@ -135,23 +152,24 @@ public final class FragmentGenerator {
"onAttach called multiple times with different Context! "
+ "Hilt Fragments should not be retained.")
.addStatement("initializeComponentContext()")
+ // The inject method will internally check if injected already
+ .addStatement("inject()")
.build();
}
// private void initializeComponentContext() {
- // // Only inject on the first call to onAttach.
// if (componentContext == null) {
// // Note: The LayoutInflater provided by this componentContext may be different from super
// // Fragment's because we are getting it from base context instead of cloning from super
// // Fragment's LayoutInflater.
// componentContext = FragmentComponentManager.createContextWrapper(super.getContext(), this);
- // inject();
+ // disableGetContextFix = FragmentGetContextFix.isFragmentGetContextFixDisabled(
+ // super.getContext());
// }
// }
private MethodSpec initializeComponentContextMethod() {
- return MethodSpec.methodBuilder("initializeComponentContext")
+ MethodSpec.Builder builder = MethodSpec.methodBuilder("initializeComponentContext")
.addModifiers(Modifier.PRIVATE)
- .addComment("Only inject on the first call to onAttach.")
.beginControlFlow("if ($N == null)", COMPONENT_CONTEXT_FIELD)
.addComment(
"Note: The LayoutInflater provided by this componentContext may be different from"
@@ -160,21 +178,54 @@ public final class FragmentGenerator {
.addStatement(
"$N = $T.createContextWrapper(super.getContext(), this)",
COMPONENT_CONTEXT_FIELD,
- metadata.componentManager())
- .addStatement("inject()")
+ metadata.componentManager());
+ if (metadata.allowsOptionalInjection()) {
+ // When optionally injected, since the runtime flag is only available in Hilt, we need to
+ // check that the parent uses Hilt first.
+ builder.beginControlFlow("if (optionalInjectParentUsesHilt(optionalInjectGetParent()))");
+ }
+
+ builder
+ .addStatement("$N = $T.isFragmentGetContextFixDisabled(super.getContext())",
+ DISABLE_GET_CONTEXT_FIX_FIELD,
+ AndroidClassNames.FRAGMENT_GET_CONTEXT_FIX);
+
+ if (metadata.allowsOptionalInjection()) {
+ // If not attached to a Hilt parent, just disable the fix for now since this is the current
+ // default. There's not a good way to flip this at runtime without Hilt, so after we flip
+ // the default we may just have to flip this and hope that the Hilt usage is already enough
+ // coverage as this should be a fairly rare case.
+ builder.nextControlFlow("else")
+ .addStatement("$N = true", DISABLE_GET_CONTEXT_FIX_FIELD)
+ .endControlFlow();
+ }
+
+ return builder
.endControlFlow()
.build();
}
// @Override
// public Context getContext() {
+ // if (super.getContext() == null && !disableGetContextFix) {
+ // return null;
+ // }
+ // initializeComponentContext();
// return componentContext;
// }
- private static MethodSpec getContextMethod() {
+ private MethodSpec getContextMethod() {
return MethodSpec.methodBuilder("getContext")
.returns(AndroidClassNames.CONTEXT)
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
+ // Note that disableGetContext can only be true if componentContext is set, so if it is
+ // true we don't need to check whether componentContext is set or not.
+ .beginControlFlow(
+ "if (super.getContext() == null && !$N)",
+ DISABLE_GET_CONTEXT_FIX_FIELD)
+ .addStatement("return null")
+ .endControlFlow()
+ .addStatement("initializeComponentContext()")
.addStatement("return $N", COMPONENT_CONTEXT_FIELD)
.build();
}
@@ -206,10 +257,19 @@ public final class FragmentGenerator {
// this, super.getDefaultViewModelProviderFactory());
// }
private MethodSpec getDefaultViewModelProviderFactory() {
- return MethodSpec.methodBuilder("getDefaultViewModelProviderFactory")
+ MethodSpec.Builder builder = MethodSpec.methodBuilder("getDefaultViewModelProviderFactory")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
- .returns(AndroidClassNames.VIEW_MODEL_PROVIDER_FACTORY)
+ .returns(AndroidClassNames.VIEW_MODEL_PROVIDER_FACTORY);
+
+ if (metadata.allowsOptionalInjection()) {
+ builder
+ .beginControlFlow("if (!optionalInjectParentUsesHilt(optionalInjectGetParent()))")
+ .addStatement("return super.getDefaultViewModelProviderFactory()")
+ .endControlFlow();
+ }
+
+ return builder
.addStatement(
"return $T.getFragmentFactory(this, super.getDefaultViewModelProviderFactory())",
AndroidClassNames.DEFAULT_VIEW_MODEL_FACTORIES)
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java
index 91df537c9..e2892aa27 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java
@@ -18,9 +18,14 @@ package dagger.hilt.android.processor.internal.androidentrypoint;
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static java.util.stream.Collectors.joining;
import static javax.lang.model.element.Modifier.PRIVATE;
+import com.google.auto.common.AnnotationMirrors;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
@@ -30,6 +35,7 @@ import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import dagger.hilt.android.processor.internal.AndroidClassNames;
+import dagger.hilt.android.processor.internal.androidentrypoint.AndroidEntryPointMetadata.AndroidType;
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.Processors;
import java.util.List;
@@ -45,6 +51,11 @@ import javax.lang.model.util.ElementFilter;
/** Helper class for writing Hilt generators. */
final class Generators {
+ private static final ImmutableMap<ClassName, String> SUPPRESS_ANNOTATION_PROPERTY_NAME =
+ ImmutableMap.<ClassName, String>builder()
+ .put(ClassNames.SUPPRESS_WARNINGS, "value")
+ .put(ClassNames.KOTLIN_SUPPRESS, "names")
+ .build();
static void addGeneratedBaseClassJavadoc(TypeSpec.Builder builder, ClassName annotation) {
builder.addJavadoc("A generated base class to be extended by the @$T annotated class. If using"
@@ -123,15 +134,14 @@ final class Generators {
private static MethodSpec copyConstructor(ExecutableElement constructor, CodeBlock body) {
List<ParameterSpec> params =
constructor.getParameters().stream()
- .map(parameter -> getParameterSpecWithNullable(parameter))
+ .map(Generators::getParameterSpecWithNullable)
.collect(Collectors.toList());
final MethodSpec.Builder builder =
MethodSpec.constructorBuilder()
.addParameters(params)
.addStatement(
- "super($L)",
- params.stream().map(param -> param.name).collect(Collectors.joining(", ")))
+ "super($L)", params.stream().map(param -> param.name).collect(joining(", ")))
.addCode(body);
constructor.getAnnotationMirrors().stream()
@@ -143,6 +153,27 @@ final class Generators {
return builder.build();
}
+ /** Copies SuppressWarnings annotations from the annotated element to the generated element. */
+ static void copySuppressAnnotations(Element element, TypeSpec.Builder builder) {
+ ImmutableSet<String> suppressValues =
+ SUPPRESS_ANNOTATION_PROPERTY_NAME.keySet().stream()
+ .filter(annotation -> Processors.hasAnnotation(element, annotation))
+ .map(
+ annotation ->
+ AnnotationMirrors.getAnnotationValue(
+ Processors.getAnnotationMirror(element, annotation),
+ SUPPRESS_ANNOTATION_PROPERTY_NAME.get(annotation)))
+ .flatMap(value -> Processors.getStringArrayAnnotationValue(value).stream())
+ .collect(toImmutableSet());
+
+ if (!suppressValues.isEmpty()) {
+ // Replace kotlin Suppress with java SuppressWarnings, as the generated file is java.
+ AnnotationSpec.Builder annotation = AnnotationSpec.builder(ClassNames.SUPPRESS_WARNINGS);
+ suppressValues.forEach(value -> annotation.addMember("value", "$S", value));
+ builder.addAnnotation(annotation.build());
+ }
+ }
+
/**
* Copies the Android lint annotations from the annotated element to the generated element.
*
@@ -186,7 +217,7 @@ final class Generators {
addComponentManagerMethods(metadata, builder);
// fall through
case BROADCAST_RECEIVER:
- addInjectMethod(metadata, builder);
+ addInjectAndMaybeOptionalInjectMethod(metadata, builder);
break;
default:
throw new AssertionError();
@@ -293,7 +324,7 @@ final class Generators {
// injected = true;
// }
// }
- private static void addInjectMethod(
+ private static void addInjectAndMaybeOptionalInjectMethod(
AndroidEntryPointMetadata metadata, TypeSpec.Builder typeSpecBuilder) {
MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder("inject")
.addModifiers(Modifier.PROTECTED);
@@ -301,22 +332,44 @@ final class Generators {
// Check if the parent is a Hilt type. If it isn't or if it is but it
// wasn't injected by hilt, then return.
// Object parent = ...depends on type...
- // if (!(parent instanceof GeneratedComponentManager)
- // || ((parent instanceof InjectedByHilt) &&
- // !((InjectedByHilt) parent).wasInjectedByHilt())) {
+ // if (!optionalInjectParentUsesHilt()) {
// return;
//
if (metadata.allowsOptionalInjection()) {
+ CodeBlock parentCodeBlock;
+ if (metadata.androidType() != AndroidType.BROADCAST_RECEIVER) {
+ parentCodeBlock = CodeBlock.of("optionalInjectGetParent()");
+
+ // Also, add the optionalInjectGetParent method we just used. This is a separate method so
+ // other parts of the code when dealing with @OptionalInject. BroadcastReceiver can't have
+ // this method since the context is only accessible as a parameter to receive()/inject().
+ typeSpecBuilder.addMethod(MethodSpec.methodBuilder("optionalInjectGetParent")
+ .addModifiers(Modifier.PRIVATE)
+ .returns(TypeName.OBJECT)
+ .addStatement("return $L", getParentCodeBlock(metadata))
+ .build());
+ } else {
+ // For BroadcastReceiver, use the "context" field that is on the stack.
+ parentCodeBlock = CodeBlock.of(
+ "$T.getApplication(context.getApplicationContext())", ClassNames.CONTEXTS);
+ }
+
methodSpecBuilder
- .addStatement("$T parent = $L", ClassNames.OBJECT, getParentCodeBlock(metadata))
- .beginControlFlow(
- "if (!(parent instanceof $T) "
- + "|| ((parent instanceof $T) && !(($T) parent).wasInjectedByHilt()))",
+ .beginControlFlow("if (!optionalInjectParentUsesHilt($L))", parentCodeBlock)
+ .addStatement("return")
+ .endControlFlow();
+
+ // Add the optionalInjectParentUsesHilt used above.
+ typeSpecBuilder.addMethod(MethodSpec.methodBuilder("optionalInjectParentUsesHilt")
+ .addModifiers(Modifier.PRIVATE)
+ .addParameter(TypeName.OBJECT, "parent")
+ .returns(TypeName.BOOLEAN)
+ .addStatement("return (parent instanceof $T) "
+ + "&& (!(parent instanceof $T) || (($T) parent).wasInjectedByHilt())",
ClassNames.GENERATED_COMPONENT_MANAGER,
AndroidClassNames.INJECTED_BY_HILT,
AndroidClassNames.INJECTED_BY_HILT)
- .addStatement("return")
- .endControlFlow();
+ .build());
}
// Only add @Override if an ancestor extends a generated Hilt class.
@@ -393,15 +446,16 @@ final class Generators {
switch (metadata.androidType()) {
case ACTIVITY:
case SERVICE:
- return CodeBlock.of("getApplicationContext()");
+ return CodeBlock.of("$T.getApplication(getApplicationContext())", ClassNames.CONTEXTS);
case FRAGMENT:
return CodeBlock.of("getHost()");
case VIEW:
return CodeBlock.of(
"$L.maybeGetParentComponentManager()", componentManagerCallBlock(metadata));
case BROADCAST_RECEIVER:
- // Broadcast receivers receive a "context" parameter
- return CodeBlock.of("context.getApplicationContext()");
+ // Broadcast receivers receive a "context" parameter that make it so this code block
+ // isn't really usable anywhere
+ throw new AssertionError("BroadcastReceiver types should not get here");
default:
throw new AssertionError();
}
@@ -476,18 +530,5 @@ final class Generators {
.build();
}
- /**
- * Adds the SupressWarnings to supress a warning in the generated code.
- *
- * @param keys the string keys of the warnings to suppress, e.g. 'deprecation', 'unchecked', etc.
- */
- public static void addSuppressAnnotation(TypeSpec.Builder builder, String... keys) {
- AnnotationSpec.Builder annotationBuilder = AnnotationSpec.builder(SuppressWarnings.class);
- for (String key : keys) {
- annotationBuilder.addMember("value", "$S", key);
- }
- builder.addAnnotation(annotationBuilder.build());
- }
-
private Generators() {}
}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/InjectorEntryPointGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/InjectorEntryPointGenerator.java
index e9e217ddc..88c40e7d4 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/InjectorEntryPointGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/InjectorEntryPointGenerator.java
@@ -61,6 +61,7 @@ public final class InjectorEntryPointGenerator {
Processors.addGeneratedAnnotation(builder, env, getClass());
Generators.copyLintAnnotations(metadata.element(), builder);
+ Generators.copySuppressAnnotations(metadata.element(), builder);
JavaFile.builder(name.packageName(), builder.build()).build().writeTo(env.getFiler());
}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java
index a80a21545..267336387 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java
@@ -61,6 +61,7 @@ public final class ServiceGenerator {
Generators.addGeneratedBaseClassJavadoc(builder, AndroidClassNames.ANDROID_ENTRY_POINT);
Processors.addGeneratedAnnotation(builder, env, getClass());
Generators.copyLintAnnotations(metadata.element(), builder);
+ Generators.copySuppressAnnotations(metadata.element(), builder);
metadata.baseElement().getTypeParameters().stream()
.map(TypeVariableName::get)
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java
index 412b09a26..47029ca6f 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java
@@ -31,7 +31,6 @@ import java.util.List;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
@@ -70,6 +69,7 @@ public final class ViewGenerator {
Generators.addGeneratedBaseClassJavadoc(builder, AndroidClassNames.ANDROID_ENTRY_POINT);
Processors.addGeneratedAnnotation(builder, env, getClass());
Generators.copyLintAnnotations(metadata.element(), builder);
+ Generators.copySuppressAnnotations(metadata.element(), builder);
metadata.baseElement().getTypeParameters().stream()
.map(TypeVariableName::get)
@@ -177,13 +177,13 @@ public final class ViewGenerator {
}
private static boolean isSecondRestrictedParameter(Element element) {
- return element instanceof TypeElement
+ return MoreElements.isType(element)
&& Processors.isAssignableFrom(
MoreElements.asType(element), AndroidClassNames.ATTRIBUTE_SET);
}
private static boolean isFirstRestrictedParameter(Element element) {
- return element instanceof TypeElement
+ return MoreElements.isType(element)
&& Processors.isAssignableFrom(MoreElements.asType(element), AndroidClassNames.CONTEXT);
}
diff --git a/java/dagger/hilt/android/processor/internal/bindvalue/BUILD b/java/dagger/hilt/android/processor/internal/bindvalue/BUILD
index cbc51b3c5..5a59735a2 100644
--- a/java/dagger/hilt/android/processor/internal/bindvalue/BUILD
+++ b/java/dagger/hilt/android/processor/internal/bindvalue/BUILD
@@ -42,15 +42,15 @@ java_library(
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/internal/codegen/extension",
"//java/dagger/internal/codegen/kotlin",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr250_annotations",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:service",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/incap",
+ "//third_party/java/javapoet",
+ "//third_party/java/jsr250_annotations",
+ "//third_party/java/jsr330_inject",
],
)
diff --git a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueMetadata.java b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueMetadata.java
index bf5028829..ecd05a8d7 100644
--- a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueMetadata.java
+++ b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueMetadata.java
@@ -30,7 +30,6 @@ import dagger.hilt.processor.internal.Processors;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
import java.util.Collection;
import java.util.Optional;
-import javax.inject.Inject;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
@@ -125,7 +124,7 @@ abstract class BindValueMetadata {
}
ProcessorErrors.checkState(
- !Processors.hasAnnotation(element, Inject.class),
+ !Processors.hasAnnotation(element, ClassNames.INJECT),
element,
"@%s fields cannot be used with @Inject annotation. Found %s",
annotationClassName.simpleName(),
diff --git a/java/dagger/hilt/android/processor/internal/customtestapplication/BUILD b/java/dagger/hilt/android/processor/internal/customtestapplication/BUILD
index e9721d5d3..681ac79c8 100644
--- a/java/dagger/hilt/android/processor/internal/customtestapplication/BUILD
+++ b/java/dagger/hilt/android/processor/internal/customtestapplication/BUILD
@@ -37,13 +37,13 @@ java_library(
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:service",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/incap",
+ "//third_party/java/javapoet",
],
)
diff --git a/java/dagger/hilt/android/processor/internal/viewmodel/BUILD b/java/dagger/hilt/android/processor/internal/viewmodel/BUILD
index b45925fe8..353729d13 100644
--- a/java/dagger/hilt/android/processor/internal/viewmodel/BUILD
+++ b/java/dagger/hilt/android/processor/internal/viewmodel/BUILD
@@ -38,11 +38,11 @@ kt_jvm_library(
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:service",
+ "//third_party/java/guava/collect",
+ "//third_party/java/incap",
+ "//third_party/java/javapoet",
],
)
@@ -60,10 +60,10 @@ kt_jvm_library(
"//:spi",
"//java/dagger/hilt/android/processor/internal:android_classnames",
"//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/guava:graph",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:service",
+ "//third_party/java/guava/graph",
+ "//third_party/java/javapoet",
],
)
diff --git a/java/dagger/hilt/android/qualifiers/BUILD b/java/dagger/hilt/android/qualifiers/BUILD
index 26b45ec74..51bb8422e 100644
--- a/java/dagger/hilt/android/qualifiers/BUILD
+++ b/java/dagger/hilt/android/qualifiers/BUILD
@@ -25,7 +25,7 @@ android_library(
],
deps = [
":package_info",
- "@google_bazel_common//third_party/java/jsr330_inject",
+ "//third_party/java/jsr330_inject",
],
)
diff --git a/java/dagger/hilt/android/scopes/BUILD b/java/dagger/hilt/android/scopes/BUILD
index 5abc27e09..d89176f1e 100644
--- a/java/dagger/hilt/android/scopes/BUILD
+++ b/java/dagger/hilt/android/scopes/BUILD
@@ -29,7 +29,7 @@ android_library(
],
deps = [
":package_info",
- "@google_bazel_common//third_party/java/jsr330_inject",
+ "//third_party/java/jsr330_inject",
],
)
diff --git a/java/dagger/hilt/android/testing/BUILD b/java/dagger/hilt/android/testing/BUILD
index 93d4ceb94..85dea9df4 100644
--- a/java/dagger/hilt/android/testing/BUILD
+++ b/java/dagger/hilt/android/testing/BUILD
@@ -42,7 +42,8 @@ android_library(
testonly = 1,
srcs = ["HiltAndroidTest.java"],
exported_plugins = [
- "//java/dagger/hilt/processor/internal/root:plugin",
+ "//java/dagger/hilt/processor/internal/root:component_tree_deps_plugin",
+ "//java/dagger/hilt/processor/internal/root:root_plugin",
"//java/dagger/hilt/android/processor/internal/androidentrypoint:plugin",
"//java/dagger/hilt/android/processor/internal/viewmodel:validation_plugin",
],
@@ -54,7 +55,9 @@ android_library(
"//:dagger_with_compiler",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android/components",
+ "//java/dagger/hilt/android/internal",
"//java/dagger/hilt/android/internal/builders",
+ "//java/dagger/hilt/android/internal/legacy:aggregated_element_proxy",
"//java/dagger/hilt/android/internal/managers",
"//java/dagger/hilt/android/internal/modules",
"//java/dagger/hilt/android/internal/testing:early_test_singleton_component_creator",
@@ -71,6 +74,7 @@ android_library(
"//java/dagger/hilt/internal:preconditions",
"//java/dagger/hilt/internal:test_singleton_component",
"//java/dagger/hilt/internal/aggregatedroot",
+ "//java/dagger/hilt/internal/componenttreedeps",
"//java/dagger/hilt/internal/processedrootsentinel",
"//java/dagger/hilt/migration:disable_install_in_check",
"@maven//:androidx_annotation_annotation",
@@ -118,10 +122,11 @@ android_library(
":package_info",
"//:dagger_with_compiler",
"//java/dagger/hilt:entry_point",
+ "//java/dagger/hilt/android/internal",
"//java/dagger/hilt/android/internal/testing:test_application_component_manager_holder",
"//java/dagger/hilt/internal:component_manager",
"//java/dagger/hilt/internal:preconditions",
- "@google_bazel_common//third_party/java/auto:value",
+ "//third_party/java/auto:value",
],
)
@@ -141,7 +146,7 @@ android_library(
],
)
-java_library(
+android_library(
name = "bind_value",
testonly = 1,
srcs = [
@@ -167,7 +172,7 @@ java_library(
name = "package_info",
srcs = ["package-info.java"],
deps = [
- "@google_bazel_common//third_party/java/jsr305_annotations",
+ "//third_party/java/jsr305_annotations",
],
)
@@ -226,6 +231,7 @@ gen_maven_artifact(
"com.google.dagger:hilt-android",
"javax.inject:javax.inject",
"junit:junit",
+ "org.jetbrains.kotlin:kotlin-stdlib",
],
artifact_target_maven_deps_banned = [
"com.google.guava:guava",
diff --git a/java/dagger/hilt/android/testing/OnComponentReadyRunner.java b/java/dagger/hilt/android/testing/OnComponentReadyRunner.java
index 925a19f49..dd670d576 100644
--- a/java/dagger/hilt/android/testing/OnComponentReadyRunner.java
+++ b/java/dagger/hilt/android/testing/OnComponentReadyRunner.java
@@ -20,6 +20,7 @@ import android.app.Application;
import android.content.Context;
import com.google.auto.value.AutoValue;
import dagger.hilt.EntryPoints;
+import dagger.hilt.android.internal.Contexts;
import dagger.hilt.android.internal.testing.TestApplicationComponentManagerHolder;
import dagger.hilt.internal.GeneratedComponentManager;
import dagger.hilt.internal.Preconditions;
@@ -48,7 +49,7 @@ public final class OnComponentReadyRunner {
/** Must be called on the test thread, before the Statement is evaluated. */
public static <T> void addListener(
Context context, Class<T> entryPoint, OnComponentReadyListener<T> listener) {
- Application application = (Application) context.getApplicationContext();
+ Application application = Contexts.getApplication(context.getApplicationContext());
if (application instanceof TestApplicationComponentManagerHolder) {
TestApplicationComponentManagerHolder managerHolder =
(TestApplicationComponentManagerHolder) application;
diff --git a/javatests/dagger/hilt/android/processor/BUILD b/java/dagger/hilt/android/testing/compile/BUILD
index 4ec4d56a6..72fb0c2dc 100644
--- a/javatests/dagger/hilt/android/processor/BUILD
+++ b/java/dagger/hilt/android/testing/compile/BUILD
@@ -17,22 +17,25 @@
package(default_visibility = ["//:src"])
java_library(
- name = "android_compilers",
- srcs = ["AndroidCompilers.java"],
+ name = "compile",
+ testonly = 1,
+ srcs = ["HiltCompilerTests.java"],
deps = [
+ "//third_party/java/guava/collect",
+ "//third_party/java/compile_testing",
"//java/dagger/hilt/android/processor/internal/androidentrypoint:processor_lib",
"//java/dagger/hilt/android/processor/internal/customtestapplication:processor_lib",
"//java/dagger/hilt/processor/internal/aggregateddeps:processor_lib",
+ "//java/dagger/hilt/processor/internal/aliasof:processor_lib",
"//java/dagger/hilt/processor/internal/definecomponent:processor_lib",
"//java/dagger/hilt/processor/internal/earlyentrypoint:processor_lib",
"//java/dagger/hilt/processor/internal/generatesrootinput:processor_lib",
"//java/dagger/hilt/processor/internal/originatingelement:processor_lib",
- "//java/dagger/hilt/processor/internal/root:processor_lib",
+ "//java/dagger/hilt/processor/internal/root:component_tree_deps_processor_lib",
+ "//java/dagger/hilt/processor/internal/root:root_processor_lib",
"//java/dagger/hilt/processor/internal/uninstallmodules:processor_lib",
"//java/dagger/internal/codegen:processor",
- "//java/dagger/internal/guava:collect",
"//java/dagger/testing/compile",
- "@google_bazel_common//third_party/java/compile_testing",
"@maven//:com_github_tschuchortdev_kotlin_compile_testing",
],
)
diff --git a/javatests/dagger/hilt/android/processor/AndroidCompilers.java b/java/dagger/hilt/android/testing/compile/HiltCompilerTests.java
index 1fb19ae3e..68a2add5f 100644
--- a/javatests/dagger/hilt/android/processor/AndroidCompilers.java
+++ b/java/dagger/hilt/android/testing/compile/HiltCompilerTests.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package dagger.hilt.android.processor;
+package dagger.hilt.android.testing.compile;
import static java.util.stream.Collectors.toMap;
@@ -23,30 +23,36 @@ import com.google.testing.compile.Compiler;
import dagger.hilt.android.processor.internal.androidentrypoint.AndroidEntryPointProcessor;
import dagger.hilt.android.processor.internal.customtestapplication.CustomTestApplicationProcessor;
import dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsProcessor;
+import dagger.hilt.processor.internal.aliasof.AliasOfProcessor;
import dagger.hilt.processor.internal.definecomponent.DefineComponentProcessor;
import dagger.hilt.processor.internal.earlyentrypoint.EarlyEntryPointProcessor;
import dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputProcessor;
import dagger.hilt.processor.internal.originatingelement.OriginatingElementProcessor;
+import dagger.hilt.processor.internal.root.ComponentTreeDepsProcessor;
import dagger.hilt.processor.internal.root.RootProcessor;
import dagger.hilt.processor.internal.uninstallmodules.UninstallModulesProcessor;
import dagger.internal.codegen.ComponentProcessor;
import dagger.testing.compile.CompilerTests;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Map;
import javax.annotation.processing.Processor;
import com.tschuchort.compiletesting.KotlinCompilation;
/** {@link Compiler} instances for testing Android Hilt. */
-public final class AndroidCompilers {
+public final class HiltCompilerTests {
public static Compiler compiler(Processor... extraProcessors) {
+ return compiler(Arrays.asList(extraProcessors));
+ }
+
+ public static Compiler compiler(Collection<? extends Processor> extraProcessors) {
Map<Class<?>, Processor> processors =
defaultProcessors().stream()
.collect(toMap((Processor e) -> e.getClass(), (Processor e) -> e));
// Adds extra processors, and allows overriding any processors of the same class.
- Arrays.stream(extraProcessors)
- .forEach(processor -> processors.put(processor.getClass(), processor));
+ extraProcessors.stream().forEach(processor -> processors.put(processor.getClass(), processor));
return CompilerTests.compiler().withProcessors(processors.values());
}
@@ -66,16 +72,18 @@ public final class AndroidCompilers {
private static ImmutableList<Processor> defaultProcessors() {
return ImmutableList.of(
new AggregatedDepsProcessor(),
+ new AliasOfProcessor(),
new AndroidEntryPointProcessor(),
new ComponentProcessor(),
+ new ComponentTreeDepsProcessor(),
+ new CustomTestApplicationProcessor(),
new DefineComponentProcessor(),
new EarlyEntryPointProcessor(),
new GeneratesRootInputProcessor(),
new OriginatingElementProcessor(),
- new CustomTestApplicationProcessor(),
- new UninstallModulesProcessor(),
- new RootProcessor());
+ new RootProcessor(),
+ new UninstallModulesProcessor());
}
- private AndroidCompilers() {}
+ private HiltCompilerTests() {}
}
diff --git a/java/dagger/hilt/components/BUILD b/java/dagger/hilt/components/BUILD
index 48dc8cd26..9baf4762b 100644
--- a/java/dagger/hilt/components/BUILD
+++ b/java/dagger/hilt/components/BUILD
@@ -25,7 +25,7 @@ java_library(
deps = [
":package_info",
"//java/dagger/hilt:define_component",
- "@google_bazel_common//third_party/java/jsr330_inject",
+ "//third_party/java/jsr330_inject",
],
)
diff --git a/java/dagger/hilt/internal/aggregatedroot/AggregatedRoot.java b/java/dagger/hilt/internal/aggregatedroot/AggregatedRoot.java
index b53ee7258..a6aa5a50c 100644
--- a/java/dagger/hilt/internal/aggregatedroot/AggregatedRoot.java
+++ b/java/dagger/hilt/internal/aggregatedroot/AggregatedRoot.java
@@ -30,5 +30,7 @@ import java.lang.annotation.Target;
public @interface AggregatedRoot {
String root();
+ String originatingRoot();
+
Class<?> rootAnnotation();
}
diff --git a/java/dagger/hilt/internal/aliasof/AliasOfPropagatedData.java b/java/dagger/hilt/internal/aliasof/AliasOfPropagatedData.java
index 25ea7043a..53c5caefc 100644
--- a/java/dagger/hilt/internal/aliasof/AliasOfPropagatedData.java
+++ b/java/dagger/hilt/internal/aliasof/AliasOfPropagatedData.java
@@ -26,7 +26,7 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface AliasOfPropagatedData {
- Class<? extends Annotation> defineComponentScope();
+ Class<? extends Annotation>[] defineComponentScopes();
Class<? extends Annotation> alias();
}
diff --git a/java/dagger/hilt/android/example/BUILD b/java/dagger/hilt/internal/componenttreedeps/BUILD
index 2a4c19450..1a100d569 100644
--- a/java/dagger/hilt/android/example/BUILD
+++ b/java/dagger/hilt/internal/componenttreedeps/BUILD
@@ -1,4 +1,4 @@
-# Copyright (C) 2017 The Dagger Authors.
+# Copyright (C) 2021 The Dagger Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -11,17 +11,18 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-#
+
# Description:
-# A skeletal application that demonstrates wiring for an injected Application and Activity.
+# The annotation for aggregating information about Hilt roots.
package(default_visibility = ["//:src"])
+java_library(
+ name = "componenttreedeps",
+ srcs = ["ComponentTreeDeps.java"],
+)
+
filegroup(
name = "srcs_filegroup",
- srcs = glob(
- ["**/*"],
- # Exclude Gradle build folder to enable working along side Bazel
- exclude = ["**/build/**"],
- ),
+ srcs = glob(["*"]),
)
diff --git a/java/dagger/hilt/internal/componenttreedeps/ComponentTreeDeps.java b/java/dagger/hilt/internal/componenttreedeps/ComponentTreeDeps.java
new file mode 100644
index 000000000..52123e5a2
--- /dev/null
+++ b/java/dagger/hilt/internal/componenttreedeps/ComponentTreeDeps.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.internal.componenttreedeps;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** An annotation that kicks off the generation of a component tree. */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+public @interface ComponentTreeDeps {
+
+ /** Returns the set of {@link dagger.hilt.internal.aggregatedroot.AggregatedRoot} dependencies. */
+ Class<?>[] rootDeps() default {};
+
+ /**
+ * Returns the set of {@link dagger.hilt.internal.definecomponent.DefineComponentClasses}
+ * dependencies.
+ */
+ Class<?>[] defineComponentDeps() default {};
+
+ /** Returns the set of {@link dagger.hilt.internal.aliasof.AliasOfPropagatedData} dependencies. */
+ Class<?>[] aliasOfDeps() default {};
+
+ /** Returns the set of {@link dagger.hilt.internal.aggregateddeps.AggregatedDeps} dependencies. */
+ Class<?>[] aggregatedDeps() default {};
+
+ /**
+ * Returns the set of {@link
+ * dagger.hilt.internal.uninstallmodules.AggregatedUninstallModulesMetadata} dependencies.
+ */
+ Class<?>[] uninstallModulesDeps() default {};
+
+ /**
+ * Returns the set of {@link dagger.hilt.android.earlyentrypoint.AggregatedEarlyEntryPoint}
+ * dependencies.
+ */
+ Class<?>[] earlyEntryPointDeps() default {};
+}
diff --git a/java/dagger/hilt/migration/AliasOf.java b/java/dagger/hilt/migration/AliasOf.java
index b68d4f12d..c26197da4 100644
--- a/java/dagger/hilt/migration/AliasOf.java
+++ b/java/dagger/hilt/migration/AliasOf.java
@@ -41,6 +41,6 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.CLASS)
@GeneratesRootInput
public @interface AliasOf {
- /** Returns the existing Hilt scope that the annotated scope is aliasing. */
- Class<? extends Annotation> value();
+ /** Returns the existing Hilt scope(s) that the annotated scope is aliasing. */
+ Class<? extends Annotation>[] value();
}
diff --git a/java/dagger/hilt/migration/BUILD b/java/dagger/hilt/migration/BUILD
index a14410d0b..446e7a2ea 100644
--- a/java/dagger/hilt/migration/BUILD
+++ b/java/dagger/hilt/migration/BUILD
@@ -16,7 +16,7 @@
package(default_visibility = ["//:src"])
-android_library(
+java_library(
name = "alias_of",
srcs = [
"AliasOf.java",
diff --git a/java/dagger/hilt/processor/BUILD b/java/dagger/hilt/processor/BUILD
index 1f75d0a34..bf2166cd6 100644
--- a/java/dagger/hilt/processor/BUILD
+++ b/java/dagger/hilt/processor/BUILD
@@ -35,7 +35,8 @@ java_library(
"//java/dagger/hilt/processor/internal/earlyentrypoint:processor_lib",
"//java/dagger/hilt/processor/internal/generatesrootinput:processor_lib",
"//java/dagger/hilt/processor/internal/originatingelement:processor_lib",
- "//java/dagger/hilt/processor/internal/root:processor_lib",
+ "//java/dagger/hilt/processor/internal/root:component_tree_deps_processor_lib",
+ "//java/dagger/hilt/processor/internal/root:root_processor_lib",
"//java/dagger/hilt/processor/internal/uninstallmodules:processor_lib",
"//java/dagger/internal/codegen:processor",
],
@@ -87,9 +88,11 @@ gen_maven_artifact(
"//java/dagger/hilt/processor/internal/generatesrootinput:generates_root_inputs",
"//java/dagger/hilt/processor/internal/generatesrootinput:processor_lib",
"//java/dagger/hilt/processor/internal/originatingelement:processor_lib",
- "//java/dagger/hilt/processor/internal/root:processor_lib",
+ "//java/dagger/hilt/processor/internal/root:component_tree_deps_processor_lib",
+ "//java/dagger/hilt/processor/internal/root:root_processor_lib",
"//java/dagger/hilt/processor/internal/root:root_metadata",
"//java/dagger/hilt/processor/internal/root:root_type",
+ "//java/dagger/hilt/processor/internal/root/ir:ir",
"//java/dagger/hilt/processor/internal/uninstallmodules:processor_lib",
"//java/dagger/hilt/processor/internal/uninstallmodules:aggregated_uninstall_modules_metadata",
],
@@ -106,6 +109,7 @@ gen_maven_artifact(
"javax.inject:javax.inject",
"net.ltgt.gradle.incap:incap",
"org.jetbrains.kotlin:kotlin-stdlib",
+ "org.jetbrains.kotlin:kotlin-stdlib-jdk8",
"org.jetbrains.kotlinx:kotlinx-metadata-jvm",
],
javadoc_android_api_level = 30,
@@ -116,8 +120,10 @@ gen_maven_artifact(
javadoc_srcs = [
"//java/dagger/hilt:hilt_processing_filegroup",
],
- shaded_deps = ["@maven//:com_google_auto_auto_common"],
- shaded_rules = ["rule com.google.auto.common.** dagger.hilt.android.shaded.auto.common.@1"],
+ # The shaded deps are added using jarjar, but they won't be shaded until later
+ # due to: https://github.com/google/dagger/issues/2765. For the shaded rules see
+ # util/deploy-hilt.sh
+ shaded_deps = ["//third_party/java/auto:common"],
)
filegroup(
diff --git a/java/dagger/hilt/processor/internal/AggregatedElements.java b/java/dagger/hilt/processor/internal/AggregatedElements.java
index 8ee820fbd..be593e9d2 100644
--- a/java/dagger/hilt/processor/internal/AggregatedElements.java
+++ b/java/dagger/hilt/processor/internal/AggregatedElements.java
@@ -17,10 +17,12 @@
package dagger.hilt.processor.internal;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static javax.lang.model.element.Modifier.PUBLIC;
import com.google.auto.common.MoreElements;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
+import java.util.Optional;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
@@ -28,6 +30,34 @@ import javax.lang.model.util.Elements;
/** Utility class for aggregating metadata. */
public final class AggregatedElements {
+ /** Returns the class name of the proxy or {@link Optional#empty()} if a proxy is not needed. */
+ public static Optional<ClassName> aggregatedElementProxyName(TypeElement aggregatedElement) {
+ if (aggregatedElement.getModifiers().contains(PUBLIC)) {
+ // Public aggregated elements do not have proxies.
+ return Optional.empty();
+ }
+ ClassName name = ClassName.get(aggregatedElement);
+ // To avoid going over the class name size limit, just prepend a single character.
+ return Optional.of(name.peerClass("_" + name.simpleName()));
+ }
+
+ /** Returns back the set of input {@code aggregatedElements} with all proxies unwrapped. */
+ public static ImmutableSet<TypeElement> unwrapProxies(
+ ImmutableSet<TypeElement> aggregatedElements, Elements elements) {
+ return aggregatedElements.stream()
+ .map(aggregatedElement -> unwrapProxy(aggregatedElement, elements))
+ .collect(toImmutableSet());
+ }
+
+ private static TypeElement unwrapProxy(TypeElement element, Elements elements) {
+ return Processors.hasAnnotation(element, ClassNames.AGGREGATED_ELEMENT_PROXY)
+ ? Processors.getAnnotationClassValue(
+ elements,
+ Processors.getAnnotationMirror(element, ClassNames.AGGREGATED_ELEMENT_PROXY),
+ "value")
+ : element;
+ }
+
/** Returns all aggregated elements in the aggregating package after validating them. */
public static ImmutableSet<TypeElement> from(
String aggregatingPackage, ClassName aggregatingAnnotation, Elements elements) {
@@ -40,6 +70,10 @@ public final class AggregatedElements {
ImmutableSet<TypeElement> aggregatedElements =
packageElement.getEnclosedElements().stream()
.map(MoreElements::asType)
+ // We're only interested in returning the original deps here. Proxies will be generated
+ // (if needed) and swapped just before generating @ComponentTreeDeps.
+ .filter(
+ element -> !Processors.hasAnnotation(element, ClassNames.AGGREGATED_ELEMENT_PROXY))
.collect(toImmutableSet());
ProcessorErrors.checkState(
diff --git a/java/dagger/hilt/processor/internal/BUILD b/java/dagger/hilt/processor/internal/BUILD
index 978655dea..b63a899dc 100644
--- a/java/dagger/hilt/processor/internal/BUILD
+++ b/java/dagger/hilt/processor/internal/BUILD
@@ -27,11 +27,11 @@ java_library(
":compiler_options",
":processor_errors",
":processors",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
@@ -43,11 +43,11 @@ java_library(
"ProcessorErrors.java",
],
deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@google_bazel_common//third_party/java/jsr305_annotations",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/error_prone:annotations",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/jsr305_annotations",
],
)
@@ -63,11 +63,11 @@ java_library(
":processor_errors",
"//java/dagger/internal/codegen/extension",
"//java/dagger/internal/codegen/kotlin",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
+ "//third_party/java/jsr330_inject",
"@maven//:org_jetbrains_kotlin_kotlin_stdlib",
"@maven//:org_jetbrains_kotlinx_kotlinx_metadata_jvm",
],
@@ -79,7 +79,7 @@ java_library(
"ClassNames.java",
],
deps = [
- "@google_bazel_common//third_party/java/javapoet",
+ "//third_party/java/javapoet",
],
)
@@ -89,11 +89,10 @@ java_library(
"ComponentNames.java",
],
deps = [
- ":classnames",
":processors",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/javapoet",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
@@ -103,12 +102,13 @@ java_library(
"AggregatedElements.java",
],
deps = [
+ ":classnames",
":processor_errors",
":processors",
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
@@ -116,9 +116,9 @@ java_library(
name = "component_descriptor",
srcs = ["ComponentDescriptor.java"],
deps = [
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
@@ -135,10 +135,10 @@ java_library(
":processors",
"//java/dagger/hilt/processor/internal/definecomponent:define_components",
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
@@ -156,8 +156,9 @@ java_library(
srcs = ["HiltCompilerOptions.java"],
deps = [
":processor_errors",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/javapoet",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
diff --git a/java/dagger/hilt/processor/internal/BaseProcessor.java b/java/dagger/hilt/processor/internal/BaseProcessor.java
index 1a63f8b47..a92107529 100644
--- a/java/dagger/hilt/processor/internal/BaseProcessor.java
+++ b/java/dagger/hilt/processor/internal/BaseProcessor.java
@@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkState;
import com.google.auto.common.MoreElements;
import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.SetMultimap;
import com.squareup.javapoet.ClassName;
@@ -102,7 +103,15 @@ public abstract class BaseProcessor extends AbstractProcessor {
// warning if any used option is not unsupported. This can happen when there is a module
// which uses Hilt but lacks any @AndroidEntryPoint annotations.
// See: https://github.com/google/dagger/issues/2040
- return HiltCompilerOptions.getProcessorOptions();
+ return ImmutableSet.<String>builder()
+ .addAll(HiltCompilerOptions.getProcessorOptions())
+ .addAll(additionalProcessingOptions())
+ .build();
+ }
+
+ /** Returns additional processing options that should only be applied for a single processor. */
+ protected Set<String> additionalProcessingOptions() {
+ return ImmutableSet.of();
}
/** Used to perform initialization before each round of processing. */
@@ -150,6 +159,7 @@ public abstract class BaseProcessor extends AbstractProcessor {
this.elements = processingEnv.getElementUtils();
this.types = processingEnv.getTypeUtils();
this.errorHandler = new ProcessorErrorHandler(processingEnvironment);
+ HiltCompilerOptions.checkWrongAndDeprecatedOptions(processingEnvironment);
}
@Override
diff --git a/java/dagger/hilt/processor/internal/ClassNames.java b/java/dagger/hilt/processor/internal/ClassNames.java
index 093e1b3d5..dd65202e5 100644
--- a/java/dagger/hilt/processor/internal/ClassNames.java
+++ b/java/dagger/hilt/processor/internal/ClassNames.java
@@ -22,6 +22,11 @@ import com.squareup.javapoet.ClassName;
/** Holder for commonly used class names. */
public final class ClassNames {
+ public static final ClassName AGGREGATED_ELEMENT_PROXY =
+ get("dagger.hilt.android.internal.legacy", "AggregatedElementProxy");
+ public static final ClassName COMPONENT_TREE_DEPS =
+ get("dagger.hilt.internal.componenttreedeps", "ComponentTreeDeps");
+
public static final String AGGREGATED_ROOT_PACKAGE =
"dagger.hilt.internal.aggregatedroot.codegen";
public static final ClassName AGGREGATED_ROOT =
@@ -31,6 +36,8 @@ public final class ClassNames {
public static final ClassName PROCESSED_ROOT_SENTINEL =
get("dagger.hilt.internal.processedrootsentinel", "ProcessedRootSentinel");
+ public static final ClassName CONTEXTS = get("dagger.hilt.android.internal", "Contexts");
+
public static final String AGGREGATED_EARLY_ENTRY_POINT_PACKAGE =
"dagger.hilt.android.internal.earlyentrypoint.codegen";
public static final ClassName AGGREGATED_EARLY_ENTRY_POINT =
@@ -202,6 +209,9 @@ public final class ClassNames {
public static final ClassName OBJECT = get("java.lang", "Object");
+ public static final ClassName SUPPRESS_WARNINGS = get("java.lang", "SuppressWarnings");
+ public static final ClassName KOTLIN_SUPPRESS = get("kotlin", "Suppress");
+
// Kotlin-specific class names
public static final ClassName KOTLIN_METADATA = get("kotlin", "Metadata");
diff --git a/java/dagger/hilt/processor/internal/ComponentNames.java b/java/dagger/hilt/processor/internal/ComponentNames.java
index eeaa5f44b..f3f0444e7 100644
--- a/java/dagger/hilt/processor/internal/ComponentNames.java
+++ b/java/dagger/hilt/processor/internal/ComponentNames.java
@@ -16,25 +16,8 @@
package dagger.hilt.processor.internal;
-import static java.lang.Character.isUpperCase;
-import static java.lang.String.format;
-import static java.util.Comparator.comparing;
-
-import com.google.common.base.CharMatcher;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Multimaps;
import com.squareup.javapoet.ClassName;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-import javax.lang.model.element.Name;
-import javax.lang.model.element.TypeElement;
+import java.util.function.Function;
/**
* Utility class for getting the generated component name.
@@ -42,41 +25,38 @@ import javax.lang.model.element.TypeElement;
* <p>This should not be used externally.
*/
public final class ComponentNames {
- private static final Splitter QUALIFIED_NAME_SPLITTER = Splitter.on('.');
-
- private final boolean renameTestComponents;
- private final String destinationPackage;
- private final ImmutableMap<ClassName, String> simpleNameByClassName;
+ /**
+ * Returns an instance of {@link ComponentNames} that will base all component names off of the
+ * given root.
+ */
public static ComponentNames withoutRenaming() {
- return new ComponentNames(
- /*renameTestComponents=*/ false, /*destinationPackage=*/ null, ImmutableMap.of());
+ return new ComponentNames(Function.identity());
+ }
+
+ /**
+ * Returns an instance of {@link ComponentNames} that will base all component names off of the
+ * given root after mapping it with {@code rootRenamer}.
+ */
+ public static ComponentNames withRenaming(Function<ClassName, ClassName> rootRenamer) {
+ return new ComponentNames(rootRenamer);
}
- public static ComponentNames withRenamingIntoPackage(
- String destinationPackage, ImmutableList<TypeElement> roots) {
- ImmutableMap.Builder<ClassName, String> builder = ImmutableMap.builder();
- ImmutableListMultimap<String, TypeElement> rootsBySimpleName =
- Multimaps.index(roots, typeElement -> typeElement.getSimpleName().toString());
- rootsBySimpleName.asMap().values().stream()
- .map(ComponentNames::disambiguateConflictingSimpleNames)
- .forEach(builder::putAll);
- return new ComponentNames(/*renameTestComponents=*/ true, destinationPackage, builder.build());
+ private final Function<ClassName, ClassName> rootRenamer;
+
+ private ComponentNames(Function<ClassName, ClassName> rootRenamer) {
+ this.rootRenamer = rootRenamer;
}
- private ComponentNames(
- boolean renameTestComponents,
- String destinationPackage,
- ImmutableMap<ClassName, String> simpleNameByClassName) {
- this.renameTestComponents = renameTestComponents;
- this.destinationPackage = destinationPackage;
- this.simpleNameByClassName = simpleNameByClassName;
+ public ClassName generatedComponentTreeDeps(ClassName root) {
+ return Processors.append(
+ Processors.getEnclosedClassName(rootRenamer.apply(root)), "_ComponentTreeDeps");
}
/** Returns the name of the generated component wrapper. */
public ClassName generatedComponentsWrapper(ClassName root) {
return Processors.append(
- Processors.getEnclosedClassName(maybeRenameComponent(root)), "_HiltComponents");
+ Processors.getEnclosedClassName(rootRenamer.apply(root)), "_HiltComponents");
}
/** Returns the name of the generated component. */
@@ -99,81 +79,4 @@ public final class ComponentNames {
return Processors.getEnclosedName(component).replaceAll("Component$", "C");
}
- /**
- * Rewrites the provided HiltAndroidTest-annotated class name using the shared component
- * directory.
- */
- private ClassName maybeRenameComponent(ClassName className) {
- return (renameTestComponents && !className.equals(ClassNames.DEFAULT_ROOT))
- ? ClassName.get(destinationPackage, dedupeSimpleName(className))
- : className;
- }
-
- /**
- * Derives a new generated component base name, should the simple names of two roots have
- * conflicting simple names.
- *
- * <p>This is lifted nearly verbatim (albeit with new different struct types) from {@link
- * dagger.internal.codegen.writing.SubcomponentNames}.
- */
- private String dedupeSimpleName(ClassName className) {
- Preconditions.checkState(
- simpleNameByClassName.containsKey(className),
- "Class name %s not found in simple name map",
- className.canonicalName());
- return simpleNameByClassName.get(className);
- }
-
- private static ImmutableMap<ClassName, String> disambiguateConflictingSimpleNames(
- Collection<TypeElement> rootsWithConflictingNames) {
- // If there's only 1 root there's nothing to disambiguate so return the simple name.
- if (rootsWithConflictingNames.size() == 1) {
- TypeElement root = Iterables.getOnlyElement(rootsWithConflictingNames);
- return ImmutableMap.of(ClassName.get(root), root.getSimpleName().toString());
- }
-
- // There are conflicting simple names, so disambiguate them with a unique prefix.
- // We keep them small to fix https://github.com/google/dagger/issues/421.
- // Sorted in order to guarantee determinism if this is invoked by different processors.
- ImmutableList<TypeElement> sortedRootsWithConflictingNames =
- ImmutableList.sortedCopyOf(
- comparing(typeElement -> typeElement.getQualifiedName().toString()),
- rootsWithConflictingNames);
- Set<String> usedNames = new HashSet<>();
- ImmutableMap.Builder<ClassName, String> uniqueNames = ImmutableMap.builder();
- for (TypeElement root : sortedRootsWithConflictingNames) {
- String basePrefix = uniquingPrefix(root);
- String uniqueName = basePrefix;
- for (int differentiator = 2; !usedNames.add(uniqueName); differentiator++) {
- uniqueName = basePrefix + differentiator;
- }
- uniqueNames.put(ClassName.get(root), format("%s_%s", uniqueName, root.getSimpleName()));
- }
- return uniqueNames.build();
- }
-
- /** Returns a prefix that could make the component's simple name more unique. */
- private static String uniquingPrefix(TypeElement typeElement) {
- String containerName = typeElement.getEnclosingElement().getSimpleName().toString();
-
- // If parent element looks like a class, use its initials as a prefix.
- if (!containerName.isEmpty() && isUpperCase(containerName.charAt(0))) {
- return CharMatcher.javaLowerCase().removeFrom(containerName);
- }
-
- // Not in a normally named class. Prefix with the initials of the elements leading here.
- Name qualifiedName = typeElement.getQualifiedName();
- Iterator<String> pieces = QUALIFIED_NAME_SPLITTER.split(qualifiedName).iterator();
- StringBuilder b = new StringBuilder();
-
- while (pieces.hasNext()) {
- String next = pieces.next();
- if (pieces.hasNext()) {
- b.append(next.charAt(0));
- }
- }
-
- // Note that a top level class in the root package will be prefixed "$_".
- return b.length() > 0 ? b.toString() : "$";
- }
}
diff --git a/java/dagger/hilt/processor/internal/HiltCompilerOptions.java b/java/dagger/hilt/processor/internal/HiltCompilerOptions.java
index 0d248239b..b06faedb6 100644
--- a/java/dagger/hilt/processor/internal/HiltCompilerOptions.java
+++ b/java/dagger/hilt/processor/internal/HiltCompilerOptions.java
@@ -16,12 +16,14 @@
package dagger.hilt.processor.internal;
+import com.google.common.base.Ascii;
import com.google.common.collect.ImmutableSet;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic.Kind;
/** Hilt annotation processor options. */
// TODO(danysantiago): Consider consolidating with Dagger compiler options logic.
@@ -75,16 +77,30 @@ public final class HiltCompilerOptions {
return BooleanOption.SHARE_TEST_COMPONENTS.get(env);
}
+ /**
+ * Returns {@code true} if the aggregating processor is enabled (default is {@code true}).
+ *
+ * <p>Note:This is for internal use only!
+ */
+ public static boolean useAggregatingRootProcessor(ProcessingEnvironment env) {
+ return BooleanOption.USE_AGGREGATING_ROOT_PROCESSOR.get(env);
+ }
+
/** Processor options which can have true or false values. */
private enum BooleanOption {
+ /** Do not use! This is for internal use only. */
DISABLE_ANDROID_SUPERCLASS_VALIDATION(
"android.internal.disableAndroidSuperclassValidation", false),
+ /** Do not use! This is for internal use only. */
+ USE_AGGREGATING_ROOT_PROCESSOR("internal.useAggregatingRootProcessor", true),
+
DISABLE_CROSS_COMPILATION_ROOT_VALIDATION("disableCrossCompilationRootValidation", false),
DISABLE_MODULES_HAVE_INSTALL_IN_CHECK("disableModulesHaveInstallInCheck", false),
- SHARE_TEST_COMPONENTS("shareTestComponents", false);
+ SHARE_TEST_COMPONENTS(
+ "shareTestComponents", true);
private final String name;
private final boolean defaultValue;
@@ -99,8 +115,22 @@ public final class HiltCompilerOptions {
if (value == null) {
return defaultValue;
}
- // TODO(danysantiago): Strictly verify input, either 'true' or 'false' and nothing else.
- return Boolean.parseBoolean(value);
+
+ // Using Boolean.parseBoolean will turn any non-"true" value into false. Strictly verify the
+ // inputs to reduce user errors.
+ String lowercaseValue = Ascii.toLowerCase(value);
+ switch (lowercaseValue) {
+ case "true":
+ return true;
+ case "false":
+ return false;
+ default:
+ throw new IllegalStateException(
+ "Expected a value of true/false for the flag \""
+ + name
+ + "\". Got instead: "
+ + value);
+ }
}
String getQualifiedName() {
@@ -108,6 +138,32 @@ public final class HiltCompilerOptions {
}
}
+ private static final ImmutableSet<String> DEPRECATED_OPTIONS = ImmutableSet.of(
+ "dagger.hilt.android.useFragmentGetContextFix");
+
+ public static void checkWrongAndDeprecatedOptions(ProcessingEnvironment env) {
+ Set<String> knownOptions = getProcessorOptions();
+ for (String option : env.getOptions().keySet()) {
+ if (knownOptions.contains(option)) {
+ continue;
+ }
+
+ if (DEPRECATED_OPTIONS.contains(option)) {
+ env.getMessager().printMessage(
+ Kind.ERROR,
+ "The compiler option " + option + " is deprecated and no longer does anything. "
+ + "Please do not set this option.");
+ continue;
+ }
+
+ if (option.startsWith("dagger.hilt.")) {
+ env.getMessager().printMessage(
+ Kind.ERROR,
+ "The compiler option " + option + " is not a recognized Hilt option. Is there a typo?");
+ }
+ }
+ }
+
public static Set<String> getProcessorOptions() {
return Arrays.stream(BooleanOption.values())
.map(BooleanOption::getQualifiedName)
diff --git a/java/dagger/hilt/processor/internal/Processors.java b/java/dagger/hilt/processor/internal/Processors.java
index 8740bd6a0..4e2e256f9 100644
--- a/java/dagger/hilt/processor/internal/Processors.java
+++ b/java/dagger/hilt/processor/internal/Processors.java
@@ -62,7 +62,6 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
-import javax.inject.Qualifier;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
@@ -104,7 +103,7 @@ public final class Processors {
.addModifiers(PUBLIC)
.addOriginatingElement(element)
.addAnnotation(aggregatingAnnotation)
- .addJavadoc("This class should only be referenced by generated code!")
+ .addJavadoc("This class should only be referenced by generated code! ")
.addJavadoc("This class aggregates information across multiple compilations.\n");;
addGeneratedAnnotation(builder, env, generatedAnnotationClass);
@@ -767,7 +766,7 @@ public final class Processors {
public static ImmutableList<AnnotationMirror> getQualifierAnnotations(Element element) {
// TODO(bcorso): Consolidate this logic with InjectionAnnotations in Dagger
ImmutableSet<? extends AnnotationMirror> qualifiers =
- AnnotationMirrors.getAnnotatedAnnotations(element, Qualifier.class);
+ AnnotationMirrors.getAnnotatedAnnotations(element, ClassNames.QUALIFIER.canonicalName());
KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil();
if (element.getKind() == ElementKind.FIELD
// static fields are generally not supported, no need to get qualifier from kotlin metadata
@@ -779,7 +778,7 @@ public final class Processors {
metadataUtil.isMissingSyntheticPropertyForAnnotations(fieldElement)
? Stream.empty()
: metadataUtil
- .getSyntheticPropertyAnnotations(fieldElement, Qualifier.class)
+ .getSyntheticPropertyAnnotations(fieldElement, ClassNames.QUALIFIER)
.stream())
.map(AnnotationMirrors.equivalence()::wrap)
.distinct()
@@ -931,6 +930,17 @@ public final class Processors {
&& !KotlinMetadataUtils.getMetadataUtil().isObjectOrCompanionObjectClass(module);
}
+ public static boolean hasVisibleEmptyConstructor(TypeElement type) {
+ List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
+ return constructors.isEmpty()
+ || constructors.stream()
+ .filter(constructor -> constructor.getParameters().isEmpty())
+ .anyMatch(
+ constructor ->
+ !constructor.getModifiers().contains(Modifier.PRIVATE)
+ );
+ }
+
private static boolean isBindingMethod(ExecutableElement method) {
return hasAnnotation(method, ClassNames.PROVIDES)
|| hasAnnotation(method, ClassNames.BINDS)
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java
index 09e1651fe..9217a574d 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java
@@ -24,11 +24,14 @@ import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.AggregatedElements;
import dagger.hilt.processor.internal.AnnotationValues;
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.Processors;
+import dagger.hilt.processor.internal.root.ir.AggregatedDepsIr;
import java.util.Optional;
+import java.util.stream.Collectors;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.TypeElement;
@@ -39,7 +42,7 @@ import javax.lang.model.util.Elements;
* dagger.hilt.processor.internal.aggregateddeps.AggregatedDeps} annotation.
*/
@AutoValue
-abstract class AggregatedDepsMetadata {
+public abstract class AggregatedDepsMetadata {
private static final String AGGREGATED_DEPS_PACKAGE = "hilt_aggregated_deps";
enum DependencyType {
@@ -48,24 +51,61 @@ abstract class AggregatedDepsMetadata {
COMPONENT_ENTRY_POINT
}
- abstract Optional<TypeElement> testElement();
+ /** Returns the aggregating element */
+ public abstract TypeElement aggregatingElement();
- abstract ImmutableSet<TypeElement> componentElements();
+ public abstract Optional<TypeElement> testElement();
+
+ public abstract ImmutableSet<TypeElement> componentElements();
abstract DependencyType dependencyType();
abstract TypeElement dependency();
- abstract ImmutableSet<TypeElement> replacedDependencies();
+ public abstract ImmutableSet<TypeElement> replacedDependencies();
+
+ public boolean isModule() {
+ return dependencyType() == DependencyType.MODULE;
+ }
- /** Returns all aggregated deps in the aggregating package. */
+ /** Returns metadata for all aggregated elements in the aggregating package. */
public static ImmutableSet<AggregatedDepsMetadata> from(Elements elements) {
- return AggregatedElements.from(AGGREGATED_DEPS_PACKAGE, ClassNames.AGGREGATED_DEPS, elements)
- .stream()
+ return from(
+ AggregatedElements.from(AGGREGATED_DEPS_PACKAGE, ClassNames.AGGREGATED_DEPS, elements),
+ elements);
+ }
+
+ /** Returns metadata for each aggregated element. */
+ public static ImmutableSet<AggregatedDepsMetadata> from(
+ ImmutableSet<TypeElement> aggregatedElements, Elements elements) {
+ return aggregatedElements.stream()
.map(aggregatedElement -> create(aggregatedElement, elements))
.collect(toImmutableSet());
}
+ public static AggregatedDepsIr toIr(AggregatedDepsMetadata metadata) {
+ return new AggregatedDepsIr(
+ ClassName.get(metadata.aggregatingElement()),
+ metadata.componentElements().stream()
+ .map(ClassName::get)
+ .collect(Collectors.toList()),
+ metadata.testElement()
+ .map(ClassName::get)
+ .orElse(null),
+ metadata.replacedDependencies().stream()
+ .map(ClassName::get)
+ .collect(Collectors.toList()),
+ metadata.dependencyType() == DependencyType.MODULE
+ ? ClassName.get(metadata.dependency())
+ : null,
+ metadata.dependencyType() == DependencyType.ENTRY_POINT
+ ? ClassName.get(metadata.dependency())
+ : null,
+ metadata.dependencyType() == DependencyType.COMPONENT_ENTRY_POINT
+ ? ClassName.get(metadata.dependency())
+ : null);
+ }
+
private static AggregatedDepsMetadata create(TypeElement element, Elements elements) {
AnnotationMirror annotationMirror =
Processors.getAnnotationMirror(element, ClassNames.AGGREGATED_DEPS);
@@ -74,12 +114,11 @@ abstract class AggregatedDepsMetadata {
Processors.getAnnotationValues(elements, annotationMirror);
return new AutoValue_AggregatedDepsMetadata(
+ element,
getTestElement(values.get("test"), elements),
getComponents(values.get("components"), elements),
getDependencyType(
- values.get("modules"),
- values.get("entryPoints"),
- values.get("componentEntryPoints")),
+ values.get("modules"), values.get("entryPoints"), values.get("componentEntryPoints")),
getDependency(
values.get("modules"),
values.get("entryPoints"),
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java
index 151401e60..184894af8 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java
@@ -26,7 +26,6 @@ import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static javax.lang.model.element.ElementKind.CLASS;
import static javax.lang.model.element.ElementKind.INTERFACE;
import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.STATIC;
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING;
@@ -135,7 +134,7 @@ public final class AggregatedDepsProcessor extends BaseProcessor {
|| installInCheckDisabled(element),
element,
"%s is missing an @InstallIn annotation. If this was intentional, see"
- + " https://dagger.dev/hilt/compiler-options#disable-install-in-check for how to disable this"
+ + " https://dagger.dev/hilt/flags#disable-install-in-check for how to disable this"
+ " check.",
element);
@@ -167,8 +166,8 @@ public final class AggregatedDepsProcessor extends BaseProcessor {
ProcessorErrors.checkState(
// Skip ApplicationContextModule, since Hilt manages this module internally.
ClassNames.APPLICATION_CONTEXT_MODULE.equals(ClassName.get(module))
- || !Processors.requiresModuleInstance(getElementUtils(), module)
- || hasVisibleEmptyConstructor(module),
+ || !Processors.requiresModuleInstance(getElementUtils(), module)
+ || Processors.hasVisibleEmptyConstructor(module),
module,
"Modules that need to be instantiated by Hilt must have a visible, empty constructor.");
@@ -444,15 +443,4 @@ public final class AggregatedDepsProcessor extends BaseProcessor {
return name.contentEquals("javax.annotation.Generated")
|| name.contentEquals("javax.annotation.processing.Generated");
}
-
- private static boolean hasVisibleEmptyConstructor(TypeElement type) {
- List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
- return constructors.isEmpty()
- || constructors.stream()
- .filter(constructor -> constructor.getParameters().isEmpty())
- .anyMatch(
- constructor ->
- !constructor.getModifiers().contains(PRIVATE)
- );
- }
}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/BUILD b/java/dagger/hilt/processor/internal/aggregateddeps/BUILD
index 5da2241f5..6af6692de 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/BUILD
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/BUILD
@@ -52,11 +52,11 @@ java_library(
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/internal/codegen/extension",
"//java/dagger/internal/codegen/kotlin",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:service",
+ "//third_party/java/guava/collect",
+ "//third_party/java/incap",
+ "//third_party/java/javapoet",
],
)
@@ -67,9 +67,9 @@ java_library(
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:kotlin",
"//java/dagger/hilt/processor/internal:processors",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:value",
+ "//third_party/java/javapoet",
],
)
@@ -86,12 +86,13 @@ java_library(
"//java/dagger/hilt/processor/internal:component_descriptor",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/hilt/processor/internal/earlyentrypoint:aggregated_early_entry_point_metadata",
+ "//java/dagger/hilt/processor/internal/root/ir",
"//java/dagger/hilt/processor/internal/uninstallmodules:aggregated_uninstall_modules_metadata",
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java b/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java
index 897ffd144..ed71c98db 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java
@@ -38,204 +38,85 @@ public abstract class ComponentDependencies {
}
/** Returns the modules for a component, without any filtering. */
- public abstract Dependencies modules();
+ public abstract ImmutableSetMultimap<ClassName, TypeElement> modules();
/** Returns the entry points associated with the given a component. */
- public abstract Dependencies entryPoints();
+ public abstract ImmutableSetMultimap<ClassName, TypeElement> entryPoints();
/** Returns the component entry point associated with the given a component. */
- public abstract Dependencies componentEntryPoints();
-
- /** Returns the set of early entry points */
- public abstract ImmutableSet<ClassName> earlyEntryPoints();
-
- /** Returns {@code true} if any entry points are annotated with {@code EarlyEntryPoints}. */
- public boolean hasEarlyEntryPoints() {
- return !earlyEntryPoints().isEmpty();
- }
-
- /**
- * Returns {@code true} if the test binds or uninstalls test-specific bindings that would prevent
- * it from sharing components with other test roots.
- */
- public final boolean includesTestDeps(ClassName root) {
- return modules().testDeps().keySet().stream().anyMatch((key) -> key.test().equals(root))
- || modules().uninstalledTestDeps().containsKey(root);
- }
+ public abstract ImmutableSetMultimap<ClassName, TypeElement> componentEntryPoints();
@AutoValue.Builder
abstract static class Builder {
- abstract Dependencies.Builder modulesBuilder();
+ abstract ImmutableSetMultimap.Builder<ClassName, TypeElement> modulesBuilder();
- abstract Dependencies.Builder entryPointsBuilder();
+ abstract ImmutableSetMultimap.Builder<ClassName, TypeElement> entryPointsBuilder();
- abstract Dependencies.Builder componentEntryPointsBuilder();
-
- abstract ImmutableSet.Builder<ClassName> earlyEntryPointsBuilder();
+ abstract ImmutableSetMultimap.Builder<ClassName, TypeElement> componentEntryPointsBuilder();
abstract ComponentDependencies build();
}
- /** A key used for grouping a test dependency by both its component and test name. */
- @AutoValue
- abstract static class TestDepKey {
- static TestDepKey of(ClassName component, ClassName test) {
- return new AutoValue_ComponentDependencies_TestDepKey(component, test);
- }
-
- /** Returns the name of the component this dependency should be installed in. */
- abstract ClassName component();
-
- /** Returns the name of the test that this dependency should be installed in. */
- abstract ClassName test();
- }
-
- /**
- * Holds a set of component dependencies, e.g. modules or entry points.
- *
- * <p>This class handles separating dependencies into global and test dependencies. Global
- * dependencies are installed with every test, where test dependencies are only installed with the
- * specified test. The total set of dependencies includes all global + test dependencies.
- */
- @AutoValue
- public abstract static class Dependencies {
- static Builder builder() {
- return new AutoValue_ComponentDependencies_Dependencies.Builder();
- }
-
- /** Returns the global deps keyed by component. */
- abstract ImmutableSetMultimap<ClassName, TypeElement> globalDeps();
-
- /** Returns the global test deps keyed by component. */
- abstract ImmutableSetMultimap<ClassName, TypeElement> globalTestDeps();
-
- /** Returns the test deps keyed by component and test. */
- abstract ImmutableSetMultimap<TestDepKey, TypeElement> testDeps();
-
- /** Returns the uninstalled test deps keyed by test. */
- abstract ImmutableSetMultimap<ClassName, TypeElement> uninstalledTestDeps();
-
- /** Returns the global uninstalled test deps. */
- abstract ImmutableSet<TypeElement> globalUninstalledTestDeps();
-
- /** Returns the dependencies to be installed in the global singleton component. */
- ImmutableSet<TypeElement> getGlobalSingletonDeps() {
- return ImmutableSet.<TypeElement>builder()
- .addAll(
- globalDeps().get(ClassNames.SINGLETON_COMPONENT).stream()
- .filter(dep -> !globalUninstalledTestDeps().contains(dep))
- .collect(toImmutableSet()))
- .addAll(globalTestDeps().get(ClassNames.SINGLETON_COMPONENT))
- .build();
- }
-
- /** Returns the dependencies to be installed in the given component for the given root. */
- public ImmutableSet<TypeElement> get(ClassName component, ClassName root, boolean isTestRoot) {
- if (!isTestRoot) {
- return globalDeps().get(component);
- }
-
- ImmutableSet<TypeElement> uninstalledTestDepsForRoot = uninstalledTestDeps().get(root);
- return ImmutableSet.<TypeElement>builder()
- .addAll(
- globalDeps().get(component).stream()
- .filter(dep -> !uninstalledTestDepsForRoot.contains(dep))
- .filter(dep -> !globalUninstalledTestDeps().contains(dep))
- .collect(toImmutableSet()))
- .addAll(globalTestDeps().get(component))
- .addAll(testDeps().get(TestDepKey.of(component, root)))
- .build();
- }
-
- @AutoValue.Builder
- abstract static class Builder {
- abstract ImmutableSetMultimap.Builder<ClassName, TypeElement> globalDepsBuilder();
-
- abstract ImmutableSetMultimap.Builder<ClassName, TypeElement> globalTestDepsBuilder();
-
- abstract ImmutableSetMultimap.Builder<TestDepKey, TypeElement> testDepsBuilder();
-
- abstract ImmutableSetMultimap.Builder<ClassName, TypeElement> uninstalledTestDepsBuilder();
-
- abstract ImmutableSet.Builder<TypeElement> globalUninstalledTestDepsBuilder();
-
- abstract Dependencies build();
- }
- }
-
- /**
- * Pulls the component dependencies from the {@code packageName}.
- *
- * <p>Dependency files are generated by the {@link AggregatedDepsProcessor}, and have the form:
- *
- * <pre>{@code
- * {@literal @}AggregatedDeps(
- * components = {
- * "foo.FooComponent",
- * "bar.BarComponent"
- * },
- * modules = "baz.BazModule"
- * )
- *
- * }</pre>
- */
+ /** Returns the component dependencies for the given metadata. */
public static ComponentDependencies from(
- ImmutableSet<ComponentDescriptor> descriptors, Elements elements) {
+ ImmutableSet<ComponentDescriptor> descriptors,
+ ImmutableSet<AggregatedDepsMetadata> aggregatedDepsMetadata,
+ ImmutableSet<AggregatedUninstallModulesMetadata> aggregatedUninstallModulesMetadata,
+ ImmutableSet<AggregatedEarlyEntryPointMetadata> aggregatedEarlyEntryPointMetadata,
+ Elements elements) {
+ ImmutableSet<TypeElement> uninstalledModules =
+ ImmutableSet.<TypeElement>builder()
+ .addAll(
+ aggregatedUninstallModulesMetadata.stream()
+ .flatMap(metadata -> metadata.uninstallModuleElements().stream())
+ // @AggregatedUninstallModules always references the user module, so convert to
+ // the generated public wrapper if needed.
+ // TODO(bcorso): Consider converting this to the public module in the processor.
+ .map(module -> PkgPrivateMetadata.publicModule(module, elements))
+ .collect(toImmutableSet()))
+ .addAll(
+ aggregatedDepsMetadata.stream()
+ .flatMap(metadata -> metadata.replacedDependencies().stream())
+ .collect(toImmutableSet()))
+ .build();
+
+ ComponentDependencies.Builder componentDependencies = ComponentDependencies.builder();
ImmutableSet<ClassName> componentNames =
descriptors.stream().map(ComponentDescriptor::component).collect(toImmutableSet());
- ComponentDependencies.Builder componentDependencies = ComponentDependencies.builder();
- for (AggregatedDepsMetadata metadata : AggregatedDepsMetadata.from(elements)) {
- Dependencies.Builder builder = null;
- switch (metadata.dependencyType()) {
- case MODULE:
- builder = componentDependencies.modulesBuilder();
- break;
- case ENTRY_POINT:
- builder = componentDependencies.entryPointsBuilder();
- break;
- case COMPONENT_ENTRY_POINT:
- builder = componentDependencies.componentEntryPointsBuilder();
- break;
- }
+ for (AggregatedDepsMetadata metadata : aggregatedDepsMetadata) {
for (TypeElement componentElement : metadata.componentElements()) {
ClassName componentName = ClassName.get(componentElement);
checkState(
componentNames.contains(componentName), "%s is not a valid Component.", componentName);
- if (metadata.testElement().isPresent()) {
- // In this case the @InstallIn or @TestInstallIn applies to only the given test root.
- ClassName test = ClassName.get(metadata.testElement().get());
- builder.testDepsBuilder().put(TestDepKey.of(componentName, test), metadata.dependency());
- builder.uninstalledTestDepsBuilder().putAll(test, metadata.replacedDependencies());
- } else {
- // In this case the @InstallIn or @TestInstallIn applies to all roots
- if (!metadata.replacedDependencies().isEmpty()) {
- // If there are replacedDependencies() it means this is a @TestInstallIn
- builder.globalTestDepsBuilder().put(componentName, metadata.dependency());
- builder.globalUninstalledTestDepsBuilder().addAll(metadata.replacedDependencies());
- } else {
- builder.globalDepsBuilder().put(componentName, metadata.dependency());
- }
+ switch (metadata.dependencyType()) {
+ case MODULE:
+ if (!uninstalledModules.contains(metadata.dependency())) {
+ componentDependencies.modulesBuilder().put(componentName, metadata.dependency());
+ }
+ break;
+ case ENTRY_POINT:
+ componentDependencies.entryPointsBuilder().put(componentName, metadata.dependency());
+ break;
+ case COMPONENT_ENTRY_POINT:
+ componentDependencies
+ .componentEntryPointsBuilder()
+ .put(componentName, metadata.dependency());
+ break;
}
}
}
- AggregatedUninstallModulesMetadata.from(elements)
- .forEach(
- metadata ->
- componentDependencies
- .modulesBuilder()
- .uninstalledTestDepsBuilder()
- .putAll(
- ClassName.get(metadata.testElement()),
- metadata.uninstallModuleElements().stream()
- .map(module -> PkgPrivateMetadata.publicModule(module, elements))
- .collect(toImmutableSet())));
-
- AggregatedEarlyEntryPointMetadata.from(elements).stream()
- .map(AggregatedEarlyEntryPointMetadata::earlyEntryPoint)
- .map(entryPoint -> PkgPrivateMetadata.publicEarlyEntryPoint(entryPoint, elements))
- .map(ClassName::get)
- .forEach(componentDependencies.earlyEntryPointsBuilder()::add);
+ componentDependencies
+ .entryPointsBuilder()
+ .putAll(
+ ClassNames.SINGLETON_COMPONENT,
+ aggregatedEarlyEntryPointMetadata.stream()
+ .map(AggregatedEarlyEntryPointMetadata::earlyEntryPoint)
+ // @AggregatedEarlyEntryPointMetadata always references the user module, so convert
+ // to the generated public wrapper if needed.
+ // TODO(bcorso): Consider converting this to the public module in the processor.
+ .map(entryPoint -> PkgPrivateMetadata.publicEarlyEntryPoint(entryPoint, elements))
+ .collect(toImmutableSet()));
return componentDependencies.build();
}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java b/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java
index ff344a651..41c6b7c75 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java
@@ -44,6 +44,11 @@ public abstract class PkgPrivateMetadata {
return publicDep(element, elements, ClassNames.EARLY_ENTRY_POINT);
}
+ /** Returns the public Hilt wrapped type or the type itself if it is already public. */
+ public static TypeElement publicEntryPoint(TypeElement element, Elements elements) {
+ return publicDep(element, elements, ClassNames.ENTRY_POINT);
+ }
+
private static TypeElement publicDep(
TypeElement element, Elements elements, ClassName annotation) {
return of(elements, element, annotation)
@@ -102,8 +107,11 @@ public abstract class PkgPrivateMetadata {
if (annotation.equals(ClassNames.MODULE)
) {
- // Skip modules that require a module instance. Required by
- // dagger (b/31489617)
+ // Skip modules that require a module instance. Otherwise Dagger validation will (correctly)
+ // fail on the wrapper saying a public module can't include a private one, which makes the
+ // error more confusing for users since they probably aren't aware of the wrapper. When
+ // skipped, if the root is in a different package, the error will instead just be on the
+ // generated Hilt component.
if (Processors.requiresModuleInstance(elements, MoreElements.asType(element))) {
return Optional.empty();
}
diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java
index 02e7f5d56..6c6a73481 100644
--- a/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java
+++ b/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java
@@ -20,6 +20,7 @@ import static com.google.auto.common.MoreElements.asType;
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING;
import com.google.auto.service.AutoService;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import dagger.hilt.processor.internal.BaseProcessor;
import dagger.hilt.processor.internal.ClassNames;
@@ -53,10 +54,16 @@ public final class AliasOfProcessor extends BaseProcessor {
AnnotationMirror annotationMirror =
Processors.getAnnotationMirror(element, ClassNames.ALIAS_OF);
- TypeElement defineComponentScope =
- Processors.getAnnotationClassValue(getElementUtils(), annotationMirror, "value");
+ ImmutableList<TypeElement> defineComponentScopes =
+ Processors.getAnnotationClassValues(getElementUtils(), annotationMirror, "value");
- new AliasOfPropagatedDataGenerator(getProcessingEnv(), asType(element), defineComponentScope)
+ ProcessorErrors.checkState(
+ defineComponentScopes.size() >= 1,
+ element,
+ "@AliasOf annotation %s must declare at least one scope to alias.",
+ annotationMirror);
+
+ new AliasOfPropagatedDataGenerator(getProcessingEnv(), asType(element), defineComponentScopes)
.generate();
}
}
diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java
index 1d7edf285..a2441f916 100644
--- a/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java
+++ b/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java
@@ -16,6 +16,7 @@
package dagger.hilt.processor.internal.aliasof;
+import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.AnnotationSpec;
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.Processors;
@@ -28,26 +29,32 @@ final class AliasOfPropagatedDataGenerator {
private final ProcessingEnvironment processingEnv;
private final TypeElement aliasScope;
- private final TypeElement defineComponentScope;
+ private final ImmutableList<TypeElement> defineComponentScopes;
AliasOfPropagatedDataGenerator(
ProcessingEnvironment processingEnv,
TypeElement aliasScope,
- TypeElement defineComponentScope) {
+ ImmutableList<TypeElement> defineComponentScopes) {
this.processingEnv = processingEnv;
this.aliasScope = aliasScope;
- this.defineComponentScope = defineComponentScope;
+ this.defineComponentScopes = defineComponentScopes;
}
void generate() throws IOException {
Processors.generateAggregatingClass(
ClassNames.ALIAS_OF_PROPAGATED_DATA_PACKAGE,
- AnnotationSpec.builder(ClassNames.ALIAS_OF_PROPAGATED_DATA)
- .addMember("defineComponentScope", "$T.class", defineComponentScope)
- .addMember("alias", "$T.class", aliasScope)
- .build(),
+ propagatedDataAnnotation(),
aliasScope,
getClass(),
processingEnv);
}
+
+ private AnnotationSpec propagatedDataAnnotation() {
+ AnnotationSpec.Builder builder = AnnotationSpec.builder(ClassNames.ALIAS_OF_PROPAGATED_DATA);
+ for (TypeElement defineComponentScope : defineComponentScopes) {
+ builder.addMember("defineComponentScopes", "$T.class", defineComponentScope);
+ }
+ builder.addMember("alias", "$T.class", aliasScope);
+ return builder.build();
+ }
}
diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataMetadata.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataMetadata.java
index 30a2c70c6..d0c89dbd2 100644
--- a/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataMetadata.java
+++ b/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataMetadata.java
@@ -16,15 +16,20 @@
package dagger.hilt.processor.internal.aliasof;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.AggregatedElements;
import dagger.hilt.processor.internal.AnnotationValues;
+import dagger.hilt.processor.internal.BadInputException;
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.Processors;
+import dagger.hilt.processor.internal.root.ir.AliasOfPropagatedDataIr;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.TypeElement;
@@ -35,22 +40,42 @@ import javax.lang.model.util.Elements;
* dagger.hilt.internal.aliasof.AliasOfPropagatedData} annotation.
*/
@AutoValue
-abstract class AliasOfPropagatedDataMetadata {
+public abstract class AliasOfPropagatedDataMetadata {
- abstract TypeElement defineComponentScopeElement();
+ /** Returns the aggregating element */
+ public abstract TypeElement aggregatingElement();
+
+ abstract ImmutableList<TypeElement> defineComponentScopeElements();
abstract TypeElement aliasElement();
- static ImmutableSet<AliasOfPropagatedDataMetadata> from(Elements elements) {
- return AggregatedElements.from(
+ /** Returns metadata for all aggregated elements in the aggregating package. */
+ public static ImmutableSet<AliasOfPropagatedDataMetadata> from(Elements elements) {
+ return from(
+ AggregatedElements.from(
ClassNames.ALIAS_OF_PROPAGATED_DATA_PACKAGE,
ClassNames.ALIAS_OF_PROPAGATED_DATA,
- elements)
- .stream()
+ elements),
+ elements);
+ }
+
+ /** Returns metadata for each aggregated element. */
+ public static ImmutableSet<AliasOfPropagatedDataMetadata> from(
+ ImmutableSet<TypeElement> aggregatedElements, Elements elements) {
+ return aggregatedElements.stream()
.map(aggregatedElement -> create(aggregatedElement, elements))
.collect(toImmutableSet());
}
+ public static AliasOfPropagatedDataIr toIr(AliasOfPropagatedDataMetadata metadata) {
+ return new AliasOfPropagatedDataIr(
+ ClassName.get(metadata.aggregatingElement()),
+ metadata.defineComponentScopeElements().stream()
+ .map(ClassName::get)
+ .collect(toImmutableList()),
+ ClassName.get(metadata.aliasElement()));
+ }
+
private static AliasOfPropagatedDataMetadata create(TypeElement element, Elements elements) {
AnnotationMirror annotationMirror =
Processors.getAnnotationMirror(element, ClassNames.ALIAS_OF_PROPAGATED_DATA);
@@ -58,8 +83,22 @@ abstract class AliasOfPropagatedDataMetadata {
ImmutableMap<String, AnnotationValue> values =
Processors.getAnnotationValues(elements, annotationMirror);
+ ImmutableList<TypeElement> defineComponentScopes;
+ if (values.containsKey("defineComponentScopes")) {
+ defineComponentScopes =
+ ImmutableList.copyOf(
+ AnnotationValues.getTypeElements(values.get("defineComponentScopes")));
+ } else if (values.containsKey("defineComponentScope")) {
+ // Older version of AliasOfPropagatedData only passed a single defineComponentScope class
+ // value. Fall back on reading the single value if we get old propagated data.
+ defineComponentScopes =
+ ImmutableList.of(AnnotationValues.getTypeElement(values.get("defineComponentScope")));
+ } else {
+ throw new BadInputException(
+ "AliasOfPropagatedData is missing defineComponentScopes", element);
+ }
+
return new AutoValue_AliasOfPropagatedDataMetadata(
- AnnotationValues.getTypeElement(values.get("defineComponentScope")),
- AnnotationValues.getTypeElement(values.get("alias")));
+ element, defineComponentScopes, AnnotationValues.getTypeElement(values.get("alias")));
}
}
diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfs.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfs.java
index 18951bdf9..1fee2a31a 100644
--- a/java/dagger/hilt/processor/internal/aliasof/AliasOfs.java
+++ b/java/dagger/hilt/processor/internal/aliasof/AliasOfs.java
@@ -16,35 +16,46 @@
package dagger.hilt.processor.internal.aliasof;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.squareup.javapoet.ClassName;
+import dagger.hilt.processor.internal.ComponentDescriptor;
import dagger.hilt.processor.internal.ProcessorErrors;
-import javax.lang.model.util.Elements;
/**
* Extracts a multimap of aliases annotated with {@link dagger.hilt.migration.AliasOf} mapping them
* to scopes they are alias of.
*/
public final class AliasOfs {
- public static AliasOfs create(Elements elements, ImmutableSet<ClassName> defineComponentScopes) {
+ public static AliasOfs create(
+ ImmutableSet<AliasOfPropagatedDataMetadata> metadatas,
+ ImmutableSet<ComponentDescriptor> componentDescriptors) {
+ ImmutableSet<ClassName> defineComponentScopes =
+ componentDescriptors.stream()
+ .flatMap(descriptor -> descriptor.scopes().stream())
+ .collect(toImmutableSet());
+
ImmutableSetMultimap.Builder<ClassName, ClassName> builder = ImmutableSetMultimap.builder();
- AliasOfPropagatedDataMetadata.from(elements)
- .forEach(
- metadata -> {
- ClassName defineComponentScopeName =
- ClassName.get(metadata.defineComponentScopeElement());
- ClassName aliasScopeName = ClassName.get(metadata.aliasElement());
- ProcessorErrors.checkState(
- defineComponentScopes.contains(defineComponentScopeName),
- metadata.aliasElement(),
- "The scope %s cannot be an alias for %s. You can only have aliases of a scope"
- + " defined directly on a @DefineComponent type.",
- aliasScopeName,
- defineComponentScopeName);
- builder.put(defineComponentScopeName, aliasScopeName);
- });
+ metadatas.forEach(
+ metadata -> {
+ ClassName aliasScopeName = ClassName.get(metadata.aliasElement());
+ metadata
+ .defineComponentScopeElements()
+ .forEach(
+ defineComponentScope -> {
+ ClassName defineComponentScopeName = ClassName.get(defineComponentScope);
+ ProcessorErrors.checkState(
+ defineComponentScopes.contains(defineComponentScopeName),
+ metadata.aliasElement(),
+ "The scope %s cannot be an alias for %s. You can only have aliases of a"
+ + " scope defined directly on a @DefineComponent type.",
+ aliasScopeName,
+ defineComponentScopeName);
+ builder.put(defineComponentScopeName, aliasScopeName);
+ });
+ });
return new AliasOfs(builder.build());
}
diff --git a/java/dagger/hilt/processor/internal/aliasof/BUILD b/java/dagger/hilt/processor/internal/aliasof/BUILD
index ffd0c9ae8..d589cb2c5 100644
--- a/java/dagger/hilt/processor/internal/aliasof/BUILD
+++ b/java/dagger/hilt/processor/internal/aliasof/BUILD
@@ -35,11 +35,11 @@ java_library(
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:service",
+ "//third_party/java/guava/collect",
+ "//third_party/java/incap",
+ "//third_party/java/javapoet",
],
)
@@ -52,12 +52,14 @@ java_library(
deps = [
"//java/dagger/hilt/processor/internal:aggregated_elements",
"//java/dagger/hilt/processor/internal:classnames",
+ "//java/dagger/hilt/processor/internal:component_descriptor",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
+ "//java/dagger/hilt/processor/internal/root/ir",
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
diff --git a/java/dagger/hilt/processor/internal/definecomponent/BUILD b/java/dagger/hilt/processor/internal/definecomponent/BUILD
index 43f4dfda0..9701a06dd 100644
--- a/java/dagger/hilt/processor/internal/definecomponent/BUILD
+++ b/java/dagger/hilt/processor/internal/definecomponent/BUILD
@@ -21,6 +21,9 @@ java_plugin(
name = "processor",
generates_api = 1,
processor_class = "dagger.hilt.processor.internal.definecomponent.DefineComponentProcessor",
+ visibility = [
+ "//java/dagger/hilt:__pkg__",
+ ],
deps = [":processor_lib"],
)
@@ -34,10 +37,10 @@ java_library(
"//java/dagger/hilt/processor/internal:base_processor",
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
+ "//third_party/java/auto:service",
+ "//third_party/java/guava/collect",
+ "//third_party/java/incap",
+ "//third_party/java/javapoet",
],
)
@@ -55,11 +58,12 @@ java_library(
"//java/dagger/hilt/processor/internal:component_descriptor",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
+ "//java/dagger/hilt/processor/internal/root/ir",
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
diff --git a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentClassesMetadata.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentClassesMetadata.java
index 36ac28fb3..a9da094d7 100644
--- a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentClassesMetadata.java
+++ b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentClassesMetadata.java
@@ -21,11 +21,13 @@ import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.AggregatedElements;
import dagger.hilt.processor.internal.AnnotationValues;
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.ProcessorErrors;
import dagger.hilt.processor.internal.Processors;
+import dagger.hilt.processor.internal.root.ir.DefineComponentClassesIr;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.TypeElement;
@@ -36,7 +38,10 @@ import javax.lang.model.util.Elements;
* dagger.hilt.internal.definecomponent.DefineComponentClasses} annotation.
*/
@AutoValue
-abstract class DefineComponentClassesMetadata {
+public abstract class DefineComponentClassesMetadata {
+
+ /** Returns the aggregating element */
+ public abstract TypeElement aggregatingElement();
/**
* Returns the element annotated with {@code dagger.hilt.internal.definecomponent.DefineComponent}
@@ -52,12 +57,20 @@ abstract class DefineComponentClassesMetadata {
return !isComponent();
}
- static ImmutableSet<DefineComponentClassesMetadata> from(Elements elements) {
- return AggregatedElements.from(
+ /** Returns metadata for all aggregated elements in the aggregating package. */
+ public static ImmutableSet<DefineComponentClassesMetadata> from(Elements elements) {
+ return from(
+ AggregatedElements.from(
ClassNames.DEFINE_COMPONENT_CLASSES_PACKAGE,
ClassNames.DEFINE_COMPONENT_CLASSES,
- elements)
- .stream()
+ elements),
+ elements);
+ }
+
+ /** Returns metadata for each aggregated element. */
+ public static ImmutableSet<DefineComponentClassesMetadata> from(
+ ImmutableSet<TypeElement> aggregatedElements, Elements elements) {
+ return aggregatedElements.stream()
.map(aggregatedElement -> create(aggregatedElement, elements))
.collect(toImmutableSet());
}
@@ -92,6 +105,13 @@ abstract class DefineComponentClassesMetadata {
ClassNames.DEFINE_COMPONENT_CLASSES.simpleName(),
isComponent ? "component" : "builder",
componentOrBuilderName);
- return new AutoValue_DefineComponentClassesMetadata(componentOrBuilderElement, isComponent);
+ return new AutoValue_DefineComponentClassesMetadata(
+ element, componentOrBuilderElement, isComponent);
+ }
+
+ public static DefineComponentClassesIr toIr(DefineComponentClassesMetadata metadata) {
+ return new DefineComponentClassesIr(
+ ClassName.get(metadata.aggregatingElement()),
+ ClassName.get(metadata.element()));
}
}
diff --git a/java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java
index efa501191..e9200d001 100644
--- a/java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java
+++ b/java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java
@@ -33,7 +33,6 @@ import java.util.LinkedHashMap;
import java.util.Map;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.Elements;
/**
* A utility class for getting {@link DefineComponentMetadata} and {@link
@@ -78,10 +77,8 @@ public final class DefineComponents {
}
/** Returns the set of aggregated {@link ComponentDescriptor}s. */
- public ImmutableSet<ComponentDescriptor> getComponentDescriptors(Elements elements) {
- ImmutableSet<DefineComponentClassesMetadata> aggregatedMetadatas =
- DefineComponentClassesMetadata.from(elements);
-
+ public ImmutableSet<ComponentDescriptor> getComponentDescriptors(
+ ImmutableSet<DefineComponentClassesMetadata> aggregatedMetadatas) {
ImmutableSet<DefineComponentMetadata> components =
aggregatedMetadatas.stream()
.filter(DefineComponentClassesMetadata::isComponent)
diff --git a/java/dagger/hilt/processor/internal/disableinstallincheck/BUILD b/java/dagger/hilt/processor/internal/disableinstallincheck/BUILD
index e3865a608..c06f9fee9 100644
--- a/java/dagger/hilt/processor/internal/disableinstallincheck/BUILD
+++ b/java/dagger/hilt/processor/internal/disableinstallincheck/BUILD
@@ -37,9 +37,9 @@ java_library(
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
+ "//third_party/java/auto:service",
+ "//third_party/java/guava/collect",
+ "//third_party/java/incap",
],
)
diff --git a/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointMetadata.java b/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointMetadata.java
index ed347bd17..1a93cf2d0 100644
--- a/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointMetadata.java
+++ b/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointMetadata.java
@@ -21,10 +21,12 @@ import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.AggregatedElements;
import dagger.hilt.processor.internal.AnnotationValues;
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.Processors;
+import dagger.hilt.processor.internal.root.ir.AggregatedEarlyEntryPointIr;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.TypeElement;
@@ -32,25 +34,41 @@ import javax.lang.model.util.Elements;
/**
* A class that represents the values stored in an {@link
- * dagger.hilt.android.internal.uninstallmodules.AggregatedUninstallModules} annotation.
+ * dagger.hilt.android.internal.earlyentrypoint.AggregatedEarlyEntryPoint} annotation.
*/
@AutoValue
public abstract class AggregatedEarlyEntryPointMetadata {
+ /** Returns the aggregating element */
+ public abstract TypeElement aggregatingElement();
+
/** Returns the element annotated with {@link dagger.hilt.android.EarlyEntryPoint}. */
public abstract TypeElement earlyEntryPoint();
- /** Returns all aggregated deps in the aggregating package. */
+ /** Returns metadata for all aggregated elements in the aggregating package. */
public static ImmutableSet<AggregatedEarlyEntryPointMetadata> from(Elements elements) {
- return AggregatedElements.from(
+ return from(
+ AggregatedElements.from(
ClassNames.AGGREGATED_EARLY_ENTRY_POINT_PACKAGE,
ClassNames.AGGREGATED_EARLY_ENTRY_POINT,
- elements)
- .stream()
+ elements),
+ elements);
+ }
+
+ /** Returns metadata for each aggregated element. */
+ public static ImmutableSet<AggregatedEarlyEntryPointMetadata> from(
+ ImmutableSet<TypeElement> aggregatedElements, Elements elements) {
+ return aggregatedElements.stream()
.map(aggregatedElement -> create(aggregatedElement, elements))
.collect(toImmutableSet());
}
+ public static AggregatedEarlyEntryPointIr toIr(AggregatedEarlyEntryPointMetadata metadata) {
+ return new AggregatedEarlyEntryPointIr(
+ ClassName.get(metadata.aggregatingElement()),
+ ClassName.get(metadata.earlyEntryPoint()));
+ }
+
private static AggregatedEarlyEntryPointMetadata create(TypeElement element, Elements elements) {
AnnotationMirror annotationMirror =
Processors.getAnnotationMirror(element, ClassNames.AGGREGATED_EARLY_ENTRY_POINT);
@@ -59,6 +77,7 @@ public abstract class AggregatedEarlyEntryPointMetadata {
Processors.getAnnotationValues(elements, annotationMirror);
return new AutoValue_AggregatedEarlyEntryPointMetadata(
+ element,
elements.getTypeElement(AnnotationValues.getString(values.get("earlyEntryPoint"))));
}
}
diff --git a/java/dagger/hilt/processor/internal/earlyentrypoint/BUILD b/java/dagger/hilt/processor/internal/earlyentrypoint/BUILD
index 3573e8603..7bbc90ca2 100644
--- a/java/dagger/hilt/processor/internal/earlyentrypoint/BUILD
+++ b/java/dagger/hilt/processor/internal/earlyentrypoint/BUILD
@@ -34,11 +34,11 @@ java_library(
"//java/dagger/hilt/processor/internal:base_processor",
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:service",
+ "//third_party/java/guava/collect",
+ "//third_party/java/incap",
+ "//third_party/java/javapoet",
],
)
@@ -51,9 +51,11 @@ java_library(
"//java/dagger/hilt/processor/internal:aggregated_elements",
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processors",
+ "//java/dagger/hilt/processor/internal/root/ir",
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
diff --git a/java/dagger/hilt/processor/internal/generatesrootinput/BUILD b/java/dagger/hilt/processor/internal/generatesrootinput/BUILD
index f24ffb716..2b56408e9 100644
--- a/java/dagger/hilt/processor/internal/generatesrootinput/BUILD
+++ b/java/dagger/hilt/processor/internal/generatesrootinput/BUILD
@@ -36,10 +36,10 @@ java_library(
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
+ "//third_party/java/auto:service",
+ "//third_party/java/guava/collect",
+ "//third_party/java/incap",
+ "//third_party/java/javapoet",
],
)
@@ -53,9 +53,9 @@ java_library(
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/javapoet",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
diff --git a/java/dagger/hilt/processor/internal/originatingelement/BUILD b/java/dagger/hilt/processor/internal/originatingelement/BUILD
index 50dbcf6b1..89425357e 100644
--- a/java/dagger/hilt/processor/internal/originatingelement/BUILD
+++ b/java/dagger/hilt/processor/internal/originatingelement/BUILD
@@ -34,10 +34,10 @@ java_library(
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:service",
+ "//third_party/java/guava/collect",
+ "//third_party/java/incap",
],
)
diff --git a/java/dagger/hilt/processor/internal/root/AggregatedRootGenerator.java b/java/dagger/hilt/processor/internal/root/AggregatedRootGenerator.java
index 722b99b72..d79c0a710 100644
--- a/java/dagger/hilt/processor/internal/root/AggregatedRootGenerator.java
+++ b/java/dagger/hilt/processor/internal/root/AggregatedRootGenerator.java
@@ -26,12 +26,17 @@ import javax.lang.model.element.TypeElement;
/** Generates an {@link dagger.hilt.internal.aggregatedroot.AggregatedRoot}. */
final class AggregatedRootGenerator {
private final TypeElement rootElement;
+ private final TypeElement originatingRootElement;
private final TypeElement rootAnnotation;
private final ProcessingEnvironment processingEnv;
AggregatedRootGenerator(
- TypeElement rootElement, TypeElement rootAnnotation, ProcessingEnvironment processingEnv) {
+ TypeElement rootElement,
+ TypeElement originatingRootElement,
+ TypeElement rootAnnotation,
+ ProcessingEnvironment processingEnv) {
this.rootElement = rootElement;
+ this.originatingRootElement = originatingRootElement;
this.rootAnnotation = rootAnnotation;
this.processingEnv = processingEnv;
}
@@ -41,6 +46,7 @@ final class AggregatedRootGenerator {
ClassNames.AGGREGATED_ROOT_PACKAGE,
AnnotationSpec.builder(ClassNames.AGGREGATED_ROOT)
.addMember("root", "$S", rootElement.getQualifiedName())
+ .addMember("originatingRoot", "$S", originatingRootElement.getQualifiedName())
.addMember("rootAnnotation", "$T.class", rootAnnotation)
.build(),
rootElement,
diff --git a/java/dagger/hilt/processor/internal/root/AggregatedRootMetadata.java b/java/dagger/hilt/processor/internal/root/AggregatedRootMetadata.java
index 961689b7c..70ee63f96 100644
--- a/java/dagger/hilt/processor/internal/root/AggregatedRootMetadata.java
+++ b/java/dagger/hilt/processor/internal/root/AggregatedRootMetadata.java
@@ -19,16 +19,19 @@ package dagger.hilt.processor.internal.root;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.AggregatedElements;
import dagger.hilt.processor.internal.AnnotationValues;
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.Processors;
+import dagger.hilt.processor.internal.root.ir.AggregatedRootIr;
+import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.Elements;
/**
* Represents the values stored in an {@link dagger.hilt.internal.aggregatedroot.AggregatedRoot}.
@@ -36,29 +39,69 @@ import javax.lang.model.util.Elements;
@AutoValue
abstract class AggregatedRootMetadata {
+ /** Returns the aggregating element */
+ public abstract TypeElement aggregatingElement();
+
/** Returns the element that was annotated with the root annotation. */
abstract TypeElement rootElement();
+ /**
+ * Returns the originating root element. In most cases this will be the same as
+ * {@link #rootElement()}.
+ */
+ abstract TypeElement originatingRootElement();
+
/** Returns the root annotation as an element. */
abstract TypeElement rootAnnotation();
- static ImmutableSet<AggregatedRootMetadata> from(Elements elements) {
- return AggregatedElements.from(
- ClassNames.AGGREGATED_ROOT_PACKAGE, ClassNames.AGGREGATED_ROOT, elements)
- .stream()
- .map(aggregatedElement -> create(aggregatedElement, elements))
+ /** Returns whether this root can use a shared component. */
+ abstract boolean allowsSharingComponent();
+
+ @Memoized
+ RootType rootType() {
+ return RootType.of(rootElement());
+ }
+
+ static ImmutableSet<AggregatedRootMetadata> from(ProcessingEnvironment env) {
+ return from(
+ AggregatedElements.from(
+ ClassNames.AGGREGATED_ROOT_PACKAGE, ClassNames.AGGREGATED_ROOT, env.getElementUtils()),
+ env);
+ }
+
+ /** Returns metadata for each aggregated element. */
+ public static ImmutableSet<AggregatedRootMetadata> from(
+ ImmutableSet<TypeElement> aggregatedElements, ProcessingEnvironment env) {
+ return aggregatedElements.stream()
+ .map(aggregatedElement -> create(aggregatedElement, env))
.collect(toImmutableSet());
}
- private static AggregatedRootMetadata create(TypeElement element, Elements elements) {
+ public static AggregatedRootIr toIr(AggregatedRootMetadata metadata) {
+ return new AggregatedRootIr(
+ ClassName.get(metadata.aggregatingElement()),
+ ClassName.get(metadata.rootElement()),
+ ClassName.get(metadata.originatingRootElement()),
+ ClassName.get(metadata.rootAnnotation()),
+ metadata.allowsSharingComponent());
+ }
+
+ private static AggregatedRootMetadata create(TypeElement element, ProcessingEnvironment env) {
AnnotationMirror annotationMirror =
Processors.getAnnotationMirror(element, ClassNames.AGGREGATED_ROOT);
ImmutableMap<String, AnnotationValue> values =
- Processors.getAnnotationValues(elements, annotationMirror);
+ Processors.getAnnotationValues(env.getElementUtils(), annotationMirror);
+ TypeElement rootElement =
+ env.getElementUtils().getTypeElement(AnnotationValues.getString(values.get("root")));
+ boolean allowSharingComponent = true;
return new AutoValue_AggregatedRootMetadata(
- elements.getTypeElement(AnnotationValues.getString(values.get("root"))),
- AnnotationValues.getTypeElement(values.get("rootAnnotation")));
+ element,
+ rootElement,
+ env.getElementUtils()
+ .getTypeElement(AnnotationValues.getString(values.get("originatingRoot"))),
+ AnnotationValues.getTypeElement(values.get("rootAnnotation")),
+ allowSharingComponent);
}
}
diff --git a/java/dagger/hilt/processor/internal/root/BUILD b/java/dagger/hilt/processor/internal/root/BUILD
index 5ce762fa6..126662c02 100644
--- a/java/dagger/hilt/processor/internal/root/BUILD
+++ b/java/dagger/hilt/processor/internal/root/BUILD
@@ -18,48 +18,95 @@
package(default_visibility = ["//:src"])
java_plugin(
- name = "plugin",
+ name = "component_tree_deps_plugin",
generates_api = 1,
- processor_class = "dagger.hilt.processor.internal.root.RootProcessor",
+ processor_class = "dagger.hilt.processor.internal.root.ComponentTreeDepsProcessor",
deps = [
- ":processor_lib",
+ ":component_tree_deps_processor_lib",
],
)
java_library(
- name = "processor_lib",
+ name = "component_tree_deps_processor_lib",
srcs = [
- "AggregatedRootGenerator.java",
"ComponentGenerator.java",
+ "ComponentTreeDepsProcessor.java",
"EarlySingletonComponentCreatorGenerator.java",
- "ProcessedRootSentinelGenerator.java",
"RootFileFormatter.java",
"RootGenerator.java",
- "RootProcessor.java",
"TestComponentDataGenerator.java",
+ ],
+ deps = [
+ ":root_metadata",
+ "//java/dagger/hilt/android/processor/internal/androidentrypoint:android_generators",
+ "//java/dagger/hilt/android/processor/internal/androidentrypoint:metadata",
+ "//java/dagger/hilt/processor/internal:base_processor",
+ "//java/dagger/hilt/processor/internal:classnames",
+ "//java/dagger/hilt/processor/internal:compiler_options",
+ "//java/dagger/hilt/processor/internal:component_descriptor",
+ "//java/dagger/hilt/processor/internal:component_names",
+ "//java/dagger/hilt/processor/internal:processor_errors",
+ "//java/dagger/hilt/processor/internal:processors",
+ "//java/dagger/hilt/processor/internal/aggregateddeps:component_dependencies",
+ "//java/dagger/hilt/processor/internal/aliasof:alias_ofs",
+ "//java/dagger/hilt/processor/internal/definecomponent:define_components",
+ "//java/dagger/hilt/processor/internal/earlyentrypoint:aggregated_early_entry_point_metadata",
+ "//java/dagger/hilt/processor/internal/uninstallmodules:aggregated_uninstall_modules_metadata",
+ "//java/dagger/internal/codegen/extension",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:service",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/graph",
+ "//third_party/java/incap",
+ "//third_party/java/javapoet",
+ ],
+)
+
+java_plugin(
+ name = "root_plugin",
+ generates_api = 1,
+ processor_class = "dagger.hilt.processor.internal.root.RootProcessor",
+ deps = [
+ ":root_processor_lib",
+ ],
+)
+
+java_library(
+ name = "root_processor_lib",
+ srcs = [
+ "AggregatedRootGenerator.java",
+ "ComponentTreeDepsGenerator.java",
+ "ProcessedRootSentinelGenerator.java",
+ "RootProcessor.java",
"TestInjectorGenerator.java",
],
deps = [
":root_metadata",
":root_type",
+ "//java/dagger/hilt/android/processor/internal/androidentrypoint:android_generators",
+ "//java/dagger/hilt/android/processor/internal/androidentrypoint:metadata",
+ "//java/dagger/hilt/processor/internal:aggregated_elements",
"//java/dagger/hilt/processor/internal:base_processor",
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:compiler_options",
- "//java/dagger/hilt/processor/internal:component_descriptor",
"//java/dagger/hilt/processor/internal:component_names",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/hilt/processor/internal/aggregateddeps:component_dependencies",
+ "//java/dagger/hilt/processor/internal/aliasof:alias_ofs",
"//java/dagger/hilt/processor/internal/definecomponent:define_components",
+ "//java/dagger/hilt/processor/internal/earlyentrypoint:aggregated_early_entry_point_metadata",
"//java/dagger/hilt/processor/internal/generatesrootinput:generates_root_inputs",
+ "//java/dagger/hilt/processor/internal/root/ir",
+ "//java/dagger/hilt/processor/internal/uninstallmodules:aggregated_uninstall_modules_metadata",
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:graph",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:service",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/incap",
+ "//third_party/java/javapoet",
],
)
@@ -68,6 +115,7 @@ java_library(
srcs = [
"AggregatedRootMetadata.java",
"ComponentTree.java",
+ "ComponentTreeDepsMetadata.java",
"ProcessedRootSentinelMetadata.java",
"Root.java",
"RootMetadata.java",
@@ -77,21 +125,21 @@ java_library(
":root_type",
"//java/dagger/hilt/processor/internal:aggregated_elements",
"//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:compiler_options",
"//java/dagger/hilt/processor/internal:component_descriptor",
"//java/dagger/hilt/processor/internal:kotlin",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/hilt/processor/internal/aggregateddeps:component_dependencies",
"//java/dagger/hilt/processor/internal/aliasof:alias_ofs",
+ "//java/dagger/hilt/processor/internal/root/ir",
"//java/dagger/internal/codegen/extension",
"//java/dagger/internal/codegen/kotlin",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:graph",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/graph",
+ "//third_party/java/javapoet",
],
)
@@ -101,7 +149,7 @@ java_library(
deps = [
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processors",
- "@google_bazel_common//third_party/java/javapoet",
+ "//third_party/java/javapoet",
],
)
diff --git a/java/dagger/hilt/processor/internal/root/ComponentTreeDepsGenerator.java b/java/dagger/hilt/processor/internal/root/ComponentTreeDepsGenerator.java
new file mode 100644
index 000000000..34c586aba
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/root/ComponentTreeDepsGenerator.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal.root;
+
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.AnnotationSpec;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.TypeSpec;
+import dagger.hilt.processor.internal.AggregatedElements;
+import dagger.hilt.processor.internal.ClassNames;
+import dagger.hilt.processor.internal.Processors;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.TypeElement;
+
+/** Generates an {@link dagger.hilt.internal.componenttreedeps.ComponentTreeDeps}. */
+final class ComponentTreeDepsGenerator {
+ // Keeps track of already generated proxies. For correctness, this same instance of
+ // ComponentTreeDepsGenerator must be used for a given round.
+ private final Set<ClassName> generatedProxies = new HashSet<>();
+ private final ProcessingEnvironment env;
+
+ ComponentTreeDepsGenerator(ProcessingEnvironment env) {
+ this.env = env;
+ }
+
+ void generate(ComponentTreeDepsMetadata metadata) throws IOException {
+ ClassName name = metadata.name();
+ TypeSpec.Builder builder =
+ TypeSpec.classBuilder(name)
+ // No originating element since this is generated by the aggregating processor.
+ .addAnnotation(componentTreeDepsAnnotation(metadata));
+
+ Processors.addGeneratedAnnotation(builder, env, ClassNames.ROOT_PROCESSOR.toString());
+
+ JavaFile.builder(name.packageName(), builder.build()).build().writeTo(env.getFiler());
+ }
+
+ AnnotationSpec componentTreeDepsAnnotation(ComponentTreeDepsMetadata metadata)
+ throws IOException {
+ AnnotationSpec.Builder builder = AnnotationSpec.builder(ClassNames.COMPONENT_TREE_DEPS);
+ addDeps(builder, metadata.aggregatedRootDeps(), "rootDeps");
+ addDeps(builder, metadata.defineComponentDeps(), "defineComponentDeps");
+ addDeps(builder, metadata.aliasOfDeps(), "aliasOfDeps");
+ addDeps(builder, metadata.aggregatedDeps(), "aggregatedDeps");
+ addDeps(builder, metadata.aggregatedUninstallModulesDeps(), "uninstallModulesDeps");
+ addDeps(builder, metadata.aggregatedEarlyEntryPointDeps(), "earlyEntryPointDeps");
+ return builder.build();
+ }
+
+ private void addDeps(AnnotationSpec.Builder builder, ImmutableSet<TypeElement> deps, String name)
+ throws IOException {
+ for (TypeElement dep : deps) {
+ builder.addMember(name, "$T.class", maybeWrapInPublicProxy(dep));
+ }
+ }
+
+ /**
+ * This method will return the public proxy for {@code dep} if it is not public, otherwise it will
+ * return {@code dep} itself. It will also generate the proxy if it doesn't already exist.
+ *
+ * <p>Note: These proxies are only used for serialization. The proxy will be unwrapped when
+ * converting to {@link ComponentTreeDepsMetadata}.
+ *
+ * <p>Note: The public proxy is needed because Hilt versions < 2.35 generated package-private
+ * aggregating elements, which can't be referenced directly in the {@code @ComponentTreeDeps}.
+ */
+ private ClassName maybeWrapInPublicProxy(TypeElement dep) throws IOException {
+ Optional<ClassName> proxyName = AggregatedElements.aggregatedElementProxyName(dep);
+ if (proxyName.isPresent()) {
+ // Check the set of already generated proxies to ensure we don't regenerate the proxy in
+ // this round. Also check that the element doesn't already exist to ensure we don't regenerate
+ // a proxy generated in a previous round.
+ if (generatedProxies.add(proxyName.get())
+ && env.getElementUtils().getTypeElement(proxyName.get().canonicalName()) == null) {
+ generateProxy(dep, proxyName.get());
+ }
+ return proxyName.get();
+ }
+ return ClassName.get(dep);
+ }
+
+ private void generateProxy(TypeElement dep, ClassName proxyName) throws IOException {
+ TypeSpec.Builder builder =
+ TypeSpec.classBuilder(proxyName)
+ .addModifiers(PUBLIC)
+ // No originating element since this is generated by the aggregating processor.
+ .addAnnotation(
+ AnnotationSpec.builder(ClassNames.AGGREGATED_ELEMENT_PROXY)
+ .addMember("value", "$T.class", dep)
+ .build());
+
+ Processors.addGeneratedAnnotation(builder, env, ClassNames.ROOT_PROCESSOR.toString());
+
+ JavaFile.builder(proxyName.packageName(), builder.build()).build().writeTo(env.getFiler());
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/root/ComponentTreeDepsMetadata.java b/java/dagger/hilt/processor/internal/root/ComponentTreeDepsMetadata.java
new file mode 100644
index 000000000..7d1f3670d
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/root/ComponentTreeDepsMetadata.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal.root;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.hilt.processor.internal.AggregatedElements.unwrapProxies;
+import static dagger.hilt.processor.internal.AnnotationValues.getTypeElements;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import dagger.hilt.processor.internal.ClassNames;
+import dagger.hilt.processor.internal.Processors;
+import dagger.hilt.processor.internal.root.ir.ComponentTreeDepsIr;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+
+/**
+ * Represents the values stored in an {@link
+ * dagger.hilt.internal.componenttreedeps.ComponentTreeDeps}.
+ *
+ * <p>This class is used in both writing ({@link ComponentTreeDepsGenerator}) and reading ({@link
+ * ComponentTreeDepsProcessor}) of the {@code @ComponentTreeDeps} annotation.
+ */
+@AutoValue
+abstract class ComponentTreeDepsMetadata {
+ /**
+ * Returns the name of the element annotated with {@link
+ * dagger.hilt.internal.componenttreedeps.ComponentTreeDeps}.
+ */
+ abstract ClassName name();
+
+ /** Returns the {@link dagger.hilt.internal.aggregatedroot.AggregatedRoot} deps. */
+ abstract ImmutableSet<TypeElement> aggregatedRootDeps();
+
+ /** Returns the {@link dagger.hilt.internal.definecomponent.DefineComponentClasses} deps. */
+ abstract ImmutableSet<TypeElement> defineComponentDeps();
+
+ /** Returns the {@link dagger.hilt.internal.aliasof.AliasOfPropagatedData} deps. */
+ abstract ImmutableSet<TypeElement> aliasOfDeps();
+
+ /** Returns the {@link dagger.hilt.internal.aggregateddeps.AggregatedDeps} deps. */
+ abstract ImmutableSet<TypeElement> aggregatedDeps();
+
+ /** Returns the {@link dagger.hilt.android.uninstallmodules.AggregatedUninstallModules} deps. */
+ abstract ImmutableSet<TypeElement> aggregatedUninstallModulesDeps();
+
+ /** Returns the {@link dagger.hilt.android.earlyentrypoint.AggregatedEarlyEntryPoint} deps. */
+ abstract ImmutableSet<TypeElement> aggregatedEarlyEntryPointDeps();
+
+ static ComponentTreeDepsMetadata from(TypeElement element, Elements elements) {
+ checkArgument(Processors.hasAnnotation(element, ClassNames.COMPONENT_TREE_DEPS));
+ AnnotationMirror annotationMirror =
+ Processors.getAnnotationMirror(element, ClassNames.COMPONENT_TREE_DEPS);
+
+ ImmutableMap<String, AnnotationValue> values =
+ Processors.getAnnotationValues(elements, annotationMirror);
+
+ return create(
+ ClassName.get(element),
+ unwrapProxies(getTypeElements(values.get("rootDeps")), elements),
+ unwrapProxies(getTypeElements(values.get("defineComponentDeps")), elements),
+ unwrapProxies(getTypeElements(values.get("aliasOfDeps")), elements),
+ unwrapProxies(getTypeElements(values.get("aggregatedDeps")), elements),
+ unwrapProxies(getTypeElements(values.get("uninstallModulesDeps")), elements),
+ unwrapProxies(getTypeElements(values.get("earlyEntryPointDeps")), elements));
+ }
+
+ static ComponentTreeDepsMetadata from(ComponentTreeDepsIr ir, Elements elements) {
+ return create(
+ ir.getName(),
+ ir.getRootDeps().stream()
+ .map(it -> elements.getTypeElement(it.canonicalName()))
+ .collect(toImmutableSet()),
+ ir.getDefineComponentDeps().stream()
+ .map(it -> elements.getTypeElement(it.canonicalName()))
+ .collect(toImmutableSet()),
+ ir.getAliasOfDeps().stream()
+ .map(it -> elements.getTypeElement(it.canonicalName()))
+ .collect(toImmutableSet()),
+ ir.getAggregatedDeps().stream()
+ .map(it -> elements.getTypeElement(it.canonicalName()))
+ .collect(toImmutableSet()),
+ ir.getUninstallModulesDeps().stream()
+ .map(it -> elements.getTypeElement(it.canonicalName()))
+ .collect(toImmutableSet()),
+ ir.getEarlyEntryPointDeps().stream()
+ .map(it -> elements.getTypeElement(it.canonicalName()))
+ .collect(toImmutableSet()));
+ }
+
+ static ComponentTreeDepsMetadata create(
+ ClassName name,
+ ImmutableSet<TypeElement> aggregatedRootDeps,
+ ImmutableSet<TypeElement> defineComponentDeps,
+ ImmutableSet<TypeElement> aliasOfDeps,
+ ImmutableSet<TypeElement> aggregatedDeps,
+ ImmutableSet<TypeElement> aggregatedUninstallModulesDeps,
+ ImmutableSet<TypeElement> aggregatedEarlyEntryPointDeps) {
+ return new AutoValue_ComponentTreeDepsMetadata(
+ name,
+ aggregatedRootDeps,
+ defineComponentDeps,
+ aliasOfDeps,
+ aggregatedDeps,
+ aggregatedUninstallModulesDeps,
+ aggregatedEarlyEntryPointDeps);
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/root/ComponentTreeDepsProcessor.java b/java/dagger/hilt/processor/internal/root/ComponentTreeDepsProcessor.java
new file mode 100644
index 000000000..85eb59a47
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/root/ComponentTreeDepsProcessor.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal.root;
+
+import static com.google.auto.common.MoreElements.asType;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.hilt.processor.internal.HiltCompilerOptions.useAggregatingRootProcessor;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING;
+
+import com.google.auto.service.AutoService;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import dagger.hilt.android.processor.internal.androidentrypoint.AndroidEntryPointMetadata;
+import dagger.hilt.android.processor.internal.androidentrypoint.ApplicationGenerator;
+import dagger.hilt.processor.internal.BaseProcessor;
+import dagger.hilt.processor.internal.ClassNames;
+import dagger.hilt.processor.internal.ComponentDescriptor;
+import dagger.hilt.processor.internal.ComponentNames;
+import dagger.hilt.processor.internal.ProcessorErrors;
+import dagger.hilt.processor.internal.Processors;
+import dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsMetadata;
+import dagger.hilt.processor.internal.aggregateddeps.ComponentDependencies;
+import dagger.hilt.processor.internal.aliasof.AliasOfPropagatedDataMetadata;
+import dagger.hilt.processor.internal.aliasof.AliasOfs;
+import dagger.hilt.processor.internal.definecomponent.DefineComponentClassesMetadata;
+import dagger.hilt.processor.internal.definecomponent.DefineComponents;
+import dagger.hilt.processor.internal.earlyentrypoint.AggregatedEarlyEntryPointMetadata;
+import dagger.hilt.processor.internal.uninstallmodules.AggregatedUninstallModulesMetadata;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
+
+/** Processor that outputs dagger components based on transitive build deps. */
+@IncrementalAnnotationProcessor(ISOLATING)
+@AutoService(Processor.class)
+public final class ComponentTreeDepsProcessor extends BaseProcessor {
+ private final Set<ClassName> componentTreeDepNames = new HashSet<>();
+ private final Set<ClassName> processed = new HashSet<>();
+ private final DefineComponents defineComponents = DefineComponents.create();
+
+ @Override
+ public ImmutableSet<String> getSupportedAnnotationTypes() {
+ return ImmutableSet.of(ClassNames.COMPONENT_TREE_DEPS.toString());
+ }
+
+ @Override
+ public void processEach(TypeElement annotation, Element element) {
+ componentTreeDepNames.add(ClassName.get(asType(element)));
+ }
+
+ @Override
+ public void postRoundProcess(RoundEnvironment roundEnv) throws Exception {
+ ImmutableSet<ComponentTreeDepsMetadata> componentTreeDepsToProcess =
+ componentTreeDepNames.stream()
+ .filter(className -> !processed.contains(className))
+ .map(className -> getElementUtils().getTypeElement(className.canonicalName()))
+ .map(element -> ComponentTreeDepsMetadata.from(element, getElementUtils()))
+ .collect(toImmutableSet());
+
+ for (ComponentTreeDepsMetadata metadata : componentTreeDepsToProcess) {
+ processComponentTreeDeps(metadata);
+ }
+ }
+
+ private void processComponentTreeDeps(ComponentTreeDepsMetadata metadata) throws IOException {
+ TypeElement metadataElement = getElementUtils().getTypeElement(metadata.name().canonicalName());
+ try {
+ // We choose a name for the generated components/wrapper based off of the originating element
+ // annotated with @ComponentTreeDeps. This is close to but isn't necessarily a "real" name of
+ // a root, since with shared test components, even for single roots, the component tree deps
+ // will be moved to a shared package with a deduped name.
+ ClassName renamedRoot = Processors.removeNameSuffix(metadataElement, "_ComponentTreeDeps");
+ ComponentNames componentNames = ComponentNames.withRenaming(rootName -> renamedRoot);
+
+ boolean isDefaultRoot = ClassNames.DEFAULT_ROOT.equals(renamedRoot);
+ ImmutableSet<Root> roots =
+ AggregatedRootMetadata.from(metadata.aggregatedRootDeps(), processingEnv).stream()
+ .map(AggregatedRootMetadata::rootElement)
+ .map(rootElement -> Root.create(rootElement, getProcessingEnv()))
+ .collect(toImmutableSet());
+
+ // TODO(bcorso): For legacy reasons, a lot of the generating code requires a "root" as input
+ // since we used to assume 1 root per component tree. Now that each ComponentTreeDeps may
+ // represent multiple roots, we should refactor this logic.
+ Root root =
+ isDefaultRoot
+ ? Root.createDefaultRoot(getProcessingEnv())
+ // Non-default roots should only ever be associated with one root element
+ : getOnlyElement(roots);
+
+ ImmutableSet<ComponentDescriptor> componentDescriptors =
+ defineComponents.getComponentDescriptors(
+ DefineComponentClassesMetadata.from(
+ metadata.defineComponentDeps(), getElementUtils()));
+ ComponentTree tree = ComponentTree.from(componentDescriptors);
+ ComponentDependencies deps =
+ ComponentDependencies.from(
+ componentDescriptors,
+ AggregatedDepsMetadata.from(metadata.aggregatedDeps(), getElementUtils()),
+ AggregatedUninstallModulesMetadata.from(
+ metadata.aggregatedUninstallModulesDeps(), getElementUtils()),
+ AggregatedEarlyEntryPointMetadata.from(
+ metadata.aggregatedEarlyEntryPointDeps(), getElementUtils()),
+ getElementUtils());
+ AliasOfs aliasOfs =
+ AliasOfs.create(
+ AliasOfPropagatedDataMetadata.from(metadata.aliasOfDeps(), getElementUtils()),
+ componentDescriptors);
+ RootMetadata rootMetadata =
+ RootMetadata.create(root, tree, deps, aliasOfs, getProcessingEnv());
+
+ generateComponents(metadata, rootMetadata, componentNames);
+
+ // Generate a creator for the early entry point if there is a default component available
+ // and there are early entry points.
+ if (isDefaultRoot && !metadata.aggregatedEarlyEntryPointDeps().isEmpty()) {
+ EarlySingletonComponentCreatorGenerator.generate(getProcessingEnv());
+ }
+
+ if (root.isTestRoot()) {
+ // Generate test related classes for each test root that uses this component.
+ ImmutableList<RootMetadata> rootMetadatas =
+ roots.stream()
+ .map(test -> RootMetadata.create(test, tree, deps, aliasOfs, getProcessingEnv()))
+ .collect(toImmutableList());
+ generateTestComponentData(metadataElement, rootMetadatas, componentNames);
+ } else {
+ generateApplication(root.element());
+ }
+
+ setProcessingState(metadata, root);
+ } catch (Exception e) {
+ processed.add(metadata.name());
+ throw e;
+ }
+ }
+
+ private void setProcessingState(ComponentTreeDepsMetadata metadata, Root root) {
+ processed.add(metadata.name());
+ }
+
+ private void generateComponents(
+ ComponentTreeDepsMetadata metadata, RootMetadata rootMetadata, ComponentNames componentNames)
+ throws IOException {
+ RootGenerator.generate(metadata, rootMetadata, componentNames, getProcessingEnv());
+ }
+
+ private void generateTestComponentData(
+ TypeElement metadataElement,
+ ImmutableList<RootMetadata> rootMetadatas,
+ ComponentNames componentNames)
+ throws IOException {
+ for (RootMetadata rootMetadata : rootMetadatas) {
+ // TODO(bcorso): Consider moving this check earlier into processEach.
+ TypeElement testElement = rootMetadata.testRootMetadata().testElement();
+ ProcessorErrors.checkState(
+ testElement.getModifiers().contains(PUBLIC),
+ testElement,
+ "Hilt tests must be public, but found: %s",
+ testElement);
+ new TestComponentDataGenerator(
+ getProcessingEnv(), metadataElement, rootMetadata, componentNames)
+ .generate();
+ }
+ }
+
+ private void generateApplication(TypeElement rootElement) throws IOException {
+ // The generated application references the generated component so they must be generated
+ // in the same build unit. Thus, we only generate the application here if we're using the
+ // Hilt Gradle plugin's aggregating task. If we're using the aggregating processor, we need
+ // to generate the application within AndroidEntryPointProcessor instead.
+ if (!useAggregatingRootProcessor(getProcessingEnv())) {
+ AndroidEntryPointMetadata metadata =
+ AndroidEntryPointMetadata.of(getProcessingEnv(), rootElement);
+ new ApplicationGenerator(
+ getProcessingEnv(),
+ metadata)
+ .generate();
+ }
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/root/EarlySingletonComponentCreatorGenerator.java b/java/dagger/hilt/processor/internal/root/EarlySingletonComponentCreatorGenerator.java
index 1dbda3982..81a904a24 100644
--- a/java/dagger/hilt/processor/internal/root/EarlySingletonComponentCreatorGenerator.java
+++ b/java/dagger/hilt/processor/internal/root/EarlySingletonComponentCreatorGenerator.java
@@ -45,10 +45,12 @@ final class EarlySingletonComponentCreatorGenerator {
.returns(ClassName.OBJECT)
.addStatement(
"return $T.builder()\n"
- + ".applicationContextModule(new $T($T.getApplicationContext()))\n"
+ + ".applicationContextModule(\n"
+ + " new $T($T.getApplication($T.getApplicationContext())))\n"
+ ".build()",
DEFAULT_COMPONENT_IMPL,
ClassNames.APPLICATION_CONTEXT_MODULE,
+ ClassNames.CONTEXTS,
ClassNames.APPLICATION_PROVIDER)
.build());
diff --git a/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelMetadata.java b/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelMetadata.java
index d60015495..a7070b848 100644
--- a/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelMetadata.java
+++ b/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelMetadata.java
@@ -21,10 +21,13 @@ import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.AggregatedElements;
import dagger.hilt.processor.internal.AnnotationValues;
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.Processors;
+import dagger.hilt.processor.internal.root.ir.ProcessedRootSentinelIr;
+import java.util.stream.Collectors;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.TypeElement;
@@ -37,6 +40,9 @@ import javax.lang.model.util.Elements;
@AutoValue
abstract class ProcessedRootSentinelMetadata {
+ /** Returns the aggregating element */
+ public abstract TypeElement aggregatingElement();
+
/** Returns the processed root elements. */
abstract ImmutableSet<TypeElement> rootElements();
@@ -50,6 +56,13 @@ abstract class ProcessedRootSentinelMetadata {
.collect(toImmutableSet());
}
+ static ProcessedRootSentinelIr toIr(ProcessedRootSentinelMetadata metadata) {
+ return new ProcessedRootSentinelIr(
+ ClassName.get(metadata.aggregatingElement()),
+ metadata.rootElements().stream().map(ClassName::get).collect(Collectors.toList())
+ );
+ }
+
private static ProcessedRootSentinelMetadata create(TypeElement element, Elements elements) {
AnnotationMirror annotationMirror =
Processors.getAnnotationMirror(element, ClassNames.PROCESSED_ROOT_SENTINEL);
@@ -58,6 +71,7 @@ abstract class ProcessedRootSentinelMetadata {
Processors.getAnnotationValues(elements, annotationMirror);
return new AutoValue_ProcessedRootSentinelMetadata(
+ element,
AnnotationValues.getStrings(values.get("roots")).stream()
.map(elements::getTypeElement)
.collect(toImmutableSet()));
diff --git a/java/dagger/hilt/processor/internal/root/Root.java b/java/dagger/hilt/processor/internal/root/Root.java
index 24440b0c9..00e17ca4f 100644
--- a/java/dagger/hilt/processor/internal/root/Root.java
+++ b/java/dagger/hilt/processor/internal/root/Root.java
@@ -43,18 +43,27 @@ abstract class Root {
static Root createDefaultRoot(ProcessingEnvironment env) {
TypeElement rootElement =
env.getElementUtils().getTypeElement(ClassNames.DEFAULT_ROOT.canonicalName());
- return new AutoValue_Root(rootElement, /*isTestRoot=*/ true);
+ return new AutoValue_Root(rootElement, rootElement, /*isTestRoot=*/ true);
}
/** Creates a {@plainlink Root root} for the given {@plainlink Element element}. */
static Root create(Element element, ProcessingEnvironment env) {
TypeElement rootElement = MoreElements.asType(element);
- return new AutoValue_Root(rootElement, RootType.of(rootElement).isTestRoot());
+ if (ClassNames.DEFAULT_ROOT.equals(ClassName.get(rootElement))) {
+ return createDefaultRoot(env);
+ }
+ return new AutoValue_Root(rootElement, rootElement, RootType.of(rootElement).isTestRoot());
}
/** Returns the root element that should be used with processing. */
abstract TypeElement element();
+ /**
+ * Returns the originating root element. In most cases this will be the same as {@link
+ * #element()}.
+ */
+ abstract TypeElement originatingRootElement();
+
/** Returns {@code true} if this is a test root. */
abstract boolean isTestRoot();
@@ -63,9 +72,14 @@ abstract class Root {
return ClassName.get(element());
}
+ /** Returns the class name of the originating root element. */
+ ClassName originatingRootClassname() {
+ return ClassName.get(originatingRootElement());
+ }
+
@Override
public final String toString() {
- return element().toString();
+ return originatingRootElement().toString();
}
/** Returns {@code true} if this uses the default root. */
diff --git a/java/dagger/hilt/processor/internal/root/RootGenerator.java b/java/dagger/hilt/processor/internal/root/RootGenerator.java
index f87fbd90b..732c6ea5f 100644
--- a/java/dagger/hilt/processor/internal/root/RootGenerator.java
+++ b/java/dagger/hilt/processor/internal/root/RootGenerator.java
@@ -16,6 +16,7 @@
package dagger.hilt.processor.internal.root;
+import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static dagger.hilt.processor.internal.Processors.toClassNames;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
@@ -44,20 +45,26 @@ import java.util.Map;
import java.util.Optional;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
/** Generates components and any other classes needed for a root. */
final class RootGenerator {
static void generate(
- RootMetadata metadata, ComponentNames componentNames, ProcessingEnvironment env)
+ ComponentTreeDepsMetadata componentTreeDepsMetadata,
+ RootMetadata metadata,
+ ComponentNames componentNames,
+ ProcessingEnvironment env)
throws IOException {
new RootGenerator(
+ componentTreeDepsMetadata,
RootMetadata.copyWithNewTree(metadata, filterDescriptors(metadata.componentTree())),
componentNames,
env)
.generateComponents();
}
+ private final TypeElement originatingElement;
private final RootMetadata metadata;
private final ProcessingEnvironment env;
private final Root root;
@@ -66,7 +73,13 @@ final class RootGenerator {
private final ComponentNames componentNames;
private RootGenerator(
- RootMetadata metadata, ComponentNames componentNames, ProcessingEnvironment env) {
+ ComponentTreeDepsMetadata componentTreeDepsMetadata,
+ RootMetadata metadata,
+ ComponentNames componentNames,
+ ProcessingEnvironment env) {
+ this.originatingElement =
+ checkNotNull(
+ env.getElementUtils().getTypeElement(componentTreeDepsMetadata.name().toString()));
this.metadata = metadata;
this.componentNames = componentNames;
this.env = env;
@@ -165,7 +178,7 @@ final class RootGenerator {
ClassName componentName, ClassName builderName, ClassName moduleName) {
TypeSpec.Builder subcomponentBuilderModule =
TypeSpec.interfaceBuilder(moduleName)
- .addOriginatingElement(root.element())
+ .addOriginatingElement(originatingElement)
.addModifiers(ABSTRACT)
.addAnnotation(
AnnotationSpec.builder(ClassNames.MODULE)
@@ -192,7 +205,7 @@ final class RootGenerator {
.map(
creator ->
TypeSpec.interfaceBuilder("Builder")
- .addOriginatingElement(root.element())
+ .addOriginatingElement(originatingElement)
.addModifiers(STATIC, ABSTRACT)
.addSuperinterface(creator)
.addAnnotation(componentBuilderAnnotation(descriptor))
@@ -221,7 +234,7 @@ final class RootGenerator {
}
private ClassName getComponentsWrapperClassName() {
- return componentNames.generatedComponentsWrapper(root.classname());
+ return componentNames.generatedComponentsWrapper(root.originatingRootClassname());
}
private ClassName getComponentClassName(ComponentDescriptor componentDescriptor) {
@@ -240,7 +253,8 @@ final class RootGenerator {
componentDescriptor.component());
ClassName generatedComponent =
- componentNames.generatedComponent(root.classname(), componentDescriptor.component());
+ componentNames.generatedComponent(
+ root.originatingRootClassname(), componentDescriptor.component());
Integer suffix = simpleComponentNamesToDedupeSuffix.get(generatedComponent.simpleName());
if (suffix != null) {
diff --git a/java/dagger/hilt/processor/internal/root/RootMetadata.java b/java/dagger/hilt/processor/internal/root/RootMetadata.java
index b39b590ef..5b390031a 100644
--- a/java/dagger/hilt/processor/internal/root/RootMetadata.java
+++ b/java/dagger/hilt/processor/internal/root/RootMetadata.java
@@ -18,14 +18,12 @@ package dagger.hilt.processor.internal.root;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Suppliers.memoize;
-import static dagger.hilt.processor.internal.HiltCompilerOptions.isSharedTestComponentsEnabled;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static javax.lang.model.element.Modifier.ABSTRACT;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.STATIC;
import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.squareup.javapoet.ClassName;
@@ -54,33 +52,22 @@ public final class RootMetadata {
Root root,
ComponentTree componentTree,
ComponentDependencies deps,
+ AliasOfs aliasOfs,
ProcessingEnvironment env) {
- return createInternal(root, ImmutableList.of(), componentTree, deps, env);
- }
-
- static RootMetadata createForDefaultRoot(
- Root root,
- ImmutableList<RootMetadata> rootsUsingDefaultComponents,
- ComponentTree componentTree,
- ComponentDependencies deps,
- ProcessingEnvironment env) {
- checkState(root.isDefaultRoot());
- return createInternal(root, rootsUsingDefaultComponents, componentTree, deps, env);
+ return createInternal(root, componentTree, deps, aliasOfs, env);
}
static RootMetadata copyWithNewTree(RootMetadata other, ComponentTree componentTree) {
- return createInternal(
- other.root, other.rootsUsingDefaultComponents, componentTree, other.deps, other.env);
+ return createInternal(other.root, componentTree, other.deps, other.aliasOfs, other.env);
}
private static RootMetadata createInternal(
Root root,
- ImmutableList<RootMetadata> rootsUsingDefaultComponents,
ComponentTree componentTree,
ComponentDependencies deps,
+ AliasOfs aliasOfs,
ProcessingEnvironment env) {
- RootMetadata metadata =
- new RootMetadata(root, componentTree, deps, rootsUsingDefaultComponents, env);
+ RootMetadata metadata = new RootMetadata(root, componentTree, deps, aliasOfs, env);
metadata.validate();
return metadata;
}
@@ -90,7 +77,7 @@ public final class RootMetadata {
private final Elements elements;
private final ComponentTree componentTree;
private final ComponentDependencies deps;
- private final ImmutableList<RootMetadata> rootsUsingDefaultComponents;
+ private final AliasOfs aliasOfs;
private final Supplier<ImmutableSetMultimap<ClassName, ClassName>> scopesByComponent =
memoize(this::getScopesByComponentUncached);
private final Supplier<TestRootMetadata> testRootMetadata =
@@ -100,14 +87,14 @@ public final class RootMetadata {
Root root,
ComponentTree componentTree,
ComponentDependencies deps,
- ImmutableList<RootMetadata> rootsUsingDefaultComponents,
+ AliasOfs aliasOfs,
ProcessingEnvironment env) {
this.root = root;
this.env = env;
this.elements = env.getElementUtils();
this.componentTree = componentTree;
this.deps = deps;
- this.rootsUsingDefaultComponents = rootsUsingDefaultComponents;
+ this.aliasOfs = aliasOfs;
}
public Root root() {
@@ -123,24 +110,15 @@ public final class RootMetadata {
}
public ImmutableSet<TypeElement> modules(ClassName componentName) {
- return deps.modules().get(componentName, root.classname(), root.isTestRoot());
- }
-
- /**
- * Returns {@code true} if this is a test root that provides no test-specific dependencies or sets
- * other options that would prevent it from sharing components with other test roots.
- */
- // TODO(groakley): Allow more tests to share modules, e.g. tests that uninstall the same module.
- // In that case, this might instead return which shared dep grouping should be used.
- public boolean canShareTestComponents() {
- return isSharedTestComponentsEnabled(env)
- && root.isTestRoot()
- && !deps.includesTestDeps(root.classname());
+ return deps.modules().get(componentName);
}
public ImmutableSet<TypeName> entryPoints(ClassName componentName) {
return ImmutableSet.<TypeName>builder()
- .addAll(getUserDefinedEntryPoints(componentName))
+ .addAll(
+ deps.entryPoints().get(componentName).stream()
+ .map(ClassName::get)
+ .collect(toImmutableSet()))
.add(
root.isTestRoot() && componentName.equals(ClassNames.SINGLETON_COMPONENT)
? ClassNames.TEST_SINGLETON_COMPONENT
@@ -197,7 +175,7 @@ public final class RootMetadata {
"[Hilt] All test modules (unless installed in ApplicationComponent) must use "
+ "static provision methods or have a visible, no-arg constructor. Found: "
+ extraModule.getQualifiedName(),
- root.element());
+ root.originatingRootElement());
} else if (!root.isTestRoot()) {
env.getMessager()
.printMessage(
@@ -205,41 +183,14 @@ public final class RootMetadata {
"[Hilt] All modules must be static and use static provision methods or have a "
+ "visible, no-arg constructor. Found: "
+ extraModule.getQualifiedName(),
- root.element());
+ root.originatingRootElement());
}
}
}
}
- private ImmutableSet<TypeName> getUserDefinedEntryPoints(ClassName componentName) {
- ImmutableSet.Builder<TypeName> entryPointSet = ImmutableSet.builder();
- if (root.isDefaultRoot() && !rootsUsingDefaultComponents.isEmpty()) {
- // Add entry points for shared component
- rootsUsingDefaultComponents.stream()
- .flatMap(metadata -> metadata.entryPoints(componentName).stream())
- .forEach(entryPointSet::add);
- } else if (root.isDefaultRoot() && componentName.equals(ClassNames.SINGLETON_COMPONENT)) {
- // We only do this for SingletonComponent because EarlyEntryPoints can only be installed
- // in the SingletonComponent.
- deps.earlyEntryPoints().forEach(entryPointSet::add);
- } else {
- deps.entryPoints().get(componentName, root.classname(), root.isTestRoot()).stream()
- .map(ClassName::get)
- .forEach(entryPointSet::add);
- }
- return entryPointSet.build();
- }
-
private ImmutableSetMultimap<ClassName, ClassName> getScopesByComponentUncached() {
ImmutableSetMultimap.Builder<ClassName, ClassName> builder = ImmutableSetMultimap.builder();
-
- ImmutableSet<ClassName> defineComponentScopes =
- componentTree.getComponentDescriptors().stream()
- .flatMap(descriptor -> descriptor.scopes().stream())
- .collect(toImmutableSet());
-
- AliasOfs aliasOfs = AliasOfs.create(env.getElementUtils(), defineComponentScopes);
-
for (ComponentDescriptor componentDescriptor : componentTree.getComponentDescriptors()) {
for (ClassName scope : componentDescriptor.scopes()) {
builder.put(componentDescriptor.component(), scope);
diff --git a/java/dagger/hilt/processor/internal/root/RootProcessor.java b/java/dagger/hilt/processor/internal/root/RootProcessor.java
index 1ee4446d4..3dd35f581 100644
--- a/java/dagger/hilt/processor/internal/root/RootProcessor.java
+++ b/java/dagger/hilt/processor/internal/root/RootProcessor.java
@@ -19,29 +19,35 @@ package dagger.hilt.processor.internal.root;
import static com.google.common.base.Preconditions.checkState;
import static dagger.hilt.processor.internal.HiltCompilerOptions.isCrossCompilationRootValidationDisabled;
import static dagger.hilt.processor.internal.HiltCompilerOptions.isSharedTestComponentsEnabled;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.hilt.processor.internal.HiltCompilerOptions.useAggregatingRootProcessor;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static java.util.Comparator.comparing;
-import static javax.lang.model.element.Modifier.PUBLIC;
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.AGGREGATING;
+import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.DYNAMIC;
+import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING;
import com.google.auto.common.MoreElements;
import com.google.auto.service.AutoService;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.ClassName;
+import dagger.hilt.processor.internal.BadInputException;
import dagger.hilt.processor.internal.BaseProcessor;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.ComponentDescriptor;
-import dagger.hilt.processor.internal.ComponentNames;
-import dagger.hilt.processor.internal.ProcessorErrors;
-import dagger.hilt.processor.internal.aggregateddeps.ComponentDependencies;
-import dagger.hilt.processor.internal.definecomponent.DefineComponents;
+import dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsMetadata;
+import dagger.hilt.processor.internal.aliasof.AliasOfPropagatedDataMetadata;
+import dagger.hilt.processor.internal.definecomponent.DefineComponentClassesMetadata;
+import dagger.hilt.processor.internal.earlyentrypoint.AggregatedEarlyEntryPointMetadata;
import dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputs;
-import java.io.IOException;
+import dagger.hilt.processor.internal.root.ir.AggregatedDepsIr;
+import dagger.hilt.processor.internal.root.ir.AggregatedEarlyEntryPointIr;
+import dagger.hilt.processor.internal.root.ir.AggregatedRootIr;
+import dagger.hilt.processor.internal.root.ir.AggregatedRootIrValidator;
+import dagger.hilt.processor.internal.root.ir.AggregatedUninstallModulesIr;
+import dagger.hilt.processor.internal.root.ir.AliasOfPropagatedDataIr;
+import dagger.hilt.processor.internal.root.ir.ComponentTreeDepsIr;
+import dagger.hilt.processor.internal.root.ir.ComponentTreeDepsIrCreator;
+import dagger.hilt.processor.internal.root.ir.DefineComponentClassesIr;
+import dagger.hilt.processor.internal.root.ir.InvalidRootsException;
+import dagger.hilt.processor.internal.root.ir.ProcessedRootSentinelIr;
+import dagger.hilt.processor.internal.uninstallmodules.AggregatedUninstallModulesMetadata;
import java.util.Arrays;
-import java.util.Comparator;
-import java.util.HashSet;
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
@@ -51,15 +57,11 @@ import javax.lang.model.element.TypeElement;
import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
/** Processor that outputs dagger components based on transitive build deps. */
-@IncrementalAnnotationProcessor(AGGREGATING)
+@IncrementalAnnotationProcessor(DYNAMIC)
@AutoService(Processor.class)
public final class RootProcessor extends BaseProcessor {
- private static final Comparator<TypeElement> QUALIFIED_NAME_COMPARATOR =
- comparing(TypeElement::getQualifiedName, (n1, n2) -> n1.toString().compareTo(n2.toString()));
- private final Set<ClassName> processed = new HashSet<>();
- // TODO(bcorso): Consider using a Dagger component to create/scope these objects
- private final DefineComponents defineComponents = DefineComponents.create();
+ private boolean processed;
private GeneratesRootInputs generatesRootInputs;
@Override
@@ -69,6 +71,13 @@ public final class RootProcessor extends BaseProcessor {
}
@Override
+ public ImmutableSet<String> additionalProcessingOptions() {
+ return useAggregatingRootProcessor(getProcessingEnv())
+ ? ImmutableSet.of(AGGREGATING.getProcessorOption())
+ : ImmutableSet.of(ISOLATING.getProcessorOption());
+ }
+
+ @Override
public ImmutableSet<String> getSupportedAnnotationTypes() {
return ImmutableSet.<String>builder()
.addAll(
@@ -81,224 +90,118 @@ public final class RootProcessor extends BaseProcessor {
@Override
public void processEach(TypeElement annotation, Element element) throws Exception {
TypeElement rootElement = MoreElements.asType(element);
+ // TODO(bcorso): Move this logic into a separate isolating processor to avoid regenerating it
+ // for unrelated changes in Gradle.
RootType rootType = RootType.of(rootElement);
if (rootType.isTestRoot()) {
new TestInjectorGenerator(
getProcessingEnv(), TestRootMetadata.of(getProcessingEnv(), rootElement))
.generate();
}
- new AggregatedRootGenerator(rootElement, annotation, getProcessingEnv()).generate();
+ TypeElement originatingRootElement =
+ Root.create(rootElement, getProcessingEnv()).originatingRootElement();
+ new AggregatedRootGenerator(rootElement, originatingRootElement, annotation, getProcessingEnv())
+ .generate();
}
@Override
public void postRoundProcess(RoundEnvironment roundEnv) throws Exception {
+ if (!useAggregatingRootProcessor(getProcessingEnv())) {
+ return;
+ }
Set<Element> newElements = generatesRootInputs.getElementsToWaitFor(roundEnv);
- if (!processed.isEmpty() ) {
+ if (processed) {
checkState(
newElements.isEmpty(),
"Found extra modules after compilation: %s\n"
+ "(If you are adding an annotation processor that generates root input for hilt, "
+ "the annotation must be annotated with @dagger.hilt.GeneratesRootInput.\n)",
newElements);
- }
+ } else if (newElements.isEmpty()) {
+ processed = true;
- if (!newElements.isEmpty()) {
- // Skip further processing since there's new elements that generate root inputs in this round.
- return;
- }
-
- ImmutableSet<Root> allRoots =
- AggregatedRootMetadata.from(getElementUtils()).stream()
- .map(metadata -> Root.create(metadata.rootElement(), getProcessingEnv()))
- .collect(toImmutableSet());
-
- ImmutableSet<Root> processedRoots =
- ProcessedRootSentinelMetadata.from(getElementUtils()).stream()
- .flatMap(metadata -> metadata.rootElements().stream())
- .map(rootElement -> Root.create(rootElement, getProcessingEnv()))
- .collect(toImmutableSet());
-
- ImmutableSet<Root> rootsToProcess =
- allRoots.stream()
- .filter(root -> !processedRoots.contains(root))
- .filter(root -> !processed.contains(rootName(root)))
- .collect(toImmutableSet());
-
- if (rootsToProcess.isEmpty()) {
- // Skip further processing since there's no roots that need processing.
- return;
- }
-
- // TODO(bcorso): Currently, if there's an exception in any of the roots we stop processing
- // all roots. We should consider if it's worth trying to continue processing for other
- // roots. At the moment, I think it's rare that if one root failed the others would not.
- try {
- validateRoots(allRoots, rootsToProcess);
-
- boolean isTestEnv = rootsToProcess.stream().anyMatch(Root::isTestRoot);
- ComponentNames componentNames =
- isTestEnv && isSharedTestComponentsEnabled(getProcessingEnv())
- ? ComponentNames.withRenamingIntoPackage(
- ClassNames.DEFAULT_ROOT.packageName(),
- rootsToProcess.stream().map(Root::element).collect(toImmutableList()))
- : ComponentNames.withoutRenaming();
-
- ImmutableSet<ComponentDescriptor> componentDescriptors =
- defineComponents.getComponentDescriptors(getElementUtils());
- ComponentTree tree = ComponentTree.from(componentDescriptors);
- ComponentDependencies deps =
- ComponentDependencies.from(componentDescriptors, getElementUtils());
- ImmutableList<RootMetadata> rootMetadatas =
- rootsToProcess.stream()
- .map(root -> RootMetadata.create(root, tree, deps, getProcessingEnv()))
- .collect(toImmutableList());
-
- for (RootMetadata rootMetadata : rootMetadatas) {
- if (!rootMetadata.canShareTestComponents()) {
- generateComponents(rootMetadata, componentNames);
- }
+ ImmutableSet<AggregatedRootIr> rootsToProcess = rootsToProcess();
+ if (rootsToProcess.isEmpty()) {
+ return;
}
- if (isTestEnv) {
- ImmutableList<RootMetadata> rootsThatCanShareComponents =
- rootMetadatas.stream()
- .filter(RootMetadata::canShareTestComponents)
- .collect(toImmutableList());
- generateTestComponentData(rootMetadatas, componentNames);
- if (deps.hasEarlyEntryPoints() || !rootsThatCanShareComponents.isEmpty()) {
- Root defaultRoot = Root.createDefaultRoot(getProcessingEnv());
- generateComponents(
- RootMetadata.createForDefaultRoot(
- defaultRoot, rootsThatCanShareComponents, tree, deps, getProcessingEnv()),
- componentNames);
- EarlySingletonComponentCreatorGenerator.generate(getProcessingEnv());
- }
- }
- } catch (Exception e) {
- for (Root root : rootsToProcess) {
- processed.add(rootName(root));
+ // Generate an @ComponentTreeDeps for each unique component tree.
+ ComponentTreeDepsGenerator componentTreeDepsGenerator =
+ new ComponentTreeDepsGenerator(getProcessingEnv());
+ for (ComponentTreeDepsMetadata metadata : componentTreeDepsMetadatas(rootsToProcess)) {
+ componentTreeDepsGenerator.generate(metadata);
}
- throw e;
- } finally {
- rootsToProcess.forEach(this::setProcessingState);
- // Calculate the roots processed in this round. We do this in the finally-block rather than in
- // the try-block because the catch-block can change the processing state.
- ImmutableSet<Root> rootsProcessedInRound =
- rootsToProcess.stream()
- // Only add a sentinel for processed roots. Skip preprocessed roots since those will
- // will be processed in the next round.
- .filter(root -> processed.contains(rootName(root)))
- .collect(toImmutableSet());
- for (Root root : rootsProcessedInRound) {
- new ProcessedRootSentinelGenerator(rootElement(root), getProcessingEnv()).generate();
+
+ // Generate a sentinel for all processed roots.
+ for (AggregatedRootIr ir : rootsToProcess) {
+ TypeElement rootElement = getElementUtils().getTypeElement(ir.getRoot().canonicalName());
+ new ProcessedRootSentinelGenerator(rootElement, getProcessingEnv()).generate();
}
}
}
- private void validateRoots(ImmutableSet<Root> allRoots, ImmutableSet<Root> rootsToProcess) {
-
- ImmutableSet<TypeElement> rootElementsToProcess =
- rootsToProcess.stream()
- .map(Root::element)
- .sorted(QUALIFIED_NAME_COMPARATOR)
+ private ImmutableSet<AggregatedRootIr> rootsToProcess() {
+ ImmutableSet<ProcessedRootSentinelIr> processedRoots =
+ ProcessedRootSentinelMetadata.from(getElementUtils()).stream()
+ .map(ProcessedRootSentinelMetadata::toIr)
.collect(toImmutableSet());
-
- ImmutableSet<TypeElement> appRootElementsToProcess =
- rootsToProcess.stream()
- .filter(root -> !root.isTestRoot())
- .map(Root::element)
- .sorted(QUALIFIED_NAME_COMPARATOR)
+ ImmutableSet<AggregatedRootIr> aggregatedRoots =
+ AggregatedRootMetadata.from(processingEnv).stream()
+ .map(AggregatedRootMetadata::toIr)
.collect(toImmutableSet());
- // Perform validation between roots in this compilation unit.
- if (!appRootElementsToProcess.isEmpty()) {
- ImmutableSet<TypeElement> testRootElementsToProcess =
- rootsToProcess.stream()
- .filter(Root::isTestRoot)
- .map(Root::element)
- .sorted(QUALIFIED_NAME_COMPARATOR)
- .collect(toImmutableSet());
-
- ProcessorErrors.checkState(
- testRootElementsToProcess.isEmpty(),
- "Cannot process test roots and app roots in the same compilation unit:"
- + "\n\tApp root in this compilation unit: %s"
- + "\n\tTest roots in this compilation unit: %s",
- appRootElementsToProcess,
- testRootElementsToProcess);
-
- ProcessorErrors.checkState(
- appRootElementsToProcess.size() == 1,
- "Cannot process multiple app roots in the same compilation unit: %s",
- appRootElementsToProcess);
- }
-
- // Perform validation across roots previous compilation units.
- if (!isCrossCompilationRootValidationDisabled(rootElementsToProcess, getProcessingEnv())) {
- ImmutableSet<TypeElement> processedTestRootElements =
- allRoots.stream()
- .filter(Root::isTestRoot)
- .filter(root -> !rootsToProcess.contains(root))
- .map(Root::element)
- .sorted(QUALIFIED_NAME_COMPARATOR)
- .collect(toImmutableSet());
-
- // TODO(b/185742783): Add an explanation or link to docs to explain why we're forbidding this.
- ProcessorErrors.checkState(
- processedTestRootElements.isEmpty(),
- "Cannot process new roots when there are test roots from a previous compilation unit:"
- + "\n\tTest roots from previous compilation unit: %s"
- + "\n\tAll roots from this compilation unit: %s",
- processedTestRootElements,
- rootElementsToProcess);
-
- ImmutableSet<TypeElement> processedAppRootElements =
- allRoots.stream()
- .filter(root -> !root.isTestRoot())
- .filter(root -> !rootsToProcess.contains(root))
- .map(Root::element)
- .sorted(QUALIFIED_NAME_COMPARATOR)
- .collect(toImmutableSet());
-
- ProcessorErrors.checkState(
- processedAppRootElements.isEmpty() || appRootElementsToProcess.isEmpty(),
- "Cannot process app roots in this compilation unit since there are app roots in a "
- + "previous compilation unit:"
- + "\n\tApp roots in previous compilation unit: %s"
- + "\n\tApp roots in this compilation unit: %s",
- processedAppRootElements,
- appRootElementsToProcess);
+ boolean isCrossCompilationRootValidationDisabled =
+ isCrossCompilationRootValidationDisabled(
+ aggregatedRoots.stream()
+ .map(ir -> getElementUtils().getTypeElement(ir.getRoot().canonicalName()))
+ .collect(toImmutableSet()),
+ processingEnv);
+ try {
+ return ImmutableSet.copyOf(
+ AggregatedRootIrValidator.rootsToProcess(
+ isCrossCompilationRootValidationDisabled, processedRoots, aggregatedRoots));
+ } catch (InvalidRootsException ex) {
+ throw new BadInputException(ex.getMessage());
}
}
- private void setProcessingState(Root root) {
- processed.add(rootName(root));
- }
-
- private ClassName rootName(Root root) {
- return ClassName.get(rootElement(root));
- }
-
- private TypeElement rootElement(Root root) {
- return root.element();
- }
-
- private void generateComponents(RootMetadata rootMetadata, ComponentNames componentNames)
- throws IOException {
- RootGenerator.generate(rootMetadata, componentNames, getProcessingEnv());
- }
+ private ImmutableSet<ComponentTreeDepsMetadata> componentTreeDepsMetadatas(
+ ImmutableSet<AggregatedRootIr> aggregatedRoots) {
+ ImmutableSet<DefineComponentClassesIr> defineComponentDeps =
+ DefineComponentClassesMetadata.from(getElementUtils()).stream()
+ .map(DefineComponentClassesMetadata::toIr)
+ .collect(toImmutableSet());
+ ImmutableSet<AliasOfPropagatedDataIr> aliasOfDeps =
+ AliasOfPropagatedDataMetadata.from(getElementUtils()).stream()
+ .map(AliasOfPropagatedDataMetadata::toIr)
+ .collect(toImmutableSet());
+ ImmutableSet<AggregatedDepsIr> aggregatedDeps =
+ AggregatedDepsMetadata.from(getElementUtils()).stream()
+ .map(AggregatedDepsMetadata::toIr)
+ .collect(toImmutableSet());
+ ImmutableSet<AggregatedUninstallModulesIr> aggregatedUninstallModulesDeps =
+ AggregatedUninstallModulesMetadata.from(getElementUtils()).stream()
+ .map(AggregatedUninstallModulesMetadata::toIr)
+ .collect(toImmutableSet());
+ ImmutableSet<AggregatedEarlyEntryPointIr> aggregatedEarlyEntryPointDeps =
+ AggregatedEarlyEntryPointMetadata.from(getElementUtils()).stream()
+ .map(AggregatedEarlyEntryPointMetadata::toIr)
+ .collect(toImmutableSet());
- private void generateTestComponentData(
- ImmutableList<RootMetadata> rootMetadatas, ComponentNames componentNames) throws IOException {
- for (RootMetadata rootMetadata : rootMetadatas) {
- // TODO(bcorso): Consider moving this check earlier into processEach.
- TypeElement testElement = rootMetadata.testRootMetadata().testElement();
- ProcessorErrors.checkState(
- testElement.getModifiers().contains(PUBLIC),
- testElement,
- "Hilt tests must be public, but found: %s",
- testElement);
- new TestComponentDataGenerator(getProcessingEnv(), rootMetadata, componentNames).generate();
- }
+ // We should be guaranteed that there are no mixed roots, so check if this is prod or test.
+ boolean isTest = aggregatedRoots.stream().anyMatch(AggregatedRootIr::isTestRoot);
+ Set<ComponentTreeDepsIr> componentTreeDeps =
+ ComponentTreeDepsIrCreator.components(
+ isTest,
+ isSharedTestComponentsEnabled(processingEnv),
+ aggregatedRoots,
+ defineComponentDeps,
+ aliasOfDeps,
+ aggregatedDeps,
+ aggregatedUninstallModulesDeps,
+ aggregatedEarlyEntryPointDeps);
+ return componentTreeDeps.stream()
+ .map(it -> ComponentTreeDepsMetadata.from(it, getElementUtils()))
+ .collect(toImmutableSet());
}
}
diff --git a/java/dagger/hilt/processor/internal/root/RootType.java b/java/dagger/hilt/processor/internal/root/RootType.java
index 807f71d73..a6efc84fd 100644
--- a/java/dagger/hilt/processor/internal/root/RootType.java
+++ b/java/dagger/hilt/processor/internal/root/RootType.java
@@ -23,13 +23,13 @@ import javax.lang.model.element.TypeElement;
/** The valid root types for Hilt applications. */
// TODO(erichang): Fix this class so we don't have to have placeholders
- enum RootType {
- ROOT(ClassNames.HILT_ANDROID_APP),
+enum RootType {
+ ROOT(ClassNames.HILT_ANDROID_APP),
- // Placeholder to make sure @HiltAndroidTest usages get processed
- HILT_ANDROID_TEST_ROOT(ClassNames.HILT_ANDROID_TEST),
+ // Placeholder to make sure @HiltAndroidTest usages get processed
+ HILT_ANDROID_TEST_ROOT(ClassNames.HILT_ANDROID_TEST),
- TEST_ROOT(ClassNames.INTERNAL_TEST_ROOT);
+ TEST_ROOT(ClassNames.INTERNAL_TEST_ROOT);
@SuppressWarnings("ImmutableEnumChecker")
private final ClassName annotation;
diff --git a/java/dagger/hilt/processor/internal/root/TestComponentDataGenerator.java b/java/dagger/hilt/processor/internal/root/TestComponentDataGenerator.java
index 101c124d9..19145f45d 100644
--- a/java/dagger/hilt/processor/internal/root/TestComponentDataGenerator.java
+++ b/java/dagger/hilt/processor/internal/root/TestComponentDataGenerator.java
@@ -44,15 +44,18 @@ import javax.lang.model.element.TypeElement;
/** Generates an implementation of {@link dagger.hilt.android.internal.TestComponentData}. */
public final class TestComponentDataGenerator {
private final ProcessingEnvironment processingEnv;
+ private final TypeElement originatingElement;
private final RootMetadata rootMetadata;
private final ClassName name;
private final ComponentNames componentNames;
public TestComponentDataGenerator(
ProcessingEnvironment processingEnv,
+ TypeElement originatingElement,
RootMetadata rootMetadata,
ComponentNames componentNames) {
this.processingEnv = processingEnv;
+ this.originatingElement = originatingElement;
this.rootMetadata = rootMetadata;
this.componentNames = componentNames;
this.name =
@@ -75,7 +78,8 @@ public final class TestComponentDataGenerator {
* modules ->
* DaggerFooTest_ApplicationComponent.builder()
* .applicationContextModule(
- * new ApplicationContextModule(ApplicationProvider.getApplicationContext()))
+ * new ApplicationContextModule(
+ * Contexts.getApplication(ApplicationProvider.getApplicationContext())))
* .testModule((FooTest.TestModule) modules.get(FooTest.TestModule.class))
* .testModule(modules.containsKey(FooTest.TestModule.class)
* ? (FooTest.TestModule) modules.get(FooTest.TestModule.class)
@@ -88,6 +92,7 @@ public final class TestComponentDataGenerator {
public void generate() throws IOException {
TypeSpec.Builder generator =
TypeSpec.classBuilder(name)
+ .addOriginatingElement(originatingElement)
.superclass(ClassNames.TEST_COMPONENT_DATA_SUPPLIER)
.addModifiers(PUBLIC, FINAL)
.addMethod(getMethod())
@@ -105,10 +110,7 @@ public final class TestComponentDataGenerator {
TypeElement testElement = rootMetadata.testRootMetadata().testElement();
ClassName component =
componentNames.generatedComponent(
- rootMetadata.canShareTestComponents()
- ? ClassNames.DEFAULT_ROOT
- : ClassName.get(testElement),
- ClassNames.SINGLETON_COMPONENT);
+ ClassName.get(testElement), ClassNames.SINGLETON_COMPONENT);
ImmutableSet<TypeElement> daggerRequiredModules =
rootMetadata.modulesThatDaggerCannotConstruct(ClassNames.SINGLETON_COMPONENT);
ImmutableSet<TypeElement> hiltRequiredModules =
@@ -128,11 +130,13 @@ public final class TestComponentDataGenerator {
getElementsListed(hiltRequiredModules),
CodeBlock.of(
"(modules, testInstance, autoAddModuleEnabled) -> $T.builder()\n"
- + ".applicationContextModule(new $T($T.getApplicationContext()))\n"
+ + ".applicationContextModule(\n"
+ + " new $T($T.getApplication($T.getApplicationContext())))\n"
+ "$L"
+ ".build()",
Processors.prepend(Processors.getEnclosedClassName(component), "Dagger"),
ClassNames.APPLICATION_CONTEXT_MODULE,
+ ClassNames.CONTEXTS,
ClassNames.APPLICATION_PROVIDER,
daggerRequiredModules.stream()
.map(module -> getAddModuleStatement(module, testElement))
@@ -216,9 +220,10 @@ public final class TestComponentDataGenerator {
private CodeBlock callInjectTest(TypeElement testElement) {
return CodeBlock.of(
- "(($T) (($T) $T.getApplicationContext()).generatedComponent()).injectTest(testInstance)",
+ "(($T) (($T) $T.getApplication($T.getApplicationContext())).generatedComponent()).injectTest(testInstance)",
rootMetadata.testRootMetadata().testInjectorName(),
ClassNames.GENERATED_COMPONENT_MANAGER,
+ ClassNames.CONTEXTS,
ClassNames.APPLICATION_PROVIDER);
}
}
diff --git a/java/dagger/hilt/processor/internal/root/ir/AggregatedRootIrValidator.kt b/java/dagger/hilt/processor/internal/root/ir/AggregatedRootIrValidator.kt
new file mode 100644
index 000000000..b24cb14ee
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/root/ir/AggregatedRootIrValidator.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal.root.ir
+
+import kotlin.jvm.Throws
+
+// Validates roots being processed.
+object AggregatedRootIrValidator {
+ @JvmStatic
+ @Throws(InvalidRootsException::class)
+ fun rootsToProcess(
+ isCrossCompilationRootValidationDisabled: Boolean,
+ processedRoots: Set<ProcessedRootSentinelIr>,
+ aggregatedRoots: Set<AggregatedRootIr>
+ ): Set<AggregatedRootIr> {
+ val processedRootNames = processedRoots.flatMap { it.roots }.toSet()
+ val rootsToProcess = aggregatedRoots
+ .filterNot { processedRootNames.contains(it.root) }
+ .sortedBy { it.root.toString() }
+ val testRootsToProcess = rootsToProcess.filter { it.isTestRoot }
+ val appRootsToProcess = rootsToProcess - testRootsToProcess
+ fun Collection<AggregatedRootIr>.rootsToString() = map { it.root }.joinToString()
+ if (appRootsToProcess.size > 1) {
+ throw InvalidRootsException(
+ "Cannot process multiple app roots in the same compilation unit: " +
+ appRootsToProcess.rootsToString()
+ )
+ }
+ if (testRootsToProcess.isNotEmpty() && appRootsToProcess.isNotEmpty()) {
+ throw InvalidRootsException("""
+ Cannot process test roots and app roots in the same compilation unit:
+ App root in this compilation unit: ${appRootsToProcess.rootsToString()}
+ Test roots in this compilation unit: ${testRootsToProcess.rootsToString()}
+ """.trimIndent()
+ )
+ }
+ // Perform validation across roots previous compilation units.
+ if (!isCrossCompilationRootValidationDisabled) {
+ val alreadyProcessedTestRoots = aggregatedRoots.filter {
+ it.isTestRoot && processedRootNames.contains(it.root)
+ }
+ // TODO(b/185742783): Add an explanation or link to docs to explain why we're forbidding this.
+ if (alreadyProcessedTestRoots.isNotEmpty() && rootsToProcess.isNotEmpty()) {
+ throw InvalidRootsException("""
+ Cannot process new roots when there are test roots from a previous compilation unit:
+ Test roots from previous compilation unit: ${alreadyProcessedTestRoots.rootsToString()}
+ All roots from this compilation unit: ${rootsToProcess.rootsToString()}
+ """.trimIndent()
+ )
+ }
+ val alreadyProcessedAppRoots = aggregatedRoots.filter {
+ !it.isTestRoot && processedRootNames.contains(it.root)
+ }
+ if (alreadyProcessedAppRoots.isNotEmpty() && appRootsToProcess.isNotEmpty()) {
+ throw InvalidRootsException("""
+ Cannot process new app roots when there are app roots from a previous compilation unit:
+ App roots in previous compilation unit: ${alreadyProcessedAppRoots.rootsToString()}
+ App roots in this compilation unit: ${appRootsToProcess.rootsToString()}
+ """.trimIndent()
+ )
+ }
+ }
+ return rootsToProcess.toSet()
+ }
+}
+
+// An exception thrown when root validation fails.
+class InvalidRootsException(msg: String) : Exception(msg)
diff --git a/java/dagger/hilt/processor/internal/root/ir/BUILD b/java/dagger/hilt/processor/internal/root/ir/BUILD
new file mode 100644
index 000000000..4bc1a29a2
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/root/ir/BUILD
@@ -0,0 +1,52 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Description:
+# A library containing intermediate representations of the various Hilt
+# aggregating annotations along with logic to process them.
+
+load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
+
+package(default_visibility = ["//:src"])
+
+kt_jvm_library(
+ name = "ir",
+ srcs = glob(["*.kt"]),
+ # Dependencies here should be kept to a minimum since this library is
+ # shadowed into the Hilt Gradle Plugin artifact.
+ deps = [
+ "//third_party/java/javapoet",
+ ],
+)
+
+# Current `kt_jvm_library` does not output source jars and gen_maven_artifact expects one.
+# See: https://github.com/bazelbuild/rules_kotlin/issues/324
+genrule(
+ name = "ir-sources",
+ srcs = glob(["*.kt"]),
+ outs = ["libir-src.jar"],
+ cmd = """
+ TEMP="$$(mktemp -d)"
+ for file in $(SRCS); do
+ filename="$$TEMP/$${file#java/}"
+ mkdir -p `dirname $$filename` && cp $$file $$filename
+ done
+ jar cf $@ -C $$TEMP .
+ """,
+)
+
+filegroup(
+ name = "srcs_filegroup",
+ srcs = glob(["*"]),
+)
diff --git a/java/dagger/hilt/processor/internal/root/ir/ComponentTreeDepsIrCreator.kt b/java/dagger/hilt/processor/internal/root/ir/ComponentTreeDepsIrCreator.kt
new file mode 100644
index 000000000..4c7b94df2
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/root/ir/ComponentTreeDepsIrCreator.kt
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal.root.ir
+
+import com.squareup.javapoet.ClassName
+
+// Produces ComponentTreeDepsIr for a set of aggregated deps and roots to process.
+class ComponentTreeDepsIrCreator private constructor(
+ private val isSharedTestComponentsEnabled: Boolean,
+ private val aggregatedRoots: Set<AggregatedRootIr>,
+ private val defineComponentDeps: Set<DefineComponentClassesIr>,
+ private val aliasOfDeps: Set<AliasOfPropagatedDataIr>,
+ private val aggregatedDeps: Set<AggregatedDepsIr>,
+ private val aggregatedUninstallModulesDeps: Set<AggregatedUninstallModulesIr>,
+ private val aggregatedEarlyEntryPointDeps: Set<AggregatedEarlyEntryPointIr>,
+) {
+ private fun prodComponents(): Set<ComponentTreeDepsIr> {
+ // There should only be one prod root in a given build.
+ val aggregatedRoot = aggregatedRoots.single()
+ return setOf(
+ ComponentTreeDepsIr(
+ name = ComponentTreeDepsNameGenerator().generate(aggregatedRoot.root),
+ rootDeps = setOf(aggregatedRoot.fqName),
+ defineComponentDeps = defineComponentDeps.map { it.fqName }.toSet(),
+ aliasOfDeps = aliasOfDeps.map { it.fqName }.toSet(),
+ aggregatedDeps =
+ // @AggregatedDeps with non-empty replaces are from @TestInstallIn and should not be
+ // installed in production components
+ aggregatedDeps.filter { it.replaces.isEmpty() }.map { it.fqName }.toSet(),
+ uninstallModulesDeps = emptySet(),
+ earlyEntryPointDeps = emptySet(),
+ )
+ )
+ }
+
+ private fun testComponents(): Set<ComponentTreeDepsIr> {
+ val rootsUsingSharedComponent = rootsUsingSharedComponent(aggregatedRoots)
+ val aggregatedRootsByRoot = aggregatedRoots.associateBy { it.root }
+ val aggregatedDepsByRoot = aggregatedDepsByRoot(
+ aggregatedRoots = aggregatedRoots,
+ rootsUsingSharedComponent = rootsUsingSharedComponent,
+ hasEarlyEntryPoints = aggregatedEarlyEntryPointDeps.isNotEmpty()
+ )
+ val uninstallModuleDepsByRoot =
+ aggregatedUninstallModulesDeps.associate { it.test to it.fqName }
+ return mutableSetOf<ComponentTreeDepsIr>().apply {
+ aggregatedDepsByRoot.keys.forEach { root ->
+ val isDefaultRoot = root == DEFAULT_ROOT_CLASS_NAME
+ val isEarlyEntryPointRoot = isDefaultRoot && aggregatedEarlyEntryPointDeps.isNotEmpty()
+ // We want to base the generated name on the user written root rather than a generated root.
+ val rootName = if (isDefaultRoot) {
+ DEFAULT_ROOT_CLASS_NAME
+ } else {
+ aggregatedRootsByRoot.getValue(root).originatingRoot
+ }
+ val componentNameGenerator =
+ if (isSharedTestComponentsEnabled) {
+ ComponentTreeDepsNameGenerator(
+ destinationPackage = "dagger.hilt.android.internal.testing.root",
+ otherRootNames = aggregatedDepsByRoot.keys
+ )
+ } else {
+ ComponentTreeDepsNameGenerator()
+ }
+ add(
+ ComponentTreeDepsIr(
+ name = componentNameGenerator.generate(rootName),
+ rootDeps =
+ // Non-default component: the root
+ // Shared component: all roots sharing the component
+ // EarlyEntryPoint component: empty
+ if (isDefaultRoot) {
+ rootsUsingSharedComponent.map { aggregatedRootsByRoot.getValue(it).fqName }.toSet()
+ } else {
+ setOf(aggregatedRootsByRoot.getValue(root).fqName)
+ },
+ defineComponentDeps = defineComponentDeps.map { it.fqName }.toSet(),
+ aliasOfDeps = aliasOfDeps.map { it.fqName }.toSet(),
+ aggregatedDeps = aggregatedDepsByRoot.getOrElse(root) { emptySet() },
+ uninstallModulesDeps = uninstallModuleDepsByRoot[root]?.let { setOf(it) } ?: emptySet(),
+ earlyEntryPointDeps =
+ if (isEarlyEntryPointRoot) {
+ aggregatedEarlyEntryPointDeps.map { it.fqName }.toSet()
+ } else {
+ emptySet()
+ }
+ )
+ )
+ }
+ }
+ }
+
+ private fun rootsUsingSharedComponent(roots: Set<AggregatedRootIr>): Set<ClassName> {
+ if (!isSharedTestComponentsEnabled) {
+ return emptySet()
+ }
+ val hasLocalModuleDependencies: Set<ClassName> = mutableSetOf<ClassName>().apply {
+ addAll(aggregatedDeps.filter { it.module != null }.mapNotNull { it.test })
+ addAll(aggregatedUninstallModulesDeps.map { it.test })
+ }
+ return roots
+ .filter { it.isTestRoot && it.allowsSharingComponent }
+ .map { it.root }
+ .filter { !hasLocalModuleDependencies.contains(it) }
+ .toSet()
+ }
+
+ private fun aggregatedDepsByRoot(
+ aggregatedRoots: Set<AggregatedRootIr>,
+ rootsUsingSharedComponent: Set<ClassName>,
+ hasEarlyEntryPoints: Boolean
+ ): Map<ClassName, Set<ClassName>> {
+ val testDepsByRoot = aggregatedDeps
+ .filter { it.test != null }
+ .groupBy(keySelector = { it.test }, valueTransform = { it.fqName })
+ val globalModules = aggregatedDeps
+ .filter { it.test == null && it.module != null }
+ .map { it.fqName }
+ val globalEntryPointsByComponent = aggregatedDeps
+ .filter { it.test == null && it.module == null }
+ .groupBy(keySelector = { it.test }, valueTransform = { it.fqName })
+ val result = mutableMapOf<ClassName, LinkedHashSet<ClassName>>()
+ aggregatedRoots.forEach { aggregatedRoot ->
+ if (!rootsUsingSharedComponent.contains(aggregatedRoot.root)) {
+ result.getOrPut(aggregatedRoot.root) { linkedSetOf() }.apply {
+ addAll(globalModules)
+ addAll(globalEntryPointsByComponent.values.flatten())
+ addAll(testDepsByRoot.getOrElse(aggregatedRoot.root) { emptyList() })
+ }
+ }
+ }
+ // Add the Default/EarlyEntryPoint root if necessary.
+ if (rootsUsingSharedComponent.isNotEmpty()) {
+ result.getOrPut(DEFAULT_ROOT_CLASS_NAME) { linkedSetOf() }.apply {
+ addAll(globalModules)
+ addAll(globalEntryPointsByComponent.values.flatten())
+ addAll(rootsUsingSharedComponent.flatMap { testDepsByRoot.getOrElse(it) { emptyList() } })
+ }
+ } else if (hasEarlyEntryPoints) {
+ result.getOrPut(DEFAULT_ROOT_CLASS_NAME) { linkedSetOf() }.apply {
+ addAll(globalModules)
+ addAll(
+ globalEntryPointsByComponent.entries
+ .filterNot { (component, _) -> component == SINGLETON_COMPONENT_CLASS_NAME }
+ .flatMap { (_, entryPoints) -> entryPoints }
+ )
+ }
+ }
+ return result
+ }
+
+ /**
+ * Generates a component name for a tree that will be based off the given root after mapping it to
+ * the [destinationPackage] and disambiguating from [otherRootNames].
+ */
+ private class ComponentTreeDepsNameGenerator(
+ private val destinationPackage: String? = null,
+ private val otherRootNames: Collection<ClassName> = emptySet()
+ ) {
+ private val simpleNameMap: Map<ClassName, String> by lazy {
+ mutableMapOf<ClassName, String>().apply {
+ otherRootNames.groupBy { it.enclosedName() }.values.forEach { conflictingRootNames ->
+ if (conflictingRootNames.size == 1) {
+ // If there's only 1 root there's nothing to disambiguate so return the simple name.
+ put(conflictingRootNames.first(), conflictingRootNames.first().enclosedName())
+ } else {
+ // There are conflicting simple names, so disambiguate them with a unique prefix.
+ // We keep them small to fix https://github.com/google/dagger/issues/421.
+ // Sorted in order to guarantee determinism if this is invoked by different processors.
+ val usedNames = mutableSetOf<String>()
+ conflictingRootNames.sorted().forEach { rootClassName ->
+ val basePrefix = rootClassName.let { className ->
+ val containerName = className.enclosingClassName()?.enclosedName() ?: ""
+ if (containerName.isNotEmpty() && containerName[0].isUpperCase()) {
+ // If parent element looks like a class, use its initials as a prefix.
+ containerName.filterNot { it.isLowerCase() }
+ } else {
+ // Not in a normally named class. Prefix with the initials of the elements
+ // leading here.
+ className.toString().split('.').dropLast(1)
+ .joinToString(separator = "") { "${it.first()}" }
+ }
+ }
+ var uniqueName = basePrefix
+ var differentiator = 2
+ while (!usedNames.add(uniqueName)) {
+ uniqueName = basePrefix + differentiator++
+ }
+ put(rootClassName, "${uniqueName}_${rootClassName.enclosedName()}")
+ }
+ }
+ }
+ }
+ }
+
+ fun generate(rootName: ClassName): ClassName =
+ ClassName.get(
+ destinationPackage ?: rootName.packageName(),
+ if (otherRootNames.isEmpty()) {
+ rootName.enclosedName()
+ } else {
+ simpleNameMap.getValue(rootName)
+ }
+ ).append("_ComponentTreeDeps")
+
+ private fun ClassName.enclosedName() = simpleNames().joinToString(separator = "_")
+
+ private fun ClassName.append(suffix: String) = peerClass(simpleName() + suffix)
+ }
+
+ companion object {
+
+ @JvmStatic
+ fun components(
+ isTest: Boolean,
+ isSharedTestComponentsEnabled: Boolean,
+ aggregatedRoots: Set<AggregatedRootIr>,
+ defineComponentDeps: Set<DefineComponentClassesIr>,
+ aliasOfDeps: Set<AliasOfPropagatedDataIr>,
+ aggregatedDeps: Set<AggregatedDepsIr>,
+ aggregatedUninstallModulesDeps: Set<AggregatedUninstallModulesIr>,
+ aggregatedEarlyEntryPointDeps: Set<AggregatedEarlyEntryPointIr>,
+ ) = ComponentTreeDepsIrCreator(
+ isSharedTestComponentsEnabled,
+ // TODO(bcorso): Consider creating a common interface for fqName so that we can sort these
+ // using a shared method rather than repeating the sorting logic.
+ aggregatedRoots.toList().sortedBy { it.fqName.canonicalName() }.toSet(),
+ defineComponentDeps.toList().sortedBy { it.fqName.canonicalName() }.toSet(),
+ aliasOfDeps.toList().sortedBy { it.fqName.canonicalName() }.toSet(),
+ aggregatedDeps.toList().sortedBy { it.fqName.canonicalName() }.toSet(),
+ aggregatedUninstallModulesDeps.toList().sortedBy { it.fqName.canonicalName() }.toSet(),
+ aggregatedEarlyEntryPointDeps.toList().sortedBy { it.fqName.canonicalName() }.toSet()
+ ).let { producer ->
+ if (isTest) {
+ producer.testComponents()
+ } else {
+ producer.prodComponents()
+ }
+ }
+
+ val DEFAULT_ROOT_CLASS_NAME: ClassName =
+ ClassName.get("dagger.hilt.android.internal.testing.root", "Default")
+ val SINGLETON_COMPONENT_CLASS_NAME: ClassName =
+ ClassName.get("dagger.hilt.components", "SingletonComponent")
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/root/ir/MetadataIr.kt b/java/dagger/hilt/processor/internal/root/ir/MetadataIr.kt
new file mode 100644
index 000000000..200c0d45a
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/root/ir/MetadataIr.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal.root.ir
+
+import com.squareup.javapoet.ClassName
+
+/**
+ * Represents [dagger.hilt.processor.internal.aggregateddeps.AggregatedDeps]
+ *
+ * Even though the annotation uses arrays for modules, entryPoints and componentEntryPoints the
+ * reality is that exactly only one value will be present in one of those arrays.
+ */
+data class AggregatedDepsIr(
+ val fqName: ClassName,
+ val components: List<ClassName>,
+ val test: ClassName?,
+ val replaces: List<ClassName>,
+ val module: ClassName?,
+ val entryPoint: ClassName?,
+ val componentEntryPoint: ClassName?,
+)
+
+/** Represents [dagger.hilt.android.internal.earlyentrypoint.AggregatedEarlyEntryPoint] */
+data class AggregatedEarlyEntryPointIr(
+ val fqName: ClassName,
+ val earlyEntryPoint: ClassName,
+)
+
+/** Represents [dagger.hilt.android.internal.legacy.AggregatedElementProxy] */
+data class AggregatedElementProxyIr(
+ val fqName: ClassName,
+ val value: ClassName,
+)
+
+/** Represents [dagger.hilt.internal.aggregatedroot.AggregatedRoot] */
+data class AggregatedRootIr(
+ val fqName: ClassName,
+ val root: ClassName,
+ val originatingRoot: ClassName,
+ val rootAnnotation: ClassName,
+ // External property from the annotation that indicates if root can use a shared component.
+ val allowsSharingComponent: Boolean = true
+) {
+ // Equivalent to RootType.isTestRoot()
+ val isTestRoot = TEST_ROOT_ANNOTATIONS.contains(rootAnnotation.toString())
+
+ companion object {
+ private val TEST_ROOT_ANNOTATIONS =
+ listOf(
+ "dagger.hilt.android.testing.HiltAndroidTest",
+ "dagger.hilt.android.internal.testing.InternalTestRoot",
+ )
+ }
+}
+
+/** Represents [dagger.hilt.android.internal.uninstallmodules.AggregatedUninstallModules] */
+data class AggregatedUninstallModulesIr(
+ val fqName: ClassName,
+ val test: ClassName,
+ val uninstallModules: List<ClassName>
+)
+
+/** Represents [dagger.hilt.internal.aliasof.AliasOfPropagatedData] */
+data class AliasOfPropagatedDataIr(
+ val fqName: ClassName,
+ val defineComponentScopes: List<ClassName>,
+ val alias: ClassName,
+)
+
+/** Represents [dagger.hilt.internal.componenttreedeps.ComponentTreeDeps] */
+data class ComponentTreeDepsIr(
+ val name: ClassName,
+ val rootDeps: Set<ClassName>,
+ val defineComponentDeps: Set<ClassName>,
+ val aliasOfDeps: Set<ClassName>,
+ val aggregatedDeps: Set<ClassName>,
+ val uninstallModulesDeps: Set<ClassName>,
+ val earlyEntryPointDeps: Set<ClassName>,
+)
+
+/** Represents [dagger.hilt.internal.definecomponent.DefineComponentClasses] */
+data class DefineComponentClassesIr(
+ val fqName: ClassName,
+ val component: ClassName,
+)
+
+/** Represents [dagger.hilt.internal.processedrootsentinel.ProcessedRootSentinel] */
+data class ProcessedRootSentinelIr(val fqName: ClassName, val roots: List<ClassName>)
diff --git a/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesMetadata.java b/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesMetadata.java
index eee78490d..5cad3c9df 100644
--- a/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesMetadata.java
+++ b/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesMetadata.java
@@ -23,10 +23,13 @@ import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.AggregatedElements;
import dagger.hilt.processor.internal.AnnotationValues;
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.Processors;
+import dagger.hilt.processor.internal.root.ir.AggregatedUninstallModulesIr;
+import java.util.stream.Collectors;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.TypeElement;
@@ -39,6 +42,9 @@ import javax.lang.model.util.Elements;
@AutoValue
public abstract class AggregatedUninstallModulesMetadata {
+ /** Returns the aggregating element */
+ public abstract TypeElement aggregatingElement();
+
/** Returns the test annotated with {@link dagger.hilt.android.testing.UninstallModules}. */
public abstract TypeElement testElement();
@@ -47,17 +53,33 @@ public abstract class AggregatedUninstallModulesMetadata {
*/
public abstract ImmutableList<TypeElement> uninstallModuleElements();
- /** Returns all aggregated deps in the aggregating package mapped by the top-level element. */
+ /** Returns metadata for all aggregated elements in the aggregating package. */
public static ImmutableSet<AggregatedUninstallModulesMetadata> from(Elements elements) {
- return AggregatedElements.from(
+ return from(
+ AggregatedElements.from(
ClassNames.AGGREGATED_UNINSTALL_MODULES_PACKAGE,
ClassNames.AGGREGATED_UNINSTALL_MODULES,
- elements)
- .stream()
+ elements),
+ elements);
+ }
+
+ /** Returns metadata for each aggregated element. */
+ public static ImmutableSet<AggregatedUninstallModulesMetadata> from(
+ ImmutableSet<TypeElement> aggregatedElements, Elements elements) {
+ return aggregatedElements.stream()
.map(aggregatedElement -> create(aggregatedElement, elements))
.collect(toImmutableSet());
}
+ public static AggregatedUninstallModulesIr toIr(AggregatedUninstallModulesMetadata metadata) {
+ return new AggregatedUninstallModulesIr(
+ ClassName.get(metadata.aggregatingElement()),
+ ClassName.get(metadata.testElement()),
+ metadata.uninstallModuleElements().stream()
+ .map(ClassName::get)
+ .collect(Collectors.toList()));
+ }
+
private static AggregatedUninstallModulesMetadata create(TypeElement element, Elements elements) {
AnnotationMirror annotationMirror =
Processors.getAnnotationMirror(element, ClassNames.AGGREGATED_UNINSTALL_MODULES);
@@ -66,6 +88,7 @@ public abstract class AggregatedUninstallModulesMetadata {
Processors.getAnnotationValues(elements, annotationMirror);
return new AutoValue_AggregatedUninstallModulesMetadata(
+ element,
elements.getTypeElement(AnnotationValues.getString(values.get("test"))),
AnnotationValues.getAnnotationValues(values.get("uninstallModules")).stream()
.map(AnnotationValues::getString)
diff --git a/java/dagger/hilt/processor/internal/uninstallmodules/BUILD b/java/dagger/hilt/processor/internal/uninstallmodules/BUILD
index 4f944be48..876c4739f 100644
--- a/java/dagger/hilt/processor/internal/uninstallmodules/BUILD
+++ b/java/dagger/hilt/processor/internal/uninstallmodules/BUILD
@@ -36,11 +36,11 @@ java_library(
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:service",
+ "//third_party/java/guava/collect",
+ "//third_party/java/incap",
+ "//third_party/java/javapoet",
],
)
@@ -53,9 +53,11 @@ java_library(
"//java/dagger/hilt/processor/internal:aggregated_elements",
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processors",
+ "//java/dagger/hilt/processor/internal/root/ir",
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
diff --git a/java/dagger/hilt/testing/BUILD b/java/dagger/hilt/testing/BUILD
index 3ea1c5f4b..59a1e9447 100644
--- a/java/dagger/hilt/testing/BUILD
+++ b/java/dagger/hilt/testing/BUILD
@@ -21,7 +21,7 @@ java_library(
name = "package_info",
srcs = ["package-info.java"],
deps = [
- "@google_bazel_common//third_party/java/jsr305_annotations",
+ "//third_party/java/jsr305_annotations",
],
)
diff --git a/java/dagger/internal/DoubleCheck.java b/java/dagger/internal/DoubleCheck.java
index ea07528bf..af7d7f69a 100644
--- a/java/dagger/internal/DoubleCheck.java
+++ b/java/dagger/internal/DoubleCheck.java
@@ -60,11 +60,8 @@ public final class DoubleCheck<T> implements Provider<T>, Lazy<T> {
* new instance is the same as the current instance, return the instance. However, if the new
* instance differs from the current instance, an {@link IllegalStateException} is thrown.
*/
- public static Object reentrantCheck(Object currentInstance, Object newInstance) {
- boolean isReentrant = !(currentInstance == UNINITIALIZED
- // This check is needed for fastInit's implementation, which uses MemoizedSentinel types.
- || currentInstance instanceof MemoizedSentinel);
-
+ private static Object reentrantCheck(Object currentInstance, Object newInstance) {
+ boolean isReentrant = currentInstance != UNINITIALIZED;
if (isReentrant && currentInstance != newInstance) {
throw new IllegalStateException("Scoped provider was invoked recursively returning "
+ "different results: " + currentInstance + " & " + newInstance + ". This is likely "
diff --git a/java/dagger/internal/QualifierMetadata.java b/java/dagger/internal/QualifierMetadata.java
new file mode 100644
index 000000000..aa6f0d0de
--- /dev/null
+++ b/java/dagger/internal/QualifierMetadata.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/** Stores the qualifier information about a type after it's been processed. */
+@Retention(CLASS)
+@Target(TYPE)
+public @interface QualifierMetadata {
+ /**
+ * Returns the list of fully qualified qualifier names used in a particular context.
+ *
+ * <p>For example, when annotating Dagger's generated {@code _Factory} class for an inject
+ * constructor, it contains all qualifiers used on parameters within the constructor. When
+ * annotating Dagger's generated {@code _MembersInjector} class for inject fields and methods, it
+ * contains all qualifiers found on the fields and method parameters. When annotating Dagger's
+ * generated {@code _Factory} class for provision methods it includes all qualifiers used on the
+ * provision method and its parameters.
+ */
+ String[] value() default {};
+}
diff --git a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/Model.java b/java/dagger/internal/ScopeMetadata.java
index 30a973e03..a313b5e4f 100644
--- a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/Model.java
+++ b/java/dagger/internal/ScopeMetadata.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Dagger Authors.
+ * Copyright (C) 2022 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,16 +14,18 @@
* limitations under the License.
*/
-package dagger.example.gradle.android.simple;
+package dagger.internal;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.CLASS;
-import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
+import java.lang.annotation.Target;
-/** Qualifies bindings relating to {@link android.os.Build#MODEL}. */
-@Qualifier
-@Retention(RUNTIME)
-@Documented
-@interface Model {}
+/** Stores the scope information about a type after it's been processed. */
+@Retention(CLASS)
+@Target(TYPE)
+public @interface ScopeMetadata {
+ /** The qualified name of the scope, if one exists, otherwise an empty string. */
+ String value() default "";
+}
diff --git a/java/dagger/internal/codegen/AssistedFactoryProcessingStep.java b/java/dagger/internal/codegen/AssistedFactoryProcessingStep.java
index dbd2b3365..7242e267a 100644
--- a/java/dagger/internal/codegen/AssistedFactoryProcessingStep.java
+++ b/java/dagger/internal/codegen/AssistedFactoryProcessingStep.java
@@ -16,24 +16,31 @@
package dagger.internal.codegen;
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.auto.common.MoreTypes.asTypeElement;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedFactoryMethods;
import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedInjectedConstructors;
import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
import static dagger.internal.codegen.javapoet.TypeNames.INSTANCE_FACTORY;
import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static dagger.internal.codegen.xprocessing.XMethodElements.hasTypeParameters;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
import static java.util.stream.Collectors.joining;
-import static javax.lang.model.element.Modifier.ABSTRACT;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
@@ -45,7 +52,6 @@ import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
-import dagger.assisted.AssistedFactory;
import dagger.internal.codegen.base.SourceFileGenerationException;
import dagger.internal.codegen.base.SourceFileGenerator;
import dagger.internal.codegen.binding.AssistedInjectionAnnotations;
@@ -53,62 +59,55 @@ import dagger.internal.codegen.binding.AssistedInjectionAnnotations.AssistedFact
import dagger.internal.codegen.binding.AssistedInjectionAnnotations.AssistedParameter;
import dagger.internal.codegen.binding.BindingFactory;
import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.validation.SuperficialValidator;
import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
import dagger.internal.codegen.validation.ValidationReport;
-import java.lang.annotation.Annotation;
+import dagger.internal.codegen.xprocessing.MethodSpecs;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
-import javax.annotation.processing.Filer;
-import javax.annotation.processing.Messager;
import javax.inject.Inject;
import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
/** An annotation processor for {@link dagger.assisted.AssistedFactory}-annotated types. */
-final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<TypeElement> {
- private final Messager messager;
- private final Filer filer;
+final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<XTypeElement> {
+ private final XMessager messager;
+ private final XFiler filer;
private final SourceVersion sourceVersion;
private final DaggerElements elements;
private final DaggerTypes types;
private final BindingFactory bindingFactory;
+ private final SuperficialValidator superficialValidator;
@Inject
AssistedFactoryProcessingStep(
- Messager messager,
- Filer filer,
+ XMessager messager,
+ XFiler filer,
SourceVersion sourceVersion,
DaggerElements elements,
DaggerTypes types,
- BindingFactory bindingFactory) {
- super(MoreElements::asType);
+ BindingFactory bindingFactory,
+ SuperficialValidator superficialValidator) {
this.messager = messager;
this.filer = filer;
this.sourceVersion = sourceVersion;
this.elements = elements;
this.types = types;
this.bindingFactory = bindingFactory;
+ this.superficialValidator = superficialValidator;
}
@Override
- public ImmutableSet<Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(AssistedFactory.class);
+ public ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(TypeNames.ASSISTED_FACTORY);
}
@Override
- protected void process(
- TypeElement factory, ImmutableSet<Class<? extends Annotation>> annotations) {
- ValidationReport<TypeElement> report = new AssistedFactoryValidator().validate(factory);
+ protected void process(XTypeElement factory, ImmutableSet<ClassName> annotations) {
+ ValidationReport report = new AssistedFactoryValidator().validate(factory);
report.printMessagesTo(messager);
if (report.isClean()) {
try {
@@ -121,10 +120,10 @@ final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<Typ
}
private final class AssistedFactoryValidator {
- ValidationReport<TypeElement> validate(TypeElement factory) {
- ValidationReport.Builder<TypeElement> report = ValidationReport.about(factory);
+ ValidationReport validate(XTypeElement factory) {
+ ValidationReport.Builder report = ValidationReport.about(factory);
- if (!factory.getModifiers().contains(ABSTRACT)) {
+ if (!factory.isAbstract()) {
return report
.addError(
"The @AssistedFactory-annotated type must be either an abstract class or "
@@ -133,12 +132,11 @@ final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<Typ
.build();
}
- if (factory.getNestingKind().isNested() && !factory.getModifiers().contains(STATIC)) {
+ if (factory.isNested() && !factory.isStatic()) {
report.addError("Nested @AssistedFactory-annotated types must be static. ", factory);
}
- ImmutableSet<ExecutableElement> abstractFactoryMethods =
- AssistedInjectionAnnotations.assistedFactoryMethods(factory, elements);
+ ImmutableSet<XMethodElement> abstractFactoryMethods = assistedFactoryMethods(factory);
if (abstractFactoryMethods.isEmpty()) {
report.addError(
@@ -147,17 +145,23 @@ final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<Typ
factory);
}
- for (ExecutableElement method : abstractFactoryMethods) {
- ExecutableType methodType = types.resolveExecutableType(method, factory.asType());
- if (!isAssistedInjectionType(methodType.getReturnType())) {
+ for (XMethodElement method : abstractFactoryMethods) {
+ XType returnType = method.asMemberOf(factory.getType()).getReturnType();
+ // The default superficial validation only applies to the @AssistedFactory-annotated
+ // element, so we have to manually check the superficial validation of the @AssistedInject
+ // element before using it to ensure it's ready for processing.
+ if (isDeclared(returnType)) {
+ superficialValidator.throwIfNearestEnclosingTypeNotValid(returnType.getTypeElement());
+ }
+ if (!isAssistedInjectionType(returnType)) {
report.addError(
String.format(
"Invalid return type: %s. An assisted factory's abstract method must return a "
+ "type with an @AssistedInject-annotated constructor.",
- methodType.getReturnType()),
+ returnType),
method);
}
- if (!method.getTypeParameters().isEmpty()) {
+ if (hasTypeParameters(method)) {
report.addError(
"@AssistedFactory does not currently support type parameters in the creator "
+ "method. See https://github.com/google/dagger/issues/2279",
@@ -177,8 +181,7 @@ final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<Typ
return report.build();
}
- AssistedFactoryMetadata metadata =
- AssistedFactoryMetadata.create(factory.asType(), elements, types);
+ AssistedFactoryMetadata metadata = AssistedFactoryMetadata.create(factory.getType());
// Note: We check uniqueness of the @AssistedInject constructor parameters in
// AssistedInjectProcessingStep. We need to check uniqueness for here too because we may
@@ -188,7 +191,7 @@ final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<Typ
if (!uniqueAssistedParameters.add(assistedParameter)) {
report.addError(
"@AssistedFactory method has duplicate @Assisted types: " + assistedParameter,
- assistedParameter.variableElement());
+ assistedParameter.element());
}
}
@@ -203,7 +206,7 @@ final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<Typ
metadata.factory().getQualifiedName(),
metadata.factoryMethod(),
metadata.factory().getQualifiedName(),
- metadata.factoryMethod().getSimpleName(),
+ getSimpleName(metadata.factoryMethod()),
metadata.assistedInjectAssistedParameters().stream()
.map(AssistedParameter::type)
.map(Object::toString)
@@ -214,9 +217,9 @@ final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<Typ
return report.build();
}
- private boolean isAssistedInjectionType(TypeMirror type) {
- return type.getKind() == TypeKind.DECLARED
- && AssistedInjectionAnnotations.isAssistedInjectionType(asTypeElement(type));
+ private boolean isAssistedInjectionType(XType type) {
+ return isDeclared(type)
+ && AssistedInjectionAnnotations.isAssistedInjectionType(type.getTypeElement());
}
}
@@ -227,7 +230,7 @@ final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<Typ
}
@Override
- public Element originatingElement(ProvisionBinding binding) {
+ public XElement originatingElement(ProvisionBinding binding) {
return binding.bindingElement().get();
}
@@ -265,25 +268,24 @@ final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<Typ
// }
@Override
public ImmutableList<TypeSpec.Builder> topLevelTypes(ProvisionBinding binding) {
- TypeElement factory = asType(binding.bindingElement().get());
+ XTypeElement factory = asTypeElement(binding.bindingElement().get());
ClassName name = generatedClassNameForBinding(binding);
TypeSpec.Builder builder =
TypeSpec.classBuilder(name)
.addModifiers(PUBLIC, FINAL)
.addTypeVariables(
- factory.getTypeParameters().stream()
+ toJavac(factory).getTypeParameters().stream()
.map(TypeVariableName::get)
.collect(toImmutableList()));
- if (factory.getKind() == ElementKind.INTERFACE) {
- builder.addSuperinterface(factory.asType());
+ if (factory.isInterface()) {
+ builder.addSuperinterface(factory.getType().getTypeName());
} else {
- builder.superclass(factory.asType());
+ builder.superclass(factory.getType().getTypeName());
}
- AssistedFactoryMetadata metadata =
- AssistedFactoryMetadata.create(asDeclared(factory.asType()), elements, types);
+ AssistedFactoryMetadata metadata = AssistedFactoryMetadata.create(factory.getType());
ParameterSpec delegateFactoryParam =
ParameterSpec.builder(
delegateFactoryTypeName(metadata.assistedInjectType()), "delegateFactory")
@@ -299,7 +301,7 @@ final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<Typ
.addStatement("this.$1N = $1N", delegateFactoryParam)
.build())
.addMethod(
- MethodSpec.overriding(metadata.factoryMethod(), metadata.factoryType(), types)
+ MethodSpecs.overriding(metadata.factoryMethod(), metadata.factoryType())
.addStatement(
"return $N.get($L)",
delegateFactoryParam,
@@ -307,7 +309,7 @@ final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<Typ
// use the parameter names of the @AssistedFactory method.
metadata.assistedInjectAssistedParameters().stream()
.map(metadata.assistedFactoryAssistedParametersMap()::get)
- .map(param -> CodeBlock.of("$L", param.getSimpleName()))
+ .map(param -> CodeBlock.of("$L", getSimpleName(param)))
.collect(toParametersCodeBlock()))
.build())
.addMethod(
@@ -315,10 +317,10 @@ final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<Typ
.addModifiers(PUBLIC, STATIC)
.addParameter(delegateFactoryParam)
.addTypeVariables(
- metadata.assistedInjectElement().getTypeParameters().stream()
+ toJavac(metadata.assistedInjectElement()).getTypeParameters().stream()
.map(TypeVariableName::get)
.collect(toImmutableList()))
- .returns(providerOf(TypeName.get(factory.asType())))
+ .returns(providerOf(factory.getType().getTypeName()))
.addStatement(
"return $T.$Lcreate(new $T($N))",
INSTANCE_FACTORY,
@@ -333,13 +335,13 @@ final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<Typ
}
/** Returns the generated factory {@link TypeName type} for an @AssistedInject constructor. */
- private TypeName delegateFactoryTypeName(DeclaredType assistedInjectType) {
+ private TypeName delegateFactoryTypeName(XType assistedInjectType) {
// The name of the generated factory for the assisted inject type,
// e.g. an @AssistedInject Foo(...) {...} constructor will generate a Foo_Factory class.
ClassName generatedFactoryClassName =
generatedClassNameForBinding(
bindingFactory.injectionBinding(
- getOnlyElement(assistedInjectedConstructors(asTypeElement(assistedInjectType))),
+ getOnlyElement(assistedInjectedConstructors(assistedInjectType.getTypeElement())),
Optional.empty()));
// Return the factory type resolved with the same type parameters as the assisted inject type.
@@ -348,7 +350,7 @@ final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<Typ
: ParameterizedTypeName.get(
generatedFactoryClassName,
assistedInjectType.getTypeArguments().stream()
- .map(TypeName::get)
+ .map(XType::getTypeName)
.collect(toImmutableList())
.toArray(new TypeName[0]));
}
diff --git a/java/dagger/internal/codegen/AssistedInjectProcessingStep.java b/java/dagger/internal/codegen/AssistedInjectProcessingStep.java
index 167c4aebe..df3a7d644 100644
--- a/java/dagger/internal/codegen/AssistedInjectProcessingStep.java
+++ b/java/dagger/internal/codegen/AssistedInjectProcessingStep.java
@@ -16,71 +16,60 @@
package dagger.internal.codegen;
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.common.base.Preconditions.checkState;
-import static dagger.internal.codegen.langmodel.DaggerElements.closestEnclosingTypeElement;
+import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedInjectAssistedParameters;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XType;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.binding.AssistedInjectionAnnotations;
+import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.binding.AssistedInjectionAnnotations.AssistedParameter;
-import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
import dagger.internal.codegen.validation.ValidationReport;
-import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.Set;
-import javax.annotation.processing.Messager;
import javax.inject.Inject;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.DeclaredType;
/** An annotation processor for {@link dagger.assisted.AssistedInject}-annotated elements. */
-final class AssistedInjectProcessingStep extends TypeCheckingProcessingStep<ExecutableElement> {
- private final DaggerTypes types;
- private final Messager messager;
+final class AssistedInjectProcessingStep extends TypeCheckingProcessingStep<XConstructorElement> {
+ private final XMessager messager;
@Inject
- AssistedInjectProcessingStep(DaggerTypes types, Messager messager) {
- super(MoreElements::asExecutable);
- this.types = types;
+ AssistedInjectProcessingStep(XMessager messager) {
this.messager = messager;
}
@Override
- public ImmutableSet<Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(AssistedInject.class);
+ public ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(TypeNames.ASSISTED_INJECT);
}
@Override
protected void process(
- ExecutableElement assistedInjectElement,
- ImmutableSet<Class<? extends Annotation>> annotations) {
+ XConstructorElement assistedInjectElement, ImmutableSet<ClassName> annotations) {
new AssistedInjectValidator().validate(assistedInjectElement).printMessagesTo(messager);
}
private final class AssistedInjectValidator {
- ValidationReport<ExecutableElement> validate(ExecutableElement constructor) {
- checkState(constructor.getKind() == ElementKind.CONSTRUCTOR);
- ValidationReport.Builder<ExecutableElement> report = ValidationReport.about(constructor);
+ ValidationReport validate(XConstructorElement constructor) {
+ ValidationReport.Builder report = ValidationReport.about(constructor);
- DeclaredType assistedInjectType =
- asDeclared(closestEnclosingTypeElement(constructor).asType());
+ XType assistedInjectType = constructor.getEnclosingElement().getType();
ImmutableList<AssistedParameter> assistedParameters =
- AssistedInjectionAnnotations.assistedInjectAssistedParameters(assistedInjectType, types);
+ assistedInjectAssistedParameters(assistedInjectType);
Set<AssistedParameter> uniqueAssistedParameters = new HashSet<>();
for (AssistedParameter assistedParameter : assistedParameters) {
if (!uniqueAssistedParameters.add(assistedParameter)) {
report.addError(
- String.format("@AssistedInject constructor has duplicate @Assisted type: %s. "
- + "Consider setting an identifier on the parameter by using "
- + "@Assisted(\"identifier\") in both the factory and @AssistedInject constructor",
+ String.format(
+ "@AssistedInject constructor has duplicate @Assisted type: %s. Consider setting"
+ + " an identifier on the parameter by using @Assisted(\"identifier\") in both"
+ + " the factory and @AssistedInject constructor",
assistedParameter),
- assistedParameter.variableElement());
+ assistedParameter.element());
}
}
diff --git a/java/dagger/internal/codegen/AssistedProcessingStep.java b/java/dagger/internal/codegen/AssistedProcessingStep.java
index 12a0d34b4..c44d2c550 100644
--- a/java/dagger/internal/codegen/AssistedProcessingStep.java
+++ b/java/dagger/internal/codegen/AssistedProcessingStep.java
@@ -16,67 +16,57 @@
package dagger.internal.codegen;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static dagger.internal.codegen.langmodel.DaggerElements.closestEnclosingTypeElement;
+import static androidx.room.compiler.processing.XElementKt.isConstructor;
+import static androidx.room.compiler.processing.XElementKt.isMethod;
+import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedFactoryMethod;
+import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedFactoryType;
+import static dagger.internal.codegen.xprocessing.XElements.asMethod;
+import static dagger.internal.codegen.xprocessing.XElements.closestEnclosingTypeElement;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XExecutableParameterElement;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.binding.AssistedInjectionAnnotations;
+import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
import dagger.internal.codegen.validation.ValidationReport;
-import java.lang.annotation.Annotation;
-import javax.annotation.processing.Messager;
import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
/**
* An annotation processor for {@link dagger.assisted.Assisted}-annotated types.
*
* <p>This processing step should run after {@link AssistedFactoryProcessingStep}.
*/
-final class AssistedProcessingStep extends TypeCheckingProcessingStep<VariableElement> {
- private final KotlinMetadataUtil kotlinMetadataUtil;
+final class AssistedProcessingStep extends TypeCheckingProcessingStep<XExecutableParameterElement> {
private final InjectionAnnotations injectionAnnotations;
- private final DaggerElements elements;
- private final Messager messager;
+ private final XMessager messager;
@Inject
- AssistedProcessingStep(
- KotlinMetadataUtil kotlinMetadataUtil,
- InjectionAnnotations injectionAnnotations,
- DaggerElements elements,
- Messager messager) {
- super(MoreElements::asVariable);
- this.kotlinMetadataUtil = kotlinMetadataUtil;
+ AssistedProcessingStep(InjectionAnnotations injectionAnnotations, XMessager messager) {
this.injectionAnnotations = injectionAnnotations;
- this.elements = elements;
this.messager = messager;
}
@Override
- public ImmutableSet<Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(Assisted.class);
+ public ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(TypeNames.ASSISTED);
}
@Override
protected void process(
- VariableElement assisted, ImmutableSet<Class<? extends Annotation>> annotations) {
+ XExecutableParameterElement assisted, ImmutableSet<ClassName> annotations) {
new AssistedValidator().validate(assisted).printMessagesTo(messager);
}
private final class AssistedValidator {
- ValidationReport<VariableElement> validate(VariableElement assisted) {
- ValidationReport.Builder<VariableElement> report = ValidationReport.about(assisted);
+ ValidationReport validate(XExecutableParameterElement assisted) {
+ ValidationReport.Builder report = ValidationReport.about(assisted);
- Element enclosingElement = assisted.getEnclosingElement();
+ XExecutableElement enclosingElement = assisted.getEnclosingMethodElement();
if (!isAssistedInjectConstructor(enclosingElement)
&& !isAssistedFactoryCreateMethod(enclosingElement)
// The generated java stubs for kotlin data classes contain a "copy" method that has
@@ -99,30 +89,29 @@ final class AssistedProcessingStep extends TypeCheckingProcessingStep<VariableEl
}
}
- private boolean isAssistedInjectConstructor(Element element) {
- return element.getKind() == ElementKind.CONSTRUCTOR
- && isAnnotationPresent(element, AssistedInject.class);
+ private boolean isAssistedInjectConstructor(XExecutableElement executableElement) {
+ return isConstructor(executableElement)
+ && executableElement.hasAnnotation(TypeNames.ASSISTED_INJECT);
}
- private boolean isAssistedFactoryCreateMethod(Element element) {
- if (element.getKind() == ElementKind.METHOD) {
- TypeElement enclosingElement = closestEnclosingTypeElement(element);
- return AssistedInjectionAnnotations.isAssistedFactoryType(enclosingElement)
+ private boolean isAssistedFactoryCreateMethod(XExecutableElement executableElement) {
+ if (isMethod(executableElement)) {
+ XTypeElement enclosingElement = closestEnclosingTypeElement(executableElement);
+ return isAssistedFactoryType(enclosingElement)
// This assumes we've already validated AssistedFactory and that a valid method exists.
- && AssistedInjectionAnnotations.assistedFactoryMethod(enclosingElement, elements)
- .equals(element);
+ && assistedFactoryMethod(enclosingElement).equals(executableElement);
}
return false;
}
- private boolean isKotlinDataClassCopyMethod(Element element) {
+ private boolean isKotlinDataClassCopyMethod(XExecutableElement executableElement) {
// Note: This is a best effort. Technically, we could check the return type and parameters of
// the copy method to verify it's the one associated with the constructor, but I'd rather keep
// this simple to avoid encoding too many details of kapt's stubs. At worst, we'll be allowing
// an @Assisted annotation that has no affect, which is already true for many of Dagger's other
// annotations.
- return element.getKind() == ElementKind.METHOD
- && element.getSimpleName().contentEquals("copy")
- && kotlinMetadataUtil.isDataClass(closestEnclosingTypeElement(element));
+ return isMethod(executableElement)
+ && getSimpleName(asMethod(executableElement)).contentEquals("copy")
+ && closestEnclosingTypeElement(executableElement.getEnclosingElement()).isDataClass();
}
}
diff --git a/java/dagger/internal/codegen/BUILD b/java/dagger/internal/codegen/BUILD
index e2f74e9e7..d1e01ae38 100644
--- a/java/dagger/internal/codegen/BUILD
+++ b/java/dagger/internal/codegen/BUILD
@@ -34,9 +34,6 @@ java_library(
"//java/dagger/internal/codegen/bootstrap",
],
tags = ["maven_coordinates=com.google.dagger:dagger-compiler:" + POM_VERSION],
- exports = [
- "@google_bazel_common//third_party/java/jsr250_annotations", # Export for @Generated
- ],
deps = [
":package_info",
"//java/dagger:core",
@@ -51,17 +48,19 @@ java_library(
"//java/dagger/internal/codegen/langmodel",
"//java/dagger/internal/codegen/validation",
"//java/dagger/internal/codegen/writing",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/producers",
+ "//java/dagger/internal/codegen/xprocessing",
"//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@google_bazel_common//third_party/java/google_java_format",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:service",
+ "//third_party/java/auto:value",
+ "//third_party/java/error_prone:annotations",
+ "//third_party/java/google_java_format",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/incap",
+ "//third_party/java/javapoet",
+ "//third_party/java/jsr330_inject",
+ "@bazel_tools//tools/jdk:langtools-neverlink",
],
)
@@ -69,7 +68,7 @@ java_library(
name = "package_info",
srcs = ["package-info.java"],
tags = ["maven:merged"],
- deps = ["@google_bazel_common//third_party/java/error_prone:annotations"],
+ deps = ["//third_party/java/error_prone:annotations"],
)
gen_maven_artifact(
@@ -90,7 +89,6 @@ gen_maven_artifact(
"//java/dagger/internal/codegen/langmodel",
"//java/dagger/internal/codegen/validation",
"//java/dagger/internal/codegen/writing",
- "//java/dagger/model:internal-proxies",
],
artifact_target_maven_deps = [
"com.google.auto:auto-common",
@@ -102,19 +100,18 @@ gen_maven_artifact(
"com.google.guava:failureaccess",
"com.google.guava:guava",
"com.squareup:javapoet",
- "javax.annotation:jsr250-api",
"javax.inject:javax.inject",
"net.ltgt.gradle.incap:incap",
"org.checkerframework:checker-compat-qual",
"org.jetbrains.kotlin:kotlin-stdlib",
+ "org.jetbrains.kotlin:kotlin-stdlib-jdk8",
"org.jetbrains.kotlinx:kotlinx-metadata-jvm",
],
javadoc_root_packages = ["dagger.internal.codegen"],
# The javadocs should only include ComponentProcessor.java, since that is the only class used
# externally. Specifically, ComponentProcessor.forTesting() is required for testing SPI plugins.
javadoc_srcs = ["ComponentProcessor.java"],
- shaded_deps = ["@maven//:com_google_auto_auto_common"],
- shaded_rules = ["rule com.google.auto.common.** dagger.shaded.auto.common.@1"],
+ # The shaded deps are inherited from dagger spi. For the shaded rules see util/deploy-dagger.sh
)
java_plugin(
diff --git a/java/dagger/internal/codegen/ComponentHjarProcessingStep.java b/java/dagger/internal/codegen/ComponentHjarProcessingStep.java
index 260f65ad9..a75c40b64 100644
--- a/java/dagger/internal/codegen/ComponentHjarProcessingStep.java
+++ b/java/dagger/internal/codegen/ComponentHjarProcessingStep.java
@@ -16,14 +16,15 @@
package dagger.internal.codegen;
-import static com.google.auto.common.MoreElements.asType;
import static com.google.common.collect.Sets.union;
import static dagger.internal.codegen.base.ComponentAnnotation.rootComponentAnnotations;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.rootComponentCreatorAnnotations;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.rootComponentCreatorAnnotations;
import static java.util.Collections.disjoint;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.base.SourceFileGenerator;
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.ComponentDescriptor;
@@ -32,11 +33,8 @@ import dagger.internal.codegen.validation.ComponentCreatorValidator;
import dagger.internal.codegen.validation.ComponentValidator;
import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
import dagger.internal.codegen.validation.ValidationReport;
-import java.lang.annotation.Annotation;
import java.util.Set;
-import javax.annotation.processing.Messager;
import javax.inject.Inject;
-import javax.lang.model.element.TypeElement;
/**
* A processing step that emits the API of a generated component, without any actual implementation.
@@ -51,8 +49,8 @@ import javax.lang.model.element.TypeElement;
* <p>The components emitted by this processing step include all of the API elements exposed by the
* normal step. Method bodies are omitted as Turbine ignores them entirely.
*/
-final class ComponentHjarProcessingStep extends TypeCheckingProcessingStep<TypeElement> {
- private final Messager messager;
+final class ComponentHjarProcessingStep extends TypeCheckingProcessingStep<XTypeElement> {
+ private final XMessager messager;
private final ComponentValidator componentValidator;
private final ComponentCreatorValidator creatorValidator;
private final ComponentDescriptorFactory componentDescriptorFactory;
@@ -60,12 +58,11 @@ final class ComponentHjarProcessingStep extends TypeCheckingProcessingStep<TypeE
@Inject
ComponentHjarProcessingStep(
- Messager messager,
+ XMessager messager,
ComponentValidator componentValidator,
ComponentCreatorValidator creatorValidator,
ComponentDescriptorFactory componentDescriptorFactory,
SourceFileGenerator<ComponentDescriptor> componentGenerator) {
- super(MoreElements::asType);
this.messager = messager;
this.componentValidator = componentValidator;
this.creatorValidator = creatorValidator;
@@ -74,7 +71,7 @@ final class ComponentHjarProcessingStep extends TypeCheckingProcessingStep<TypeE
}
@Override
- public Set<Class<? extends Annotation>> annotations() {
+ public Set<ClassName> annotationClassNames() {
return union(rootComponentAnnotations(), rootComponentCreatorAnnotations());
}
@@ -83,8 +80,7 @@ final class ComponentHjarProcessingStep extends TypeCheckingProcessingStep<TypeE
// clause for any exception that's not TypeNotPresentException and ignore the component entirely
// in that case.
@Override
- protected void process(
- TypeElement element, ImmutableSet<Class<? extends Annotation>> annotations) {
+ protected void process(XTypeElement element, ImmutableSet<ClassName> annotations) {
if (!disjoint(annotations, rootComponentAnnotations())) {
processRootComponent(element);
}
@@ -93,8 +89,8 @@ final class ComponentHjarProcessingStep extends TypeCheckingProcessingStep<TypeE
}
}
- private void processRootComponent(TypeElement element) {
- ValidationReport<TypeElement> validationReport = componentValidator.validate(element);
+ private void processRootComponent(XTypeElement element) {
+ ValidationReport validationReport = componentValidator.validate(element);
validationReport.printMessagesTo(messager);
if (validationReport.isClean()) {
componentGenerator.generate(
@@ -102,7 +98,7 @@ final class ComponentHjarProcessingStep extends TypeCheckingProcessingStep<TypeE
}
}
- private void processRootCreator(TypeElement creator) {
- creatorValidator.validate(asType(creator)).printMessagesTo(messager);
+ private void processRootCreator(XTypeElement creator) {
+ creatorValidator.validate(creator).printMessagesTo(messager);
}
}
diff --git a/java/dagger/internal/codegen/ComponentProcessingStep.java b/java/dagger/internal/codegen/ComponentProcessingStep.java
index 3125ce7f4..6a1f09521 100644
--- a/java/dagger/internal/codegen/ComponentProcessingStep.java
+++ b/java/dagger/internal/codegen/ComponentProcessingStep.java
@@ -16,18 +16,19 @@
package dagger.internal.codegen;
-import static com.google.auto.common.MoreElements.asType;
import static com.google.common.collect.Sets.union;
import static dagger.internal.codegen.base.ComponentAnnotation.allComponentAnnotations;
import static dagger.internal.codegen.base.ComponentAnnotation.rootComponentAnnotations;
import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotations;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.allCreatorAnnotations;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.allCreatorAnnotations;
import static java.util.Collections.disjoint;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
-import com.google.auto.common.MoreElements;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.base.SourceFileGenerator;
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.BindingGraphFactory;
@@ -39,19 +40,15 @@ import dagger.internal.codegen.validation.ComponentDescriptorValidator;
import dagger.internal.codegen.validation.ComponentValidator;
import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
import dagger.internal.codegen.validation.ValidationReport;
-import java.lang.annotation.Annotation;
import java.util.Set;
-import javax.annotation.processing.Messager;
import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
/**
* A {@link ProcessingStep} that is responsible for dealing with a component or production component
* as part of the {@link ComponentProcessor}.
*/
-final class ComponentProcessingStep extends TypeCheckingProcessingStep<TypeElement> {
- private final Messager messager;
+final class ComponentProcessingStep extends TypeCheckingProcessingStep<XTypeElement> {
+ private final XMessager messager;
private final ComponentValidator componentValidator;
private final ComponentCreatorValidator creatorValidator;
private final ComponentDescriptorValidator componentDescriptorValidator;
@@ -62,7 +59,7 @@ final class ComponentProcessingStep extends TypeCheckingProcessingStep<TypeEleme
@Inject
ComponentProcessingStep(
- Messager messager,
+ XMessager messager,
ComponentValidator componentValidator,
ComponentCreatorValidator creatorValidator,
ComponentDescriptorValidator componentDescriptorValidator,
@@ -70,7 +67,6 @@ final class ComponentProcessingStep extends TypeCheckingProcessingStep<TypeEleme
BindingGraphFactory bindingGraphFactory,
SourceFileGenerator<BindingGraph> componentGenerator,
BindingGraphValidator bindingGraphValidator) {
- super(MoreElements::asType);
this.messager = messager;
this.componentValidator = componentValidator;
this.creatorValidator = creatorValidator;
@@ -82,13 +78,12 @@ final class ComponentProcessingStep extends TypeCheckingProcessingStep<TypeEleme
}
@Override
- public Set<Class<? extends Annotation>> annotations() {
+ public Set<ClassName> annotationClassNames() {
return union(allComponentAnnotations(), allCreatorAnnotations());
}
@Override
- protected void process(
- TypeElement element, ImmutableSet<Class<? extends Annotation>> annotations) {
+ protected void process(XTypeElement element, ImmutableSet<ClassName> annotations) {
if (!disjoint(annotations, rootComponentAnnotations())) {
processRootComponent(element);
}
@@ -100,7 +95,7 @@ final class ComponentProcessingStep extends TypeCheckingProcessingStep<TypeEleme
}
}
- private void processRootComponent(TypeElement component) {
+ private void processRootComponent(XTypeElement component) {
if (!isComponentValid(component)) {
return;
}
@@ -118,7 +113,7 @@ final class ComponentProcessingStep extends TypeCheckingProcessingStep<TypeEleme
}
}
- private void processSubcomponent(TypeElement subcomponent) {
+ private void processSubcomponent(XTypeElement subcomponent) {
if (!isComponentValid(subcomponent)) {
return;
}
@@ -132,20 +127,20 @@ final class ComponentProcessingStep extends TypeCheckingProcessingStep<TypeEleme
componentGenerator.generate(bindingGraph, messager);
}
- private void processCreator(Element creator) {
- creatorValidator.validate(MoreElements.asType(creator)).printMessagesTo(messager);
+ private void processCreator(XTypeElement creator) {
+ creatorValidator.validate(creator).printMessagesTo(messager);
}
- private boolean isComponentValid(Element component) {
- ValidationReport<?> report = componentValidator.validate(asType(component));
+ private boolean isComponentValid(XTypeElement component) {
+ ValidationReport report = componentValidator.validate(component);
report.printMessagesTo(messager);
return report.isClean();
}
@CanIgnoreReturnValue
private boolean validateFullBindingGraph(ComponentDescriptor componentDescriptor) {
- TypeElement component = componentDescriptor.typeElement();
- if (!bindingGraphValidator.shouldDoFullBindingGraphValidation(component)) {
+ if (!bindingGraphValidator.shouldDoFullBindingGraphValidation(
+ componentDescriptor.typeElement())) {
return true;
}
BindingGraph fullBindingGraph = bindingGraphFactory.create(componentDescriptor, true);
@@ -153,7 +148,7 @@ final class ComponentProcessingStep extends TypeCheckingProcessingStep<TypeEleme
}
private boolean isValid(ComponentDescriptor componentDescriptor) {
- ValidationReport<TypeElement> componentDescriptorReport =
+ ValidationReport componentDescriptorReport =
componentDescriptorValidator.validate(componentDescriptor);
componentDescriptorReport.printMessagesTo(messager);
return componentDescriptorReport.isClean();
diff --git a/java/dagger/internal/codegen/ComponentProcessor.java b/java/dagger/internal/codegen/ComponentProcessor.java
index e392252a2..facb04d1f 100644
--- a/java/dagger/internal/codegen/ComponentProcessor.java
+++ b/java/dagger/internal/codegen/ComponentProcessor.java
@@ -18,18 +18,21 @@ package dagger.internal.codegen;
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING;
-import com.google.auto.common.BasicAnnotationProcessor;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XProcessingEnvConfig;
+import androidx.room.compiler.processing.XProcessingStep;
+import androidx.room.compiler.processing.XRoundEnv;
+import androidx.room.compiler.processing.compat.XConverters;
+import androidx.room.compiler.processing.javac.JavacBasicAnnotationProcessor;
import com.google.auto.service.AutoService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
import com.google.errorprone.annotations.CheckReturnValue;
import dagger.BindsInstance;
import dagger.Component;
import dagger.Module;
import dagger.Provides;
-import dagger.internal.codegen.SpiModule.TestingPlugins;
import dagger.internal.codegen.base.ClearableCache;
import dagger.internal.codegen.base.SourceFileGenerationException;
import dagger.internal.codegen.base.SourceFileGenerator;
@@ -40,20 +43,20 @@ import dagger.internal.codegen.bindinggraphvalidation.BindingGraphValidationModu
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions;
import dagger.internal.codegen.componentgenerator.ComponentGeneratorModule;
-import dagger.internal.codegen.validation.BindingGraphPlugins;
import dagger.internal.codegen.validation.BindingMethodProcessingStep;
import dagger.internal.codegen.validation.BindingMethodValidatorsModule;
import dagger.internal.codegen.validation.BindsInstanceProcessingStep;
+import dagger.internal.codegen.validation.ExternalBindingGraphPlugins;
import dagger.internal.codegen.validation.InjectBindingRegistryModule;
import dagger.internal.codegen.validation.MonitoringModuleProcessingStep;
import dagger.internal.codegen.validation.MultibindingAnnotationsProcessingStep;
+import dagger.internal.codegen.validation.ValidationBindingGraphPlugins;
import dagger.spi.BindingGraphPlugin;
import java.util.Arrays;
+import java.util.Map;
import java.util.Optional;
import java.util.Set;
-import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
-import javax.annotation.processing.RoundEnvironment;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.lang.model.SourceVersion;
@@ -67,21 +70,28 @@ import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
*/
@IncrementalAnnotationProcessor(ISOLATING)
@AutoService(Processor.class)
-public class ComponentProcessor extends BasicAnnotationProcessor {
+public class ComponentProcessor extends JavacBasicAnnotationProcessor {
+ private static XProcessingEnvConfig envConfig(Map<String, String> options) {
+ return new XProcessingEnvConfig.Builder().disableAnnotatedElementValidation(true).build();
+ }
+
private final Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins;
@Inject InjectBindingRegistry injectBindingRegistry;
@Inject SourceFileGenerator<ProvisionBinding> factoryGenerator;
@Inject SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator;
- @Inject ImmutableList<ProcessingStep> processingSteps;
- @Inject BindingGraphPlugins bindingGraphPlugins;
+ @Inject ImmutableList<XProcessingStep> processingSteps;
+ @Inject ValidationBindingGraphPlugins validationBindingGraphPlugins;
+ @Inject ExternalBindingGraphPlugins externalBindingGraphPlugins;
@Inject Set<ClearableCache> clearableCaches;
public ComponentProcessor() {
+ super(ComponentProcessor::envConfig);
this.testingPlugins = Optional.empty();
}
private ComponentProcessor(Iterable<BindingGraphPlugin> testingPlugins) {
+ super(ComponentProcessor::envConfig);
this.testingPlugins = Optional.of(ImmutableSet.copyOf(testingPlugins));
}
@@ -104,27 +114,38 @@ public class ComponentProcessor extends BasicAnnotationProcessor {
}
@Override
+ public void initialize(XProcessingEnv env) {
+ ProcessorComponent.factory()
+ .create(env, testingPlugins.orElseGet(this::loadExternalPlugins))
+ .inject(this);
+ }
+
+ @Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
- public Set<String> getSupportedOptions() {
- return Sets.union(
- ProcessingEnvironmentCompilerOptions.supportedOptions(),
- bindingGraphPlugins.allSupportedOptions())
- .immutableCopy();
+ public ImmutableSet<String> getSupportedOptions() {
+ return ImmutableSet.<String>builder()
+ .addAll(ProcessingEnvironmentCompilerOptions.supportedOptions())
+ .addAll(validationBindingGraphPlugins.allSupportedOptions())
+ .addAll(externalBindingGraphPlugins.allSupportedOptions())
+ .build();
}
@Override
- protected Iterable<? extends ProcessingStep> initSteps() {
- ProcessorComponent.factory().create(processingEnv, testingPlugins).inject(this);
-
- bindingGraphPlugins.initializePlugins();
+ public Iterable<XProcessingStep> processingSteps() {
+ validationBindingGraphPlugins.initializePlugins();
+ externalBindingGraphPlugins.initializePlugins();
return processingSteps;
}
+ private ImmutableSet<BindingGraphPlugin> loadExternalPlugins() {
+ return ServiceLoaders.load(processingEnv, BindingGraphPlugin.class);
+ }
+
@Singleton
@Component(
modules = {
@@ -136,7 +157,6 @@ public class ComponentProcessor extends BasicAnnotationProcessor {
ProcessingRoundCacheModule.class,
ProcessingStepsModule.class,
SourceFileGeneratorsModule.class,
- SpiModule.class
})
interface ProcessorComponent {
void inject(ComponentProcessor processor);
@@ -149,15 +169,15 @@ public class ComponentProcessor extends BasicAnnotationProcessor {
interface Factory {
@CheckReturnValue
ProcessorComponent create(
- @BindsInstance ProcessingEnvironment processingEnv,
- @BindsInstance @TestingPlugins Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins);
+ @BindsInstance XProcessingEnv xProcessingEnv,
+ @BindsInstance ImmutableSet<BindingGraphPlugin> externalPlugins);
}
}
@Module
interface ProcessingStepsModule {
@Provides
- static ImmutableList<ProcessingStep> processingSteps(
+ static ImmutableList<XProcessingStep> processingSteps(
MapKeyProcessingStep mapKeyProcessingStep,
InjectProcessingStep injectProcessingStep,
AssistedInjectProcessingStep assistedInjectProcessingStep,
@@ -189,13 +209,14 @@ public class ComponentProcessor extends BasicAnnotationProcessor {
}
@Override
- protected void postRound(RoundEnvironment roundEnv) {
- if (!roundEnv.processingOver()) {
+ public void postRound(XProcessingEnv env, XRoundEnv roundEnv) {
+ // TODO(bcorso): Add a way to determine if processing is over without converting to Javac here.
+ if (!XConverters.toJavac(roundEnv).processingOver()) {
try {
injectBindingRegistry.generateSourcesForRequiredBindings(
factoryGenerator, membersInjectorGenerator);
} catch (SourceFileGenerationException e) {
- e.printMessageTo(processingEnv.getMessager());
+ e.printMessageTo(env.getMessager());
}
}
clearableCaches.forEach(ClearableCache::clearCache);
diff --git a/java/dagger/internal/codegen/InjectProcessingStep.java b/java/dagger/internal/codegen/InjectProcessingStep.java
index 537459235..a201afec0 100644
--- a/java/dagger/internal/codegen/InjectProcessingStep.java
+++ b/java/dagger/internal/codegen/InjectProcessingStep.java
@@ -16,73 +16,59 @@
package dagger.internal.codegen;
-import com.google.auto.common.MoreElements;
+import static androidx.room.compiler.processing.XElementKt.isConstructor;
+import static androidx.room.compiler.processing.XElementKt.isField;
+import static androidx.room.compiler.processing.XElementKt.isMethod;
+import static dagger.internal.codegen.xprocessing.XElements.asConstructor;
+import static dagger.internal.codegen.xprocessing.XElements.asField;
+import static dagger.internal.codegen.xprocessing.XElements.asMethod;
+
+import androidx.room.compiler.processing.XElement;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
-import dagger.assisted.AssistedInject;
+import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.binding.InjectBindingRegistry;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
-import java.lang.annotation.Annotation;
import java.util.Set;
import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementVisitor;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.util.ElementKindVisitor8;
/**
* An annotation processor for generating Dagger implementation code based on the {@link Inject}
* annotation.
*/
// TODO(gak): add some error handling for bad source files
-final class InjectProcessingStep extends TypeCheckingProcessingStep<Element> {
- private final ElementVisitor<Void, Void> visitor;
- private final Set<Element> processedElements = Sets.newLinkedHashSet();
+// TODO(bcorso): Add support in TypeCheckingProcessingStep to perform custom validation and use
+// SuperficialInjectValidator rather than SuperficialValidator.
+final class InjectProcessingStep extends TypeCheckingProcessingStep<XElement> {
+ private final InjectBindingRegistry injectBindingRegistry;
+ private final Set<XElement> processedElements = Sets.newHashSet();
@Inject
InjectProcessingStep(InjectBindingRegistry injectBindingRegistry) {
- super(e -> e);
- this.visitor =
- new ElementKindVisitor8<Void, Void>() {
- @Override
- public Void visitExecutableAsConstructor(
- ExecutableElement constructorElement, Void aVoid) {
- injectBindingRegistry.tryRegisterConstructor(constructorElement);
- return null;
- }
-
- @Override
- public Void visitVariableAsField(VariableElement fieldElement, Void aVoid) {
- injectBindingRegistry.tryRegisterMembersInjectedType(
- MoreElements.asType(fieldElement.getEnclosingElement()));
- return null;
- }
-
- @Override
- public Void visitExecutableAsMethod(ExecutableElement methodElement, Void aVoid) {
- injectBindingRegistry.tryRegisterMembersInjectedType(
- MoreElements.asType(methodElement.getEnclosingElement()));
- return null;
- }
- };
+ this.injectBindingRegistry = injectBindingRegistry;
}
@Override
- public Set<Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(Inject.class, AssistedInject.class);
+ public ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(TypeNames.INJECT, TypeNames.INJECT_JAVAX, TypeNames.ASSISTED_INJECT);
}
@Override
- protected void process(
- Element injectElement, ImmutableSet<Class<? extends Annotation>> annotations) {
+ protected void process(XElement injectElement, ImmutableSet<ClassName> annotations) {
// Only process an element once to avoid getting duplicate errors when an element is annotated
// with multiple inject annotations.
if (processedElements.contains(injectElement)) {
return;
}
- injectElement.accept(visitor, null);
+ if (isConstructor(injectElement)) {
+ injectBindingRegistry.tryRegisterInjectConstructor(asConstructor(injectElement));
+ } else if (isField(injectElement)) {
+ injectBindingRegistry.tryRegisterInjectField(asField(injectElement));
+ } else if (isMethod(injectElement)) {
+ injectBindingRegistry.tryRegisterInjectMethod(asMethod(injectElement));
+ }
processedElements.add(injectElement);
}
diff --git a/java/dagger/internal/codegen/MapKeyProcessingStep.java b/java/dagger/internal/codegen/MapKeyProcessingStep.java
index 50693da14..4d1f3b822 100644
--- a/java/dagger/internal/codegen/MapKeyProcessingStep.java
+++ b/java/dagger/internal/codegen/MapKeyProcessingStep.java
@@ -17,77 +17,64 @@
package dagger.internal.codegen;
import static dagger.internal.codegen.binding.MapKeys.getUnwrappedMapKeyType;
-import static javax.lang.model.element.ElementKind.ANNOTATION_TYPE;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
import dagger.MapKey;
-import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.validation.MapKeyValidator;
import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
import dagger.internal.codegen.validation.ValidationReport;
import dagger.internal.codegen.writing.AnnotationCreatorGenerator;
import dagger.internal.codegen.writing.UnwrappedMapKeyGenerator;
-import java.lang.annotation.Annotation;
-import java.util.Set;
-import javax.annotation.processing.Messager;
import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
/**
* The annotation processor responsible for validating the mapKey annotation and auto-generate
* implementation of annotations marked with {@link MapKey @MapKey} where necessary.
*/
-final class MapKeyProcessingStep extends TypeCheckingProcessingStep<TypeElement> {
- private final Messager messager;
- private final DaggerTypes types;
+final class MapKeyProcessingStep extends TypeCheckingProcessingStep<XTypeElement> {
+ private final XMessager messager;
private final MapKeyValidator mapKeyValidator;
private final AnnotationCreatorGenerator annotationCreatorGenerator;
private final UnwrappedMapKeyGenerator unwrappedMapKeyGenerator;
@Inject
MapKeyProcessingStep(
- Messager messager,
- DaggerTypes types,
+ XMessager messager,
MapKeyValidator mapKeyValidator,
AnnotationCreatorGenerator annotationCreatorGenerator,
UnwrappedMapKeyGenerator unwrappedMapKeyGenerator) {
- super(MoreElements::asType);
this.messager = messager;
- this.types = types;
this.mapKeyValidator = mapKeyValidator;
this.annotationCreatorGenerator = annotationCreatorGenerator;
this.unwrappedMapKeyGenerator = unwrappedMapKeyGenerator;
}
@Override
- public Set<Class<? extends Annotation>> annotations() {
- return ImmutableSet.<Class<? extends Annotation>>of(MapKey.class);
+ public ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(TypeNames.MAP_KEY);
}
@Override
- protected void process(
- TypeElement mapKeyAnnotationType, ImmutableSet<Class<? extends Annotation>> annotations) {
- ValidationReport<Element> mapKeyReport = mapKeyValidator.validate(mapKeyAnnotationType);
+ protected void process(XTypeElement mapAnnotation, ImmutableSet<ClassName> annotations) {
+ ValidationReport mapKeyReport = mapKeyValidator.validate(mapAnnotation);
mapKeyReport.printMessagesTo(messager);
if (mapKeyReport.isClean()) {
- MapKey mapkey = mapKeyAnnotationType.getAnnotation(MapKey.class);
- if (!mapkey.unwrapValue()) {
- annotationCreatorGenerator.generate(mapKeyAnnotationType, messager);
- } else if (unwrappedValueKind(mapKeyAnnotationType).equals(ANNOTATION_TYPE)) {
- unwrappedMapKeyGenerator.generate(mapKeyAnnotationType, messager);
+ if (!mapAnnotation.getAnnotation(TypeNames.MAP_KEY).getAsBoolean("unwrapValue")) {
+ annotationCreatorGenerator.generate(mapAnnotation, messager);
+ } else if (isAnnotationType(getUnwrappedMapKeyType(mapAnnotation.getType()))) {
+ unwrappedMapKeyGenerator.generate(mapAnnotation, messager);
}
}
}
- private ElementKind unwrappedValueKind(TypeElement mapKeyAnnotationType) {
- DeclaredType unwrappedMapKeyType =
- getUnwrappedMapKeyType(MoreTypes.asDeclared(mapKeyAnnotationType.asType()), types);
- return unwrappedMapKeyType.asElement().getKind();
+ private boolean isAnnotationType(XType type) {
+ return isDeclared(type) && type.getTypeElement().isAnnotationClass();
}
}
diff --git a/java/dagger/internal/codegen/ModuleProcessingStep.java b/java/dagger/internal/codegen/ModuleProcessingStep.java
index 2bf33545c..811d35a10 100644
--- a/java/dagger/internal/codegen/ModuleProcessingStep.java
+++ b/java/dagger/internal/codegen/ModuleProcessingStep.java
@@ -16,70 +16,59 @@
package dagger.internal.codegen;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-import static javax.lang.model.util.ElementFilter.typesIn;
+import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
-import com.google.auto.common.MoreElements;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
+import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.base.SourceFileGenerator;
import dagger.internal.codegen.binding.BindingFactory;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.binding.DelegateDeclaration;
-import dagger.internal.codegen.binding.DelegateDeclaration.Factory;
import dagger.internal.codegen.binding.ProductionBinding;
import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.validation.ModuleValidator;
import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
import dagger.internal.codegen.validation.ValidationReport;
import dagger.internal.codegen.writing.InaccessibleMapKeyProxyGenerator;
import dagger.internal.codegen.writing.ModuleGenerator;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import java.lang.annotation.Annotation;
-import java.util.List;
+import java.util.Map;
import java.util.Set;
-import javax.annotation.processing.Messager;
import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
/**
* A {@link ProcessingStep} that validates module classes and generates factories for binding
* methods.
*/
-final class ModuleProcessingStep extends TypeCheckingProcessingStep<TypeElement> {
- private final Messager messager;
+final class ModuleProcessingStep extends TypeCheckingProcessingStep<XTypeElement> {
+ private final XMessager messager;
private final ModuleValidator moduleValidator;
private final BindingFactory bindingFactory;
private final SourceFileGenerator<ProvisionBinding> factoryGenerator;
private final SourceFileGenerator<ProductionBinding> producerFactoryGenerator;
- private final SourceFileGenerator<TypeElement> moduleConstructorProxyGenerator;
+ private final SourceFileGenerator<XTypeElement> moduleConstructorProxyGenerator;
private final InaccessibleMapKeyProxyGenerator inaccessibleMapKeyProxyGenerator;
private final DelegateDeclaration.Factory delegateDeclarationFactory;
- private final KotlinMetadataUtil metadataUtil;
- private final Set<TypeElement> processedModuleElements = Sets.newLinkedHashSet();
+ private final Set<XTypeElement> processedModuleElements = Sets.newLinkedHashSet();
@Inject
ModuleProcessingStep(
- Messager messager,
+ XMessager messager,
ModuleValidator moduleValidator,
BindingFactory bindingFactory,
SourceFileGenerator<ProvisionBinding> factoryGenerator,
SourceFileGenerator<ProductionBinding> producerFactoryGenerator,
- @ModuleGenerator SourceFileGenerator<TypeElement> moduleConstructorProxyGenerator,
+ @ModuleGenerator SourceFileGenerator<XTypeElement> moduleConstructorProxyGenerator,
InaccessibleMapKeyProxyGenerator inaccessibleMapKeyProxyGenerator,
- Factory delegateDeclarationFactory,
- KotlinMetadataUtil metadataUtil) {
- super(MoreElements::asType);
+ DelegateDeclaration.Factory delegateDeclarationFactory) {
this.messager = messager;
this.moduleValidator = moduleValidator;
this.bindingFactory = bindingFactory;
@@ -88,54 +77,57 @@ final class ModuleProcessingStep extends TypeCheckingProcessingStep<TypeElement>
this.moduleConstructorProxyGenerator = moduleConstructorProxyGenerator;
this.inaccessibleMapKeyProxyGenerator = inaccessibleMapKeyProxyGenerator;
this.delegateDeclarationFactory = delegateDeclarationFactory;
- this.metadataUtil = metadataUtil;
}
@Override
- public Set<? extends Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(Module.class, ProducerModule.class);
+ public ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(TypeNames.MODULE, TypeNames.PRODUCER_MODULE);
}
@Override
- public ImmutableSet<Element> process(
- SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
- List<TypeElement> modules = typesIn(elementsByAnnotation.values());
- moduleValidator.addKnownModules(modules);
- return super.process(elementsByAnnotation);
+ public ImmutableSet<XElement> process(
+ XProcessingEnv env, Map<String, ? extends Set<? extends XElement>> elementsByAnnotation) {
+ moduleValidator.addKnownModules(
+ elementsByAnnotation.values().stream()
+ .flatMap(Set::stream)
+ // This cast is safe because @Module has @Target(ElementType.TYPE)
+ .map(XTypeElement.class::cast)
+ .collect(toImmutableSet()));
+ return super.process(env, elementsByAnnotation);
}
@Override
- protected void process(
- TypeElement module, ImmutableSet<Class<? extends Annotation>> annotations) {
+ protected void process(XTypeElement module, ImmutableSet<ClassName> annotations) {
if (processedModuleElements.contains(module)) {
return;
}
// For backwards compatibility, we allow a companion object to be annotated with @Module even
// though it's no longer required. However, we skip processing the companion object itself
// because it will now be processed when processing the companion object's enclosing class.
- if (metadataUtil.isCompanionObjectClass(module)) {
+ if (module.isCompanionObject()) {
// TODO(danysantiago): Be strict about annotating companion objects with @Module,
// i.e. tell user to annotate parent instead.
return;
}
- ValidationReport<TypeElement> report = moduleValidator.validate(module);
+ ValidationReport report = moduleValidator.validate(module);
report.printMessagesTo(messager);
if (report.isClean()) {
generateForMethodsIn(module);
- if (metadataUtil.hasEnclosedCompanionObject(module)) {
- generateForMethodsIn(metadataUtil.getEnclosedCompanionObject(module));
- }
+ module.getEnclosedTypeElements().stream()
+ .filter(XTypeElement::isCompanionObject)
+ .collect(toOptional())
+ .ifPresent(this::generateForMethodsIn);
}
processedModuleElements.add(module);
}
- private void generateForMethodsIn(TypeElement module) {
- for (ExecutableElement method : methodsIn(module.getEnclosedElements())) {
- if (isAnnotationPresent(method, Provides.class)) {
+ private void generateForMethodsIn(XTypeElement module) {
+ for (XMethodElement method : module.getDeclaredMethods()) {
+ if (method.hasAnnotation(TypeNames.PROVIDES)) {
generate(factoryGenerator, bindingFactory.providesMethodBinding(method, module));
- } else if (isAnnotationPresent(method, Produces.class)) {
+ } else if (method.hasAnnotation(TypeNames.PRODUCES)) {
generate(producerFactoryGenerator, bindingFactory.producesMethodBinding(method, module));
- } else if (isAnnotationPresent(method, Binds.class)) {
+ } else if (method.hasAnnotation(TypeNames.BINDS)) {
inaccessibleMapKeyProxyGenerator.generate(bindsMethodBinding(module, method), messager);
}
}
@@ -148,7 +140,7 @@ final class ModuleProcessingStep extends TypeCheckingProcessingStep<TypeElement>
inaccessibleMapKeyProxyGenerator.generate(binding, messager);
}
- private ContributionBinding bindsMethodBinding(TypeElement module, ExecutableElement method) {
+ private ContributionBinding bindsMethodBinding(XTypeElement module, XMethodElement method) {
return bindingFactory.unresolvedDelegateBinding(
delegateDeclarationFactory.create(method, module));
}
diff --git a/java/dagger/internal/codegen/ProcessingEnvironmentModule.java b/java/dagger/internal/codegen/ProcessingEnvironmentModule.java
index 120714b33..1561c7c88 100644
--- a/java/dagger/internal/codegen/ProcessingEnvironmentModule.java
+++ b/java/dagger/internal/codegen/ProcessingEnvironmentModule.java
@@ -16,28 +16,27 @@
package dagger.internal.codegen;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.compat.XConverters;
import com.google.googlejavaformat.java.filer.FormattingFiler;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.Reusable;
-import dagger.internal.codegen.SpiModule.ProcessorClassLoader;
import dagger.internal.codegen.base.ClearableCache;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions;
import dagger.internal.codegen.compileroption.ProcessingOptions;
import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
import dagger.multibindings.IntoSet;
-import dagger.spi.BindingGraphPlugin;
import java.util.Map;
-import javax.annotation.processing.Filer;
-import javax.annotation.processing.Messager;
-import javax.annotation.processing.ProcessingEnvironment;
import javax.inject.Singleton;
import javax.lang.model.SourceVersion;
-import javax.lang.model.util.Types;
-/** Bindings that depend on the {@link ProcessingEnvironment}. */
+/** Bindings that depend on the {@link XProcessingEnv}. */
@Module
interface ProcessingEnvironmentModule {
@Binds
@@ -47,47 +46,43 @@ interface ProcessingEnvironmentModule {
@Provides
@ProcessingOptions
- static Map<String, String> processingOptions(ProcessingEnvironment processingEnvironment) {
- return processingEnvironment.getOptions();
+ static Map<String, String> processingOptions(XProcessingEnv xProcessingEnv) {
+ return xProcessingEnv.getOptions();
}
@Provides
- static Messager messager(ProcessingEnvironment processingEnvironment) {
- return processingEnvironment.getMessager();
+ static XMessager messager(XProcessingEnv xProcessingEnv) {
+ return xProcessingEnv.getMessager();
}
@Provides
- static Filer filer(CompilerOptions compilerOptions, ProcessingEnvironment processingEnvironment) {
- if (compilerOptions.headerCompilation() || !compilerOptions.formatGeneratedSource()) {
- return processingEnvironment.getFiler();
- } else {
- return new FormattingFiler(processingEnvironment.getFiler());
- }
+ static XFiler filer(CompilerOptions compilerOptions, XProcessingEnv xProcessingEnv) {
+ return compilerOptions.headerCompilation() || !compilerOptions.formatGeneratedSource()
+ ? xProcessingEnv.getFiler()
+ : XConverters.toXProcessing(
+ new FormattingFiler(XConverters.toJavac(xProcessingEnv.getFiler())), xProcessingEnv);
}
@Provides
- static Types types(ProcessingEnvironment processingEnvironment) {
- return processingEnvironment.getTypeUtils();
+ static SourceVersion sourceVersion(XProcessingEnv xProcessingEnv) {
+ return XConverters.toJavac(xProcessingEnv).getSourceVersion();
}
@Provides
- static SourceVersion sourceVersion(ProcessingEnvironment processingEnvironment) {
- return processingEnvironment.getSourceVersion();
+ @Singleton
+ static DaggerElements daggerElements(XProcessingEnv xProcessingEnv) {
+ return new DaggerElements(
+ XConverters.toJavac(xProcessingEnv).getElementUtils(),
+ XConverters.toJavac(xProcessingEnv).getTypeUtils());
}
@Provides
@Singleton
- static DaggerElements daggerElements(ProcessingEnvironment processingEnvironment) {
- return new DaggerElements(processingEnvironment);
+ static DaggerTypes daggerTypes(XProcessingEnv xProcessingEnv, DaggerElements elements) {
+ return new DaggerTypes(XConverters.toJavac(xProcessingEnv).getTypeUtils(), elements);
}
@Binds
@IntoSet
ClearableCache daggerElementAsClearableCache(DaggerElements elements);
-
- @Provides
- @ProcessorClassLoader
- static ClassLoader processorClassloader(ProcessingEnvironment processingEnvironment) {
- return BindingGraphPlugin.class.getClassLoader();
- }
}
diff --git a/java/dagger/internal/codegen/ProcessingRoundCacheModule.java b/java/dagger/internal/codegen/ProcessingRoundCacheModule.java
index 2373cd291..0d9b02a3b 100644
--- a/java/dagger/internal/codegen/ProcessingRoundCacheModule.java
+++ b/java/dagger/internal/codegen/ProcessingRoundCacheModule.java
@@ -26,6 +26,7 @@ import dagger.internal.codegen.validation.AnyBindingMethodValidator;
import dagger.internal.codegen.validation.ComponentCreatorValidator;
import dagger.internal.codegen.validation.ComponentValidator;
import dagger.internal.codegen.validation.InjectValidator;
+import dagger.internal.codegen.validation.SuperficialValidator;
import dagger.multibindings.IntoSet;
/**
@@ -61,4 +62,8 @@ interface ProcessingRoundCacheModule {
@Binds
@IntoSet
ClearableCache kotlinMetadata(KotlinMetadataFactory cache);
+
+ @Binds
+ @IntoSet
+ ClearableCache superficialValidator(SuperficialValidator cache);
}
diff --git a/java/dagger/internal/codegen/ServiceLoaders.java b/java/dagger/internal/codegen/ServiceLoaders.java
new file mode 100644
index 000000000..0f9b3555e
--- /dev/null
+++ b/java/dagger/internal/codegen/ServiceLoaders.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.ServiceLoader;
+import javax.annotation.processing.ProcessingEnvironment;
+
+/** A class that loads services for the {@link ComponentProcessor}. */
+final class ServiceLoaders {
+
+ private ServiceLoaders() {}
+
+ static <T> ImmutableSet<T> load(ProcessingEnvironment processingEnvironment, Class<T> clazz) {
+ return ImmutableSet.copyOf(
+ ServiceLoader.load(clazz, classloaderFor(processingEnvironment, clazz)));
+ }
+
+ private static ClassLoader classloaderFor(
+ ProcessingEnvironment processingEnvironment, Class<?> clazz) {
+ return clazz.getClassLoader();
+ }
+}
diff --git a/java/dagger/internal/codegen/SourceFileGeneratorsModule.java b/java/dagger/internal/codegen/SourceFileGeneratorsModule.java
index 426afae37..1ba7351bb 100644
--- a/java/dagger/internal/codegen/SourceFileGeneratorsModule.java
+++ b/java/dagger/internal/codegen/SourceFileGeneratorsModule.java
@@ -16,6 +16,7 @@
package dagger.internal.codegen;
+import androidx.room.compiler.processing.XTypeElement;
import dagger.Module;
import dagger.Provides;
import dagger.internal.codegen.base.SourceFileGenerator;
@@ -29,7 +30,6 @@ import dagger.internal.codegen.writing.MembersInjectorGenerator;
import dagger.internal.codegen.writing.ModuleGenerator;
import dagger.internal.codegen.writing.ModuleProxies.ModuleConstructorProxyGenerator;
import dagger.internal.codegen.writing.ProducerFactoryGenerator;
-import javax.lang.model.element.TypeElement;
@Module
abstract class SourceFileGeneratorsModule {
@@ -54,7 +54,7 @@ abstract class SourceFileGeneratorsModule {
@Provides
@ModuleGenerator
- static SourceFileGenerator<TypeElement> moduleConstructorProxyGenerator(
+ static SourceFileGenerator<XTypeElement> moduleConstructorProxyGenerator(
ModuleConstructorProxyGenerator generator, CompilerOptions compilerOptions) {
return hjarWrapper(generator, compilerOptions);
}
diff --git a/java/dagger/internal/codegen/SpiModule.java b/java/dagger/internal/codegen/SpiModule.java
deleted file mode 100644
index a4f537bff..000000000
--- a/java/dagger/internal/codegen/SpiModule.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2018 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.google.common.collect.ImmutableSet;
-import dagger.Module;
-import dagger.Provides;
-import dagger.internal.codegen.validation.BindingGraphValidator;
-import dagger.spi.BindingGraphPlugin;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-import java.util.Optional;
-import java.util.ServiceLoader;
-import javax.inject.Qualifier;
-import javax.inject.Singleton;
-
-/** Contains the bindings for {@link BindingGraphValidator} from external SPI providers. */
-@Module
-abstract class SpiModule {
- private SpiModule() {}
-
- @Provides
- @Singleton
- static ImmutableSet<BindingGraphPlugin> externalPlugins(
- @TestingPlugins Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins,
- @ProcessorClassLoader ClassLoader processorClassLoader) {
- return testingPlugins.orElseGet(
- () ->
- ImmutableSet.copyOf(
- ServiceLoader.load(BindingGraphPlugin.class, processorClassLoader)));
- }
-
- @Qualifier
- @Retention(RUNTIME)
- @Target({FIELD, PARAMETER, METHOD})
- @interface TestingPlugins {}
-
- @Qualifier
- @Retention(RUNTIME)
- @Target({PARAMETER, METHOD})
- @interface ProcessorClassLoader {}
-}
diff --git a/java/dagger/internal/codegen/base/BUILD b/java/dagger/internal/codegen/base/BUILD
index 0bcbb128e..69e84d037 100644
--- a/java/dagger/internal/codegen/base/BUILD
+++ b/java/dagger/internal/codegen/base/BUILD
@@ -35,20 +35,20 @@ java_library(
tags = ["maven:merged"],
exports = [":shared"],
deps = [
- ":shared",
"//java/dagger:core",
+ "//java/dagger/internal/codegen/compileroption",
"//java/dagger/internal/codegen/extension",
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "//java/dagger/producers",
+ "//java/dagger/internal/codegen/xprocessing",
"//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/graph",
+ "//third_party/java/javapoet",
+ "//third_party/java/jsr330_inject",
],
)
@@ -59,8 +59,8 @@ java_library(
tags = ["maven:merged"],
deps = [
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
],
)
diff --git a/java/dagger/internal/codegen/base/ComponentAnnotation.java b/java/dagger/internal/codegen/base/ComponentAnnotation.java
index b70ef54bb..e0871eb7f 100644
--- a/java/dagger/internal/codegen/base/ComponentAnnotation.java
+++ b/java/dagger/internal/codegen/base/ComponentAnnotation.java
@@ -16,31 +16,22 @@
package dagger.internal.codegen.base;
-import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreTypes.asTypeElements;
-import static com.google.auto.common.MoreTypes.isTypeOf;
-import static dagger.internal.codegen.base.MoreAnnotationValues.asAnnotationValues;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER_MODULE;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnyAnnotation;
-
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.xprocessing.XAnnotations.getClassName;
+import static dagger.internal.codegen.xprocessing.XElements.getAnyAnnotation;
+
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
-import dagger.Component;
-import dagger.Subcomponent;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-import java.lang.annotation.Annotation;
+import dagger.internal.codegen.javapoet.TypeNames;
import java.util.Collection;
import java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
/**
* A {@code @Component}, {@code @Subcomponent}, {@code @ProductionComponent}, or
@@ -48,74 +39,82 @@ import javax.lang.model.type.TypeMirror;
* annotation that is being treated as a component annotation when validating full binding graphs
* for modules.
*/
+@AutoValue
public abstract class ComponentAnnotation {
/** The root component annotation types. */
- private static final ImmutableSet<Class<? extends Annotation>> ROOT_COMPONENT_ANNOTATIONS =
- ImmutableSet.of(Component.class, ProductionComponent.class);
+ private static final ImmutableSet<ClassName> ROOT_COMPONENT_ANNOTATIONS =
+ ImmutableSet.of(TypeNames.COMPONENT, TypeNames.PRODUCTION_COMPONENT);
/** The subcomponent annotation types. */
- private static final ImmutableSet<Class<? extends Annotation>> SUBCOMPONENT_ANNOTATIONS =
- ImmutableSet.of(Subcomponent.class, ProductionSubcomponent.class);
-
- // TODO(erichang): Move ComponentCreatorAnnotation into /base and use that here?
- /** The component/subcomponent creator annotation types. */
- private static final ImmutableSet<Class<? extends Annotation>> CREATOR_ANNOTATIONS =
- ImmutableSet.of(
- Component.Builder.class,
- Component.Factory.class,
- ProductionComponent.Builder.class,
- ProductionComponent.Factory.class,
- Subcomponent.Builder.class,
- Subcomponent.Factory.class,
- ProductionSubcomponent.Builder.class,
- ProductionSubcomponent.Factory.class);
+ private static final ImmutableSet<ClassName> SUBCOMPONENT_ANNOTATIONS =
+ ImmutableSet.of(TypeNames.SUBCOMPONENT, TypeNames.PRODUCTION_SUBCOMPONENT);
/** All component annotation types. */
- private static final ImmutableSet<Class<? extends Annotation>> ALL_COMPONENT_ANNOTATIONS =
- ImmutableSet.<Class<? extends Annotation>>builder()
- .addAll(ROOT_COMPONENT_ANNOTATIONS)
- .addAll(SUBCOMPONENT_ANNOTATIONS)
- .build();
+ private static final ImmutableSet<ClassName> ALL_COMPONENT_ANNOTATIONS =
+ ImmutableSet.<ClassName>builder()
+ .addAll(ROOT_COMPONENT_ANNOTATIONS)
+ .addAll(SUBCOMPONENT_ANNOTATIONS)
+ .build();
/** All component and creator annotation types. */
- private static final ImmutableSet<Class<? extends Annotation>>
- ALL_COMPONENT_AND_CREATOR_ANNOTATIONS = ImmutableSet.<Class<? extends Annotation>>builder()
- .addAll(ALL_COMPONENT_ANNOTATIONS)
- .addAll(CREATOR_ANNOTATIONS)
- .build();
+ private static final ImmutableSet<ClassName> ALL_COMPONENT_AND_CREATOR_ANNOTATIONS =
+ ImmutableSet.<ClassName>builder()
+ .addAll(ALL_COMPONENT_ANNOTATIONS)
+ .addAll(ComponentCreatorAnnotation.allCreatorAnnotations())
+ .build();
+
+ /** All production annotation types. */
+ private static final ImmutableSet<ClassName> PRODUCTION_ANNOTATIONS =
+ ImmutableSet.of(
+ TypeNames.PRODUCTION_COMPONENT,
+ TypeNames.PRODUCTION_SUBCOMPONENT,
+ TypeNames.PRODUCER_MODULE);
+
+ private XAnnotation annotation;
/** The annotation itself. */
- public abstract AnnotationMirror annotation();
+ public final XAnnotation annotation() {
+ return annotation;
+ }
+
+ /** Returns the {@link ClassName} name of the annotation. */
+ public abstract ClassName className();
/** The simple name of the annotation type. */
- public String simpleName() {
- return MoreAnnotationMirrors.simpleName(annotation()).toString();
+ public final String simpleName() {
+ return className().simpleName();
}
/**
* Returns {@code true} if the annotation is a {@code @Subcomponent} or
* {@code @ProductionSubcomponent}.
*/
- public abstract boolean isSubcomponent();
+ public final boolean isSubcomponent() {
+ return SUBCOMPONENT_ANNOTATIONS.contains(className());
+ }
/**
* Returns {@code true} if the annotation is a {@code @ProductionComponent},
* {@code @ProductionSubcomponent}, or {@code @ProducerModule}.
*/
- public abstract boolean isProduction();
+ public final boolean isProduction() {
+ return PRODUCTION_ANNOTATIONS.contains(className());
+ }
/**
* Returns {@code true} if the annotation is a real component annotation and not a module
* annotation.
*/
- public abstract boolean isRealComponent();
-
- /** The values listed as {@code dependencies}. */
- public abstract ImmutableList<AnnotationValue> dependencyValues();
+ public final boolean isRealComponent() {
+ return ALL_COMPONENT_ANNOTATIONS.contains(className());
+ }
/** The types listed as {@code dependencies}. */
- public ImmutableList<TypeMirror> dependencyTypes() {
- return dependencyValues().stream().map(MoreAnnotationValues::asType).collect(toImmutableList());
+ @Memoized
+ public ImmutableList<XType> dependencyTypes() {
+ return isRootComponent()
+ ? ImmutableList.copyOf(annotation.getAsTypeList("dependencies"))
+ : ImmutableList.of();
}
/**
@@ -123,229 +122,100 @@ public abstract class ComponentAnnotation {
*
* @throws IllegalArgumentException if any of {@link #dependencyTypes()} are error types
*/
- public ImmutableList<TypeElement> dependencies() {
- return asTypeElements(dependencyTypes()).asList();
- }
-
- /** The values listed as {@code modules}. */
- public abstract ImmutableList<AnnotationValue> moduleValues();
-
- /** The types listed as {@code modules}. */
- public ImmutableList<TypeMirror> moduleTypes() {
- return moduleValues().stream().map(MoreAnnotationValues::asType).collect(toImmutableList());
+ @Memoized
+ public ImmutableSet<XTypeElement> dependencies() {
+ return dependencyTypes().stream().map(XType::getTypeElement).collect(toImmutableSet());
}
/**
* The types listed as {@code modules}.
*
- * @throws IllegalArgumentException if any of {@link #moduleTypes()} are error types
+ * @throws IllegalArgumentException if any module is an error type.
*/
- public ImmutableSet<TypeElement> modules() {
- return asTypeElements(moduleTypes());
+ @Memoized
+ public ImmutableSet<XTypeElement> modules() {
+ return annotation.getAsTypeList(isRealComponent() ? "modules" : "includes").stream()
+ .map(XType::getTypeElement)
+ .collect(toImmutableSet());
}
- protected final ImmutableList<AnnotationValue> getAnnotationValues(String parameterName) {
- return asAnnotationValues(getAnnotationValue(annotation(), parameterName));
+ private final boolean isRootComponent() {
+ return ROOT_COMPONENT_ANNOTATIONS.contains(className());
}
/**
* Returns an object representing a root component annotation, not a subcomponent annotation, if
* one is present on {@code typeElement}.
*/
- public static Optional<ComponentAnnotation> rootComponentAnnotation(TypeElement typeElement) {
- return anyComponentAnnotation(typeElement, ROOT_COMPONENT_ANNOTATIONS);
+ public static Optional<ComponentAnnotation> rootComponentAnnotation(
+ XTypeElement typeElement, DaggerSuperficialValidation superficialValidation) {
+ return anyComponentAnnotation(typeElement, ROOT_COMPONENT_ANNOTATIONS, superficialValidation);
}
/**
* Returns an object representing a subcomponent annotation, if one is present on {@code
* typeElement}.
*/
- public static Optional<ComponentAnnotation> subcomponentAnnotation(TypeElement typeElement) {
- return anyComponentAnnotation(typeElement, SUBCOMPONENT_ANNOTATIONS);
+ public static Optional<ComponentAnnotation> subcomponentAnnotation(
+ XTypeElement typeElement, DaggerSuperficialValidation superficialValidation) {
+ return anyComponentAnnotation(typeElement, SUBCOMPONENT_ANNOTATIONS, superficialValidation);
}
/**
* Returns an object representing a root component or subcomponent annotation, if one is present
* on {@code typeElement}.
*/
- public static Optional<ComponentAnnotation> anyComponentAnnotation(TypeElement typeElement) {
- return anyComponentAnnotation(typeElement, ALL_COMPONENT_ANNOTATIONS);
+ public static Optional<ComponentAnnotation> anyComponentAnnotation(
+ XElement element, DaggerSuperficialValidation superficialValidation) {
+ return anyComponentAnnotation(element, ALL_COMPONENT_ANNOTATIONS, superficialValidation);
}
private static Optional<ComponentAnnotation> anyComponentAnnotation(
- TypeElement typeElement, Collection<Class<? extends Annotation>> annotations) {
- return getAnyAnnotation(typeElement, annotations).map(ComponentAnnotation::componentAnnotation);
+ XElement element,
+ Collection<ClassName> annotations,
+ DaggerSuperficialValidation superficialValidation) {
+ return getAnyAnnotation(element, annotations)
+ .map(
+ annotation -> {
+ superficialValidation.validateAnnotationOf(element, annotation);
+ return create(annotation);
+ });
}
/** Returns {@code true} if the argument is a component annotation. */
- public static boolean isComponentAnnotation(AnnotationMirror annotation) {
- return ALL_COMPONENT_ANNOTATIONS.stream()
- .anyMatch(annotationClass -> isTypeOf(annotationClass, annotation.getAnnotationType()));
- }
-
- /** Creates an object representing a component or subcomponent annotation. */
- public static ComponentAnnotation componentAnnotation(AnnotationMirror annotation) {
- RealComponentAnnotation.Builder annotationBuilder =
- RealComponentAnnotation.builder().annotation(annotation);
-
- if (isTypeOf(Component.class, annotation.getAnnotationType())) {
- return annotationBuilder.isProduction(false).isSubcomponent(false).build();
- }
- if (isTypeOf(Subcomponent.class, annotation.getAnnotationType())) {
- return annotationBuilder.isProduction(false).isSubcomponent(true).build();
- }
- if (isTypeOf(ProductionComponent.class, annotation.getAnnotationType())) {
- return annotationBuilder.isProduction(true).isSubcomponent(false).build();
- }
- if (isTypeOf(ProductionSubcomponent.class, annotation.getAnnotationType())) {
- return annotationBuilder.isProduction(true).isSubcomponent(true).build();
- }
- throw new IllegalArgumentException(
- annotation
- + " must be a Component, Subcomponent, ProductionComponent, "
- + "or ProductionSubcomponent annotation");
+ public static boolean isComponentAnnotation(XAnnotation annotation) {
+ return ALL_COMPONENT_ANNOTATIONS.contains(getClassName(annotation));
}
/** Creates a fictional component annotation representing a module. */
public static ComponentAnnotation fromModuleAnnotation(ModuleAnnotation moduleAnnotation) {
- return new AutoValue_ComponentAnnotation_FictionalComponentAnnotation(moduleAnnotation);
+ return create(moduleAnnotation.annotation());
+ }
+
+ private static ComponentAnnotation create(XAnnotation annotation) {
+ ComponentAnnotation componentAnnotation =
+ new AutoValue_ComponentAnnotation(getClassName(annotation));
+ componentAnnotation.annotation = annotation;
+ return componentAnnotation;
}
/** The root component annotation types. */
- public static ImmutableSet<Class<? extends Annotation>> rootComponentAnnotations() {
+ public static ImmutableSet<ClassName> rootComponentAnnotations() {
return ROOT_COMPONENT_ANNOTATIONS;
}
/** The subcomponent annotation types. */
- public static ImmutableSet<Class<? extends Annotation>> subcomponentAnnotations() {
+ public static ImmutableSet<ClassName> subcomponentAnnotations() {
return SUBCOMPONENT_ANNOTATIONS;
}
/** All component annotation types. */
- public static ImmutableSet<Class<? extends Annotation>> allComponentAnnotations() {
+ public static ImmutableSet<ClassName> allComponentAnnotations() {
return ALL_COMPONENT_ANNOTATIONS;
}
/** All component and creator annotation types. */
- public static ImmutableSet<Class<? extends Annotation>> allComponentAndCreatorAnnotations() {
+ public static ImmutableSet<ClassName> allComponentAndCreatorAnnotations() {
return ALL_COMPONENT_AND_CREATOR_ANNOTATIONS;
}
-
- /**
- * An actual component annotation.
- *
- * @see FictionalComponentAnnotation
- */
- @AutoValue
- abstract static class RealComponentAnnotation extends ComponentAnnotation {
-
- @Override
- @Memoized
- public ImmutableList<AnnotationValue> dependencyValues() {
- return isSubcomponent() ? ImmutableList.of() : getAnnotationValues("dependencies");
- }
-
- @Override
- @Memoized
- public ImmutableList<TypeMirror> dependencyTypes() {
- return super.dependencyTypes();
- }
-
- @Override
- @Memoized
- public ImmutableList<TypeElement> dependencies() {
- return super.dependencies();
- }
-
- @Override
- public boolean isRealComponent() {
- return true;
- }
-
- @Override
- @Memoized
- public ImmutableList<AnnotationValue> moduleValues() {
- return getAnnotationValues("modules");
- }
-
- @Override
- @Memoized
- public ImmutableList<TypeMirror> moduleTypes() {
- return super.moduleTypes();
- }
-
- @Override
- @Memoized
- public ImmutableSet<TypeElement> modules() {
- return super.modules();
- }
-
- static Builder builder() {
- return new AutoValue_ComponentAnnotation_RealComponentAnnotation.Builder();
- }
-
- @AutoValue.Builder
- interface Builder {
- Builder annotation(AnnotationMirror annotation);
-
- Builder isSubcomponent(boolean isSubcomponent);
-
- Builder isProduction(boolean isProduction);
-
- RealComponentAnnotation build();
- }
- }
-
- /**
- * A fictional component annotation used to represent modules or other collections of bindings as
- * a component.
- */
- @AutoValue
- abstract static class FictionalComponentAnnotation extends ComponentAnnotation {
-
- @Override
- public AnnotationMirror annotation() {
- return moduleAnnotation().annotation();
- }
-
- @Override
- public boolean isSubcomponent() {
- return false;
- }
-
- @Override
- public boolean isProduction() {
- return ClassName.get(asType(moduleAnnotation().annotation().getAnnotationType().asElement()))
- .equals(PRODUCER_MODULE);
- }
-
- @Override
- public boolean isRealComponent() {
- return false;
- }
-
- @Override
- public ImmutableList<AnnotationValue> dependencyValues() {
- return ImmutableList.of();
- }
-
- @Override
- public ImmutableList<AnnotationValue> moduleValues() {
- return moduleAnnotation().includesAsAnnotationValues();
- }
-
- @Override
- @Memoized
- public ImmutableList<TypeMirror> moduleTypes() {
- return super.moduleTypes();
- }
-
- @Override
- @Memoized
- public ImmutableSet<TypeElement> modules() {
- return super.modules();
- }
-
- public abstract ModuleAnnotation moduleAnnotation();
- }
}
diff --git a/java/dagger/internal/codegen/binding/ComponentCreatorAnnotation.java b/java/dagger/internal/codegen/base/ComponentCreatorAnnotation.java
index 6297188d0..621d66f64 100644
--- a/java/dagger/internal/codegen/binding/ComponentCreatorAnnotation.java
+++ b/java/dagger/internal/codegen/base/ComponentCreatorAnnotation.java
@@ -14,68 +14,62 @@
* limitations under the License.
*/
-package dagger.internal.codegen.binding;
+package dagger.internal.codegen.base;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
import static com.google.common.base.Ascii.toUpperCase;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.extension.DaggerStreams.valuesOf;
import static java.util.stream.Collectors.mapping;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
-import dagger.Component;
-import dagger.Subcomponent;
-import dagger.internal.codegen.base.ComponentAnnotation;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-import java.lang.annotation.Annotation;
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.javapoet.TypeNames;
import java.util.stream.Collector;
import java.util.stream.Stream;
-import javax.lang.model.element.TypeElement;
/** Simple representation of a component creator annotation type. */
public enum ComponentCreatorAnnotation {
- COMPONENT_BUILDER(Component.Builder.class),
- COMPONENT_FACTORY(Component.Factory.class),
- SUBCOMPONENT_BUILDER(Subcomponent.Builder.class),
- SUBCOMPONENT_FACTORY(Subcomponent.Factory.class),
- PRODUCTION_COMPONENT_BUILDER(ProductionComponent.Builder.class),
- PRODUCTION_COMPONENT_FACTORY(ProductionComponent.Factory.class),
- PRODUCTION_SUBCOMPONENT_BUILDER(ProductionSubcomponent.Builder.class),
- PRODUCTION_SUBCOMPONENT_FACTORY(ProductionSubcomponent.Factory.class),
+ COMPONENT_BUILDER(TypeNames.COMPONENT_BUILDER),
+ COMPONENT_FACTORY(TypeNames.COMPONENT_FACTORY),
+ SUBCOMPONENT_BUILDER(TypeNames.SUBCOMPONENT_BUILDER),
+ SUBCOMPONENT_FACTORY(TypeNames.SUBCOMPONENT_FACTORY),
+ PRODUCTION_COMPONENT_BUILDER(TypeNames.PRODUCTION_COMPONENT_BUILDER),
+ PRODUCTION_COMPONENT_FACTORY(TypeNames.PRODUCTION_COMPONENT_FACTORY),
+ PRODUCTION_SUBCOMPONENT_BUILDER(TypeNames.PRODUCTION_SUBCOMPONENT_BUILDER),
+ PRODUCTION_SUBCOMPONENT_FACTORY(TypeNames.PRODUCTION_SUBCOMPONENT_FACTORY),
;
- private final Class<? extends Annotation> annotation;
+ private final ClassName annotation;
private final ComponentCreatorKind creatorKind;
- private final Class<? extends Annotation> componentAnnotation;
+ private final ClassName componentAnnotation;
- @SuppressWarnings("unchecked") // Builder/factory annotations live within their parent annotation.
- ComponentCreatorAnnotation(Class<? extends Annotation> annotation) {
+ ComponentCreatorAnnotation(ClassName annotation) {
this.annotation = annotation;
- this.creatorKind = ComponentCreatorKind.valueOf(toUpperCase(annotation.getSimpleName()));
- this.componentAnnotation = (Class<? extends Annotation>) annotation.getEnclosingClass();
+ this.creatorKind = ComponentCreatorKind.valueOf(toUpperCase(annotation.simpleName()));
+ this.componentAnnotation = annotation.enclosingClassName();
}
/** The actual annotation type. */
- public Class<? extends Annotation> annotation() {
+ public ClassName annotation() {
return annotation;
}
/** The component annotation type that encloses this creator annotation type. */
- public final Class<? extends Annotation> componentAnnotation() {
+ public final ClassName componentAnnotation() {
return componentAnnotation;
}
/** Returns {@code true} if the creator annotation is for a subcomponent. */
public final boolean isSubcomponentCreatorAnnotation() {
- return componentAnnotation().getSimpleName().endsWith("Subcomponent");
+ return componentAnnotation().simpleName().endsWith("Subcomponent");
}
/**
* Returns {@code true} if the creator annotation is for a production component or subcomponent.
*/
public final boolean isProductionCreatorAnnotation() {
- return componentAnnotation().getSimpleName().startsWith("Production");
+ return componentAnnotation().simpleName().startsWith("Production");
}
/** The creator kind the annotation is associated with. */
@@ -86,16 +80,16 @@ public enum ComponentCreatorAnnotation {
@Override
public final String toString() {
- return annotation().getName();
+ return annotation().canonicalName();
}
/** Returns all component creator annotations. */
- public static ImmutableSet<Class<? extends Annotation>> allCreatorAnnotations() {
+ public static ImmutableSet<ClassName> allCreatorAnnotations() {
return stream().collect(toAnnotationClasses());
}
/** Returns all root component creator annotations. */
- public static ImmutableSet<Class<? extends Annotation>> rootComponentCreatorAnnotations() {
+ public static ImmutableSet<ClassName> rootComponentCreatorAnnotations() {
return stream()
.filter(
componentCreatorAnnotation ->
@@ -104,7 +98,7 @@ public enum ComponentCreatorAnnotation {
}
/** Returns all subcomponent creator annotations. */
- public static ImmutableSet<Class<? extends Annotation>> subcomponentCreatorAnnotations() {
+ public static ImmutableSet<ClassName> subcomponentCreatorAnnotations() {
return stream()
.filter(
componentCreatorAnnotation ->
@@ -113,7 +107,7 @@ public enum ComponentCreatorAnnotation {
}
/** Returns all production component creator annotations. */
- public static ImmutableSet<Class<? extends Annotation>> productionCreatorAnnotations() {
+ public static ImmutableSet<ClassName> productionCreatorAnnotations() {
return stream()
.filter(
componentCreatorAnnotation ->
@@ -122,30 +116,28 @@ public enum ComponentCreatorAnnotation {
}
/** Returns the legal creator annotations for the given {@code componentAnnotation}. */
- public static ImmutableSet<Class<? extends Annotation>> creatorAnnotationsFor(
+ public static ImmutableSet<ClassName> creatorAnnotationsFor(
ComponentAnnotation componentAnnotation) {
return stream()
.filter(
creatorAnnotation ->
creatorAnnotation
.componentAnnotation()
- .getSimpleName()
+ .simpleName()
.equals(componentAnnotation.simpleName()))
.collect(toAnnotationClasses());
}
/** Returns all creator annotations present on the given {@code type}. */
- public static ImmutableSet<ComponentCreatorAnnotation> getCreatorAnnotations(TypeElement type) {
- return stream()
- .filter(cca -> isAnnotationPresent(type, cca.annotation()))
- .collect(toImmutableSet());
+ public static ImmutableSet<ComponentCreatorAnnotation> getCreatorAnnotations(XTypeElement type) {
+ return stream().filter(cca -> type.hasAnnotation(cca.annotation())).collect(toImmutableSet());
}
private static Stream<ComponentCreatorAnnotation> stream() {
return valuesOf(ComponentCreatorAnnotation.class);
}
- private static Collector<ComponentCreatorAnnotation, ?, ImmutableSet<Class<? extends Annotation>>>
+ private static Collector<ComponentCreatorAnnotation, ?, ImmutableSet<ClassName>>
toAnnotationClasses() {
return mapping(ComponentCreatorAnnotation::annotation, toImmutableSet());
}
diff --git a/java/dagger/internal/codegen/binding/ComponentCreatorKind.java b/java/dagger/internal/codegen/base/ComponentCreatorKind.java
index b2581d685..3af94bbc2 100644
--- a/java/dagger/internal/codegen/binding/ComponentCreatorKind.java
+++ b/java/dagger/internal/codegen/base/ComponentCreatorKind.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package dagger.internal.codegen.binding;
+package dagger.internal.codegen.base;
import static com.google.common.base.CaseFormat.UPPER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
diff --git a/java/dagger/internal/codegen/base/ComponentKind.java b/java/dagger/internal/codegen/base/ComponentKind.java
new file mode 100644
index 000000000..9d087636a
--- /dev/null
+++ b/java/dagger/internal/codegen/base/ComponentKind.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.base;
+
+import static com.google.common.collect.Sets.immutableEnumSet;
+import static dagger.internal.codegen.extension.DaggerStreams.stream;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.extension.DaggerStreams.valuesOf;
+import static java.util.EnumSet.allOf;
+
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.javapoet.TypeNames;
+import java.util.Optional;
+
+/** Enumeration of the different kinds of components. */
+public enum ComponentKind {
+ COMPONENT(TypeNames.COMPONENT),
+ SUBCOMPONENT(TypeNames.SUBCOMPONENT),
+ PRODUCTION_COMPONENT(TypeNames.PRODUCTION_COMPONENT),
+ PRODUCTION_SUBCOMPONENT(TypeNames.PRODUCTION_SUBCOMPONENT),
+ MODULE(TypeNames.MODULE),
+ PRODUCER_MODULE(TypeNames.PRODUCER_MODULE);
+
+ private static final ImmutableSet<ComponentKind> PRODUCER_KINDS =
+ ImmutableSet.of(PRODUCTION_COMPONENT, PRODUCTION_SUBCOMPONENT, PRODUCER_MODULE);
+
+ /** Returns the annotations for components of the given kinds. */
+ public static ImmutableSet<ClassName> annotationsFor(Iterable<ComponentKind> kinds) {
+ return stream(kinds).map(ComponentKind::annotation).collect(toImmutableSet());
+ }
+
+ /** Returns the set of component kinds the given {@code element} has annotations for. */
+ public static ImmutableSet<ComponentKind> getComponentKinds(XTypeElement element) {
+ return valuesOf(ComponentKind.class)
+ .filter(kind -> element.hasAnnotation(kind.annotation()))
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Returns the kind of an annotated element if it is annotated with one of the {@linkplain
+ * #annotation() annotations}.
+ *
+ * @throws IllegalArgumentException if the element is annotated with more than one of the
+ * annotations
+ */
+ public static Optional<ComponentKind> forAnnotatedElement(XTypeElement element) {
+ ImmutableSet<ComponentKind> kinds = getComponentKinds(element);
+ if (kinds.size() > 1) {
+ throw new IllegalArgumentException(
+ element + " cannot be annotated with more than one of " + annotationsFor(kinds));
+ }
+ return kinds.stream().findAny();
+ }
+
+ private final ClassName annotation;
+
+ ComponentKind(ClassName annotation) {
+ this.annotation = annotation;
+ }
+
+ /** Returns the annotation that marks a component of this kind. */
+ public ClassName annotation() {
+ return annotation;
+ }
+
+ /** Returns the kinds of modules that can be used with a component of this kind. */
+ public ImmutableSet<ModuleKind> legalModuleKinds() {
+ return isProducer()
+ ? immutableEnumSet(allOf(ModuleKind.class))
+ : immutableEnumSet(ModuleKind.MODULE);
+ }
+
+ /** Returns the kinds of subcomponents a component of this kind can have. */
+ public ImmutableSet<ComponentKind> legalSubcomponentKinds() {
+ return isProducer()
+ ? immutableEnumSet(PRODUCTION_SUBCOMPONENT)
+ : immutableEnumSet(SUBCOMPONENT, PRODUCTION_SUBCOMPONENT);
+ }
+
+ /** Returns true if this is a production component. */
+ public boolean isProducer() {
+ return PRODUCER_KINDS.contains(this);
+ }
+}
diff --git a/java/dagger/internal/codegen/base/ContributionType.java b/java/dagger/internal/codegen/base/ContributionType.java
index c046daaf2..93d423e4b 100644
--- a/java/dagger/internal/codegen/base/ContributionType.java
+++ b/java/dagger/internal/codegen/base/ContributionType.java
@@ -16,8 +16,10 @@
package dagger.internal.codegen.base;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import androidx.room.compiler.processing.XElement;
import dagger.multibindings.ElementsIntoSet;
import dagger.multibindings.IntoMap;
import dagger.multibindings.IntoSet;
@@ -54,6 +56,17 @@ public enum ContributionType {
* dagger.internal.codegen.validation.BindsInstanceProcessingStep} validate correctness on their
* own.
*/
+ public static ContributionType fromBindingElement(XElement element) {
+ return fromBindingElement(toJavac(element));
+ }
+
+ /**
+ * The contribution type from a binding element's annotations. Presumes a well-formed binding
+ * element (at most one of @IntoSet, @IntoMap, @ElementsIntoSet and @Provides.type). {@link
+ * dagger.internal.codegen.validation.BindingMethodValidator} and {@link
+ * dagger.internal.codegen.validation.BindsInstanceProcessingStep} validate correctness on their
+ * own.
+ */
public static ContributionType fromBindingElement(Element element) {
// TODO(bcorso): Replace these class references with ClassName.
if (isAnnotationPresent(element, IntoMap.class)) {
diff --git a/java/dagger/internal/codegen/base/DaggerSuperficialValidation.java b/java/dagger/internal/codegen/base/DaggerSuperficialValidation.java
new file mode 100644
index 000000000..2f53a71fc
--- /dev/null
+++ b/java/dagger/internal/codegen/base/DaggerSuperficialValidation.java
@@ -0,0 +1,823 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.base;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static com.google.auto.common.MoreElements.asType;
+import static com.google.auto.common.MoreElements.isType;
+import static com.google.auto.common.MoreTypes.asDeclared;
+
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.auto.common.AnnotationMirrors;
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Ascii;
+import com.google.common.collect.ImmutableList;
+import com.squareup.javapoet.ClassName;
+import dagger.Reusable;
+import dagger.internal.codegen.compileroption.CompilerOptions;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.AnnotationValueVisitor;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ErrorType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+import javax.lang.model.type.WildcardType;
+import javax.lang.model.util.AbstractElementVisitor8;
+import javax.lang.model.util.SimpleAnnotationValueVisitor8;
+import javax.lang.model.util.SimpleTypeVisitor8;
+
+/**
+ * A fork of {@link com.google.auto.common.SuperficialValidation}.
+ *
+ * <p>This fork makes a couple changes from the original:
+ *
+ * <ul>
+ * <li>Throws {@link ValidationException} rather than returning {@code false} for invalid types.
+ * <li>Fixes a bug that incorrectly validates error types in annotations (b/213880825)
+ * <li>Exposes extra methods needed to validate various parts of an element rather than just the
+ * entire element.
+ * </ul>
+ */
+@Reusable
+public final class DaggerSuperficialValidation {
+
+ /**
+ * Returns the type element with the given class name or throws {@link ValidationException} if it
+ * is not accessible in the current compilation.
+ */
+ public static XTypeElement requireTypeElement(XProcessingEnv processingEnv, ClassName className) {
+ return requireTypeElement(processingEnv, className.canonicalName());
+ }
+
+ /**
+ * Returns the type element with the given class name or throws {@link ValidationException} if it
+ * is not accessible in the current compilation.
+ */
+ public static XTypeElement requireTypeElement(XProcessingEnv processingEnv, String className) {
+ XTypeElement type = processingEnv.findTypeElement(className);
+ if (type == null) {
+ throw new ValidationException.KnownErrorType(className);
+ }
+ return type;
+ }
+
+ private final boolean isStrictValidationEnabled;
+
+ @Inject
+ DaggerSuperficialValidation(CompilerOptions compilerOptions) {
+ this(compilerOptions.strictSuperficialValidation());
+ }
+
+ private DaggerSuperficialValidation(boolean isStrictValidationEnabled) {
+ this.isStrictValidationEnabled = isStrictValidationEnabled;
+ }
+
+ /**
+ * Validates the {@link XElement#getType()} type of the given element.
+ *
+ * <p>Validating the type also validates any types it references, such as any type arguments or
+ * type bounds. For an {@link ExecutableType}, the parameter and return types must be fully
+ * defined, as must types declared in a {@code throws} clause or in the bounds of any type
+ * parameters.
+ */
+ public void validateTypeOf(XElement element) {
+ validateTypeOf(toJavac(element));
+ }
+
+ private void validateTypeOf(Element element) {
+ try {
+ validateType(Ascii.toLowerCase(element.getKind().name()), element.asType());
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception).append(element);
+ }
+ }
+
+ /**
+ * Validates the {@link XElement#getSuperType()} type of the given element.
+ *
+ * <p>Validating the type also validates any types it references, such as any type arguments or
+ * type bounds.
+ */
+ public void validateSuperTypeOf(XTypeElement element) {
+ validateSuperTypeOf(toJavac(element));
+ }
+
+ private void validateSuperTypeOf(TypeElement element) {
+ try {
+ validateType("superclass", element.getSuperclass());
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception).append(element);
+ }
+ }
+
+ /**
+ * Validates the {@link XExecutableElement#getThrownTypes()} types of the given element.
+ *
+ * <p>Validating the type also validates any types it references, such as any type arguments or
+ * type bounds.
+ */
+ public void validateThrownTypesOf(XExecutableElement element) {
+ validateThrownTypesOf(toJavac(element));
+ }
+
+ private void validateThrownTypesOf(ExecutableElement element) {
+ try {
+ validateTypes("thrown type", element.getThrownTypes());
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception).append(element);
+ }
+ }
+
+ /**
+ * Validates the annotation types of the given element.
+ *
+ * <p>Note: this method does not validate annotation values. This method is useful if you care
+ * about the annotation's annotations (e.g. to check for {@code Scope} or {@code Qualifier}). In
+ * such cases, we just need to validate the annotation's type.
+ */
+ public void validateAnnotationTypesOf(XElement element) {
+ validateAnnotationTypesOf(toJavac(element));
+ }
+
+ /**
+ * Validates the annotation types of the given element.
+ *
+ * <p>Note: this method does not validate annotation values. This method is useful if you care
+ * about the annotation's annotations (e.g. to check for {@code Scope} or {@code Qualifier}). In
+ * such cases, we just need to validate the annotation's type.
+ */
+ public void validateAnnotationTypesOf(Element element) {
+ element
+ .getAnnotationMirrors()
+ .forEach(annotation -> validateAnnotationTypeOf(element, annotation));
+ }
+
+ /**
+ * Validates the type of the given annotation.
+ *
+ * <p>The annotation is assumed to be annotating the given element, but this is not checked. The
+ * element is only in the error message if a {@link ValidatationException} is thrown.
+ *
+ * <p>Note: this method does not validate annotation values. This method is useful if you care
+ * about the annotation's annotations (e.g. to check for {@code Scope} or {@code Qualifier}). In
+ * such cases, we just need to validate the annotation's type.
+ */
+ // TODO(bcorso): See CL/427767370 for suggestions to make this API clearer.
+ public void validateAnnotationTypeOf(XElement element, XAnnotation annotation) {
+ validateAnnotationTypeOf(toJavac(element), toJavac(annotation));
+ }
+
+ /**
+ * Validates the type of the given annotation.
+ *
+ * <p>The annotation is assumed to be annotating the given element, but this is not checked. The
+ * element is only in the error message if a {@link ValidatationException} is thrown.
+ *
+ * <p>Note: this method does not validate annotation values. This method is useful if you care
+ * about the annotation's annotations (e.g. to check for {@code Scope} or {@code Qualifier}). In
+ * such cases, we just need to validate the annotation's type.
+ */
+ public void validateAnnotationTypeOf(Element element, AnnotationMirror annotation) {
+ try {
+ validateType("annotation type", annotation.getAnnotationType());
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception).append(annotation).append(element);
+ }
+ }
+
+ /** Validate the annotations of the given element. */
+ public void validateAnnotationsOf(XElement element) {
+ validateAnnotationsOf(toJavac(element));
+ }
+
+ public void validateAnnotationsOf(Element element) {
+ try {
+ validateAnnotations(element.getAnnotationMirrors());
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception).append(element);
+ }
+ }
+
+ public void validateAnnotationOf(XElement element, XAnnotation annotation) {
+ validateAnnotationOf(toJavac(element), toJavac(annotation));
+ }
+
+ public void validateAnnotationOf(Element element, AnnotationMirror annotation) {
+ try {
+ validateAnnotation(annotation);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception).append(element);
+ }
+ }
+
+ /**
+ * Validate the type hierarchy for the given type (with the given type description) within the
+ * given element.
+ *
+ * <p>Validation includes all superclasses, interfaces, and type parameters of those types.
+ */
+ public void validateTypeHierarchyOf(String typeDescription, XElement element, XType type) {
+ try {
+ validateTypeHierarchy(typeDescription, type);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception).append(toJavac(element));
+ }
+ }
+
+ private void validateTypeHierarchy(String desc, XType type) {
+ validateType(desc, toJavac(type));
+ try {
+ type.getSuperTypes().forEach(supertype -> validateTypeHierarchy("supertype", supertype));
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception).append(desc, toJavac(type));
+ }
+ }
+
+ /**
+ * Returns true if all of the given elements return true from {@link #validateElement(Element)}.
+ */
+ public void validateElements(Iterable<? extends Element> elements) {
+ for (Element element : elements) {
+ validateElement(element);
+ }
+ }
+
+ private final ElementVisitor<Void, Void> elementValidatingVisitor =
+ new AbstractElementVisitor8<Void, Void>() {
+ @Override
+ public Void visitPackage(PackageElement e, Void p) {
+ // don't validate enclosed elements because it will return types in the package
+ validateAnnotations(e.getAnnotationMirrors());
+ return null;
+ }
+
+ @Override
+ public Void visitType(TypeElement e, Void p) {
+ validateBaseElement(e);
+ validateElements(e.getTypeParameters());
+ validateTypes("interface", e.getInterfaces());
+ validateType("superclass", e.getSuperclass());
+ return null;
+ }
+
+ @Override
+ public Void visitVariable(VariableElement e, Void p) {
+ validateBaseElement(e);
+ return null;
+ }
+
+ @Override
+ public Void visitExecutable(ExecutableElement e, Void p) {
+ AnnotationValue defaultValue = e.getDefaultValue();
+ validateBaseElement(e);
+ if (defaultValue != null) {
+ validateAnnotationValue(defaultValue, e.getReturnType());
+ }
+ validateType("return type", e.getReturnType());
+ validateTypes("thrown type", e.getThrownTypes());
+ validateElements(e.getTypeParameters());
+ validateElements(e.getParameters());
+ return null;
+ }
+
+ @Override
+ public Void visitTypeParameter(TypeParameterElement e, Void p) {
+ validateBaseElement(e);
+ validateTypes("bound type", e.getBounds());
+ return null;
+ }
+
+ @Override
+ public Void visitUnknown(Element e, Void p) {
+ // just assume that unknown elements are OK
+ return null;
+ }
+ };
+
+ /**
+ * Returns true if all types referenced by the given element are defined. The exact meaning of
+ * this depends on the kind of element. For packages, it means that all annotations on the package
+ * are fully defined. For other element kinds, it means that types referenced by the element,
+ * anything it contains, and any of its annotations element are all defined.
+ */
+ public void validateElement(XElement element) {
+ validateElement(toJavac(element));
+ }
+
+ /**
+ * Returns true if all types referenced by the given element are defined. The exact meaning of
+ * this depends on the kind of element. For packages, it means that all annotations on the package
+ * are fully defined. For other element kinds, it means that types referenced by the element,
+ * anything it contains, and any of its annotations element are all defined.
+ */
+ public void validateElement(Element element) {
+ try {
+ element.accept(elementValidatingVisitor, null);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception).append(element);
+ }
+ }
+
+ private void validateBaseElement(Element e) {
+ validateType(Ascii.toLowerCase(e.getKind().name()), e.asType());
+ validateAnnotations(e.getAnnotationMirrors());
+ validateElements(e.getEnclosedElements());
+ }
+
+ private void validateTypes(String desc, Iterable<? extends TypeMirror> types) {
+ for (TypeMirror type : types) {
+ validateType(desc, type);
+ }
+ }
+
+ /*
+ * This visitor does not test type variables specifically, but it seems that that is not actually
+ * an issue. Javac turns the whole type parameter into an error type if it can't figure out the
+ * bounds.
+ */
+ private final TypeVisitor<Void, Void> typeValidatingVisitor =
+ new SimpleTypeVisitor8<Void, Void>() {
+ @Override
+ protected Void defaultAction(TypeMirror t, Void p) {
+ return null;
+ }
+
+ @Override
+ public Void visitArray(ArrayType t, Void p) {
+ validateType("array component type", t.getComponentType());
+ return null;
+ }
+
+ @Override
+ public Void visitDeclared(DeclaredType t, Void p) {
+ if (isStrictValidationEnabled) {
+ // There's a bug in TypeVisitor which will visit the visitDeclared() method rather than
+ // visitError() even when it's an ERROR kind. Thus, we check the kind directly here and
+ // fail validation if it's an ERROR kind (see b/213880825).
+ if (t.getKind() == TypeKind.ERROR) {
+ throw new ValidationException.KnownErrorType(t);
+ }
+ }
+ validateTypes("type argument", t.getTypeArguments());
+ return null;
+ }
+
+ @Override
+ public Void visitError(ErrorType t, Void p) {
+ throw new ValidationException.KnownErrorType(t);
+ }
+
+ @Override
+ public Void visitUnknown(TypeMirror t, Void p) {
+ // just make the default choice for unknown types
+ return defaultAction(t, p);
+ }
+
+ @Override
+ public Void visitWildcard(WildcardType t, Void p) {
+ TypeMirror extendsBound = t.getExtendsBound();
+ TypeMirror superBound = t.getSuperBound();
+ if (extendsBound != null) {
+ validateType("extends bound type", extendsBound);
+ }
+ if (superBound != null) {
+ validateType("super bound type", superBound);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitExecutable(ExecutableType t, Void p) {
+ validateTypes("parameter type", t.getParameterTypes());
+ validateType("return type", t.getReturnType());
+ validateTypes("thrown type", t.getThrownTypes());
+ validateTypes("type variable", t.getTypeVariables());
+ return null;
+ }
+ };
+
+ /**
+ * Returns true if the given type is fully defined. This means that the type itself is defined, as
+ * are any types it references, such as any type arguments or type bounds. For an {@link
+ * ExecutableType}, the parameter and return types must be fully defined, as must types declared
+ * in a {@code throws} clause or in the bounds of any type parameters.
+ */
+ private void validateType(String desc, TypeMirror type) {
+ try {
+ type.accept(typeValidatingVisitor, null);
+ if (isStrictValidationEnabled) {
+ // Note: We don't actually expect to get an ERROR type here as it should have been caught
+ // by the visitError() or visitDeclared() methods above. However, we check here as a last
+ // resort.
+ if (type.getKind() == TypeKind.ERROR) {
+ // In this case, the type is not guaranteed to be a DeclaredType, so we report the
+ // toString() of the type. We could report using UnknownErrorType but the type's toString
+ // may actually contain useful information.
+ throw new ValidationException.KnownErrorType(type.toString());
+ }
+ }
+ } catch (RuntimeException e) {
+ throw ValidationException.from(e).append(desc, type);
+ }
+ }
+
+ private void validateAnnotations(Iterable<? extends AnnotationMirror> annotationMirrors) {
+ for (AnnotationMirror annotationMirror : annotationMirrors) {
+ validateAnnotation(annotationMirror);
+ }
+ }
+
+ private void validateAnnotation(AnnotationMirror annotationMirror) {
+ try {
+ validateType("annotation type", annotationMirror.getAnnotationType());
+ validateAnnotationValues(annotationMirror.getElementValues());
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception).append(annotationMirror);
+ }
+ }
+
+ private void validateAnnotationValues(
+ Map<? extends ExecutableElement, ? extends AnnotationValue> valueMap) {
+ valueMap.forEach(
+ (method, annotationValue) -> {
+ try {
+ TypeMirror expectedType = method.getReturnType();
+ validateAnnotationValue(annotationValue, expectedType);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception)
+ .append(String.format("annotation method: %s %s", method.getReturnType(), method));
+ }
+ });
+ }
+
+ private void validateAnnotationValue(AnnotationValue annotationValue, TypeMirror expectedType) {
+ annotationValue.accept(valueValidatingVisitor, expectedType);
+ }
+
+ private final AnnotationValueVisitor<Void, TypeMirror> valueValidatingVisitor =
+ new SimpleAnnotationValueVisitor8<Void, TypeMirror>() {
+ @Override
+ protected Void defaultAction(Object o, TypeMirror expectedType) {
+ try {
+ validateIsTypeOf(o.getClass(), expectedType);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception)
+ .append(exceptionMessage("DEFAULT", o, expectedType));
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitString(String str, TypeMirror expectedType) {
+ try {
+ if (!MoreTypes.isTypeOf(String.class, expectedType)) {
+ if (str.contentEquals("<error>")) {
+ // Invalid annotation value types will visit visitString() with a value of "<error>"
+ // Technically, we don't know the error type in this case, but it will be referred
+ // to as "<error>" in the dependency trace, so we use that.
+ throw new ValidationException.KnownErrorType("<error>");
+ } else {
+ throw new ValidationException.UnknownErrorType();
+ }
+ }
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception)
+ .append(exceptionMessage("STRING", str, expectedType));
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitUnknown(AnnotationValue av, TypeMirror expectedType) {
+ // just take the default action for the unknown
+ defaultAction(av, expectedType);
+ return null;
+ }
+
+ @Override
+ public Void visitAnnotation(AnnotationMirror a, TypeMirror expectedType) {
+ try {
+ validateIsEquivalentType(a.getAnnotationType(), expectedType);
+ validateAnnotation(a);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception)
+ .append(exceptionMessage("ANNOTATION", a, expectedType));
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitArray(List<? extends AnnotationValue> values, TypeMirror expectedType) {
+ try {
+ if (!expectedType.getKind().equals(TypeKind.ARRAY)) {
+ throw new ValidationException.UnknownErrorType();
+ }
+ TypeMirror componentType = MoreTypes.asArray(expectedType).getComponentType();
+ for (AnnotationValue value : values) {
+ value.accept(this, componentType);
+ }
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception)
+ .append(exceptionMessage("ARRAY", values, expectedType));
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitEnumConstant(VariableElement enumConstant, TypeMirror expectedType) {
+ try {
+ validateIsEquivalentType(asDeclared(enumConstant.asType()), expectedType);
+ validateElement(enumConstant);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception)
+ .append(exceptionMessage("ENUM_CONSTANT", enumConstant, expectedType));
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitType(TypeMirror type, TypeMirror expectedType) {
+ try {
+ // We could check assignability here, but would require a Types instance. Since this
+ // isn't really the sort of thing that shows up in a bad AST from upstream compilation
+ // we ignore the expected type and just validate the type. It might be wrong, but
+ // it's valid.
+ validateType("annotation value type", type);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception)
+ .append(exceptionMessage("TYPE", type, expectedType));
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitBoolean(boolean b, TypeMirror expectedType) {
+ try {
+ validateIsTypeOf(Boolean.TYPE, expectedType);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception)
+ .append(exceptionMessage("BOOLEAN", b, expectedType));
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitByte(byte b, TypeMirror expectedType) {
+ try {
+ validateIsTypeOf(Byte.TYPE, expectedType);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception)
+ .append(exceptionMessage("BYTE", b, expectedType));
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitChar(char c, TypeMirror expectedType) {
+ try {
+ validateIsTypeOf(Character.TYPE, expectedType);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception)
+ .append(exceptionMessage("CHAR", c, expectedType));
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitDouble(double d, TypeMirror expectedType) {
+ try {
+ validateIsTypeOf(Double.TYPE, expectedType);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception)
+ .append(exceptionMessage("DOUBLE", d, expectedType));
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitFloat(float f, TypeMirror expectedType) {
+ try {
+ validateIsTypeOf(Float.TYPE, expectedType);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception)
+ .append(exceptionMessage("FLOAT", f, expectedType));
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitInt(int i, TypeMirror expectedType) {
+ try {
+ validateIsTypeOf(Integer.TYPE, expectedType);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception)
+ .append(exceptionMessage("INT", i, expectedType));
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitLong(long l, TypeMirror expectedType) {
+ try {
+ validateIsTypeOf(Long.TYPE, expectedType);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception)
+ .append(exceptionMessage("LONG", l, expectedType));
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitShort(short s, TypeMirror expectedType) {
+ try {
+ validateIsTypeOf(Short.TYPE, expectedType);
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception)
+ .append(exceptionMessage("SHORT", s, expectedType));
+ }
+ return null;
+ }
+
+ private <T> String exceptionMessage(String valueType, T value, TypeMirror expectedType) {
+ return String.format(
+ "annotation value (%s): value '%s' with expected type %s",
+ valueType, value, expectedType);
+ }
+ };
+
+ private void validateIsTypeOf(Class<?> clazz, TypeMirror expectedType) {
+ if (!MoreTypes.isTypeOf(clazz, expectedType)) {
+ throw new ValidationException.UnknownErrorType();
+ }
+ }
+
+ private void validateIsEquivalentType(DeclaredType type, TypeMirror expectedType) {
+ if (!MoreTypes.equivalence().equivalent(type, expectedType)) {
+ throw new ValidationException.KnownErrorType(type);
+ }
+ }
+
+ /**
+ * A runtime exception that can be used during superficial validation to collect information about
+ * unexpected exceptions during validation.
+ */
+ public abstract static class ValidationException extends RuntimeException {
+ /** A {@link ValidationException} that originated from an unexpected exception. */
+ public static final class UnexpectedException extends ValidationException {
+ private UnexpectedException(Throwable throwable) {
+ super(throwable);
+ }
+ }
+
+ /** A {@link ValidationException} that originated from a known error type. */
+ public static final class KnownErrorType extends ValidationException {
+ private final String errorTypeName;
+
+ private KnownErrorType(DeclaredType errorType) {
+ Element errorElement = errorType.asElement();
+ this.errorTypeName =
+ isType(errorElement)
+ ? asType(errorElement).getQualifiedName().toString()
+ // Maybe this case should be handled by UnknownErrorType?
+ : errorElement.getSimpleName().toString();
+ }
+
+ private KnownErrorType(String errorTypeName) {
+ this.errorTypeName = errorTypeName;
+ }
+
+ public String getErrorTypeName() {
+ return errorTypeName;
+ }
+ }
+
+ /** A {@link ValidationException} that originated from an unknown error type. */
+ public static final class UnknownErrorType extends ValidationException {}
+
+ private static ValidationException from(Throwable throwable) {
+ // We only ever create one instance of the ValidationException.
+ return throwable instanceof ValidationException
+ ? ((ValidationException) throwable)
+ : new UnexpectedException(throwable);
+ }
+
+ private Optional<Element> lastReportedElement = Optional.empty();
+ private final List<String> messages = new ArrayList<>();
+
+ private ValidationException() {
+ super("");
+ }
+
+ private ValidationException(Throwable throwable) {
+ super("", throwable);
+ }
+
+ /**
+ * Appends a message for the given element and returns this instance of {@link
+ * ValidationException}
+ */
+ private ValidationException append(Element element) {
+ lastReportedElement = Optional.of(element);
+ return append(getMessageForElement(element));
+ }
+
+ /**
+ * Appends a message for the given type mirror and returns this instance of {@link
+ * ValidationException}
+ */
+ private ValidationException append(String desc, TypeMirror type) {
+ return append(String.format("type (%s %s): %s", type.getKind().name(), desc, type));
+ }
+
+ /**
+ * Appends a message for the given annotation mirror and returns this instance of {@link
+ * ValidationException}
+ */
+ private ValidationException append(AnnotationMirror annotationMirror) {
+ // Note: Calling #toString() directly on the annotation throws NPE (b/216180336).
+ return append(String.format("annotation: %s", AnnotationMirrors.toString(annotationMirror)));
+ }
+
+ /** Appends the given message and returns this instance of {@link ValidationException} */
+ private ValidationException append(String message) {
+ messages.add(message);
+ return this;
+ }
+
+ @Override
+ public String getMessage() {
+ return String.format("\n Validation trace:\n => %s", getTrace());
+ }
+
+ public String getTrace() {
+ return String.join("\n => ", getMessageInternal().reverse());
+ }
+
+ private ImmutableList<String> getMessageInternal() {
+ if (!lastReportedElement.isPresent()) {
+ return ImmutableList.copyOf(messages);
+ }
+ // Append any enclosing element information if needed.
+ List<String> newMessages = new ArrayList<>(messages);
+ Element element = lastReportedElement.get();
+ while (shouldAppendEnclosingElement(element)) {
+ element = element.getEnclosingElement();
+ newMessages.add(getMessageForElement(element));
+ }
+ return ImmutableList.copyOf(newMessages);
+ }
+
+ private static boolean shouldAppendEnclosingElement(Element element) {
+ return element.getEnclosingElement() != null
+ // We don't report enclosing elements for types because the type name should contain any
+ // enclosing type and package information we need.
+ && !isType(element)
+ && (isExecutable(element.getEnclosingElement()) || isType(element.getEnclosingElement()));
+ }
+
+ private static boolean isExecutable(Element element) {
+ return element.getKind() == ElementKind.METHOD
+ || element.getKind() == ElementKind.CONSTRUCTOR;
+ }
+
+ private String getMessageForElement(Element element) {
+ return String.format("element (%s): %s", element.getKind().name(), element);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/base/ElementFormatter.java b/java/dagger/internal/codegen/base/ElementFormatter.java
index f85fbfde8..65f9385c1 100644
--- a/java/dagger/internal/codegen/base/ElementFormatter.java
+++ b/java/dagger/internal/codegen/base/ElementFormatter.java
@@ -16,9 +16,11 @@
package dagger.internal.codegen.base;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.auto.common.MoreElements.asExecutable;
import static java.util.stream.Collectors.joining;
+import androidx.room.compiler.processing.XElement;
import javax.inject.Inject;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementVisitor;
@@ -50,6 +52,17 @@ public final class ElementFormatter extends Formatter<Element> {
*
* <p>Parameters are given with their enclosing executable, with other parameters elided.
*/
+ public static String elementToString(XElement element) {
+ return elementToString(toJavac(element));
+ }
+
+ /**
+ * Returns a useful string form for an element.
+ *
+ * <p>Elements directly enclosed by a type are preceded by the enclosing type's qualified name.
+ *
+ * <p>Parameters are given with their enclosing executable, with other parameters elided.
+ */
public static String elementToString(Element element) {
return element.accept(ELEMENT_TO_STRING, null);
}
diff --git a/java/dagger/internal/codegen/base/FrameworkTypes.java b/java/dagger/internal/codegen/base/FrameworkTypes.java
index 4cd54a33d..2336256e2 100644
--- a/java/dagger/internal/codegen/base/FrameworkTypes.java
+++ b/java/dagger/internal/codegen/base/FrameworkTypes.java
@@ -16,16 +16,16 @@
package dagger.internal.codegen.base;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.auto.common.MoreTypes.isType;
+import static dagger.internal.codegen.langmodel.DaggerTypes.isTypeOf;
+import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XType;
import com.google.common.collect.ImmutableSet;
-import dagger.Lazy;
-import dagger.MembersInjector;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.javapoet.TypeNames;
import java.util.Set;
-import javax.inject.Provider;
import javax.lang.model.type.TypeMirror;
/**
@@ -33,17 +33,22 @@ import javax.lang.model.type.TypeMirror;
* type that the framework itself defines.
*/
public final class FrameworkTypes {
- private static final ImmutableSet<Class<?>> PROVISION_TYPES =
- ImmutableSet.of(Provider.class, Lazy.class, MembersInjector.class);
+ private static final ImmutableSet<ClassName> PROVISION_TYPES =
+ ImmutableSet.of(TypeNames.PROVIDER, TypeNames.LAZY, TypeNames.MEMBERS_INJECTOR);
// NOTE(beder): ListenableFuture is not considered a producer framework type because it is not
// defined by the framework, so we can't treat it specially in ordinary Dagger.
- private static final ImmutableSet<Class<?>> PRODUCTION_TYPES =
- ImmutableSet.of(Produced.class, Producer.class);
+ private static final ImmutableSet<ClassName> PRODUCTION_TYPES =
+ ImmutableSet.of(TypeNames.PRODUCED, TypeNames.PRODUCER);
/** Returns true if the type represents a producer-related framework type. */
- public static boolean isProducerType(TypeMirror type) {
- return isType(type) && typeIsOneOf(PRODUCTION_TYPES, type);
+ public static boolean isProducerType(XType type) {
+ return PRODUCTION_TYPES.stream().anyMatch(className -> isTypeOf(type, className));
+ }
+
+ /** Returns true if the type represents a framework type. */
+ public static boolean isFrameworkType(XType type) {
+ return isFrameworkType(toJavac(type));
}
/** Returns true if the type represents a framework type. */
@@ -53,13 +58,8 @@ public final class FrameworkTypes {
|| typeIsOneOf(PRODUCTION_TYPES, type));
}
- private static boolean typeIsOneOf(Set<Class<?>> classes, TypeMirror type) {
- for (Class<?> clazz : classes) {
- if (MoreTypes.isTypeOf(clazz, type)) {
- return true;
- }
- }
- return false;
+ private static boolean typeIsOneOf(Set<ClassName> classNames, TypeMirror type) {
+ return classNames.stream().anyMatch(className -> isTypeOf(className, type));
}
private FrameworkTypes() {}
diff --git a/java/dagger/internal/codegen/base/Keys.java b/java/dagger/internal/codegen/base/Keys.java
index 4d139266d..dc061fe2a 100644
--- a/java/dagger/internal/codegen/base/Keys.java
+++ b/java/dagger/internal/codegen/base/Keys.java
@@ -16,38 +16,33 @@
package dagger.internal.codegen.base;
-import static com.google.auto.common.MoreTypes.asTypeElement;
import static dagger.internal.codegen.base.ComponentAnnotation.allComponentAndCreatorAnnotations;
-import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
+import static dagger.internal.codegen.xprocessing.XElements.hasAnyAnnotation;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
+import static dagger.internal.codegen.xprocessing.XTypes.isRawParameterizedType;
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import dagger.spi.model.DaggerAnnotation;
+import dagger.spi.model.Key;
import java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.SimpleTypeVisitor6;
/** Utility methods related to {@link Key}s. */
public final class Keys {
public static boolean isValidMembersInjectionKey(Key key) {
return !key.qualifier().isPresent()
&& !key.multibindingContributionIdentifier().isPresent()
- && key.type().getKind().equals(TypeKind.DECLARED);
+ && isDeclared(key.type().xprocessing());
}
/**
* Returns {@code true} if this is valid as an implicit key (that is, if it's valid for a
* just-in-time binding by discovering an {@code @Inject} constructor).
*/
- public static boolean isValidImplicitProvisionKey(Key key, DaggerTypes types) {
- return isValidImplicitProvisionKey(key.qualifier(), key.type(), types);
+ public static boolean isValidImplicitProvisionKey(Key key) {
+ return isValidImplicitProvisionKey(
+ key.qualifier().map(DaggerAnnotation::xprocessing), key.type().xprocessing());
}
/**
@@ -55,42 +50,36 @@ public final class Keys {
* key (that is, if it's valid for a just-in-time binding by discovering an {@code @Inject}
* constructor).
*/
- public static boolean isValidImplicitProvisionKey(
- Optional<? extends AnnotationMirror> qualifier, TypeMirror type, final DaggerTypes types) {
+ public static boolean isValidImplicitProvisionKey(Optional<XAnnotation> qualifier, XType type) {
// Qualifiers disqualify implicit provisioning.
if (qualifier.isPresent()) {
return false;
}
- return type.accept(
- new SimpleTypeVisitor6<Boolean, Void>(false) {
- @Override
- public Boolean visitDeclared(DeclaredType type, Void ignored) {
- // Non-classes or abstract classes aren't allowed.
- TypeElement element = MoreElements.asType(type.asElement());
- if (!element.getKind().equals(ElementKind.CLASS)
- || element.getModifiers().contains(Modifier.ABSTRACT)) {
- return false;
- }
+ // A provision type must be a declared type
+ if (!isDeclared(type)) {
+ return false;
+ }
+
+ // Non-classes or abstract classes aren't allowed.
+ XTypeElement typeElement = type.getTypeElement();
+ if (!typeElement.isClass() || typeElement.isAbstract()) {
+ return false;
+ }
- // If the key has type arguments, validate that each type argument is declared.
- // Otherwise the type argument may be a wildcard (or other type), and we can't
- // resolve that to actual types.
- for (TypeMirror arg : type.getTypeArguments()) {
- if (arg.getKind() != TypeKind.DECLARED) {
- return false;
- }
- }
+ // If the key has type arguments, validate that each type argument is declared.
+ // Otherwise the type argument may be a wildcard (or other type), and we can't
+ // resolve that to actual types.
+ for (XType arg : type.getTypeArguments()) {
+ if (!isDeclared(arg)) {
+ return false;
+ }
+ }
- // Also validate that the key is not the erasure of a generic type.
- // If it is, that means the user referred to Foo<T> as just 'Foo',
- // which we don't allow. (This is a judgement call -- we *could*
- // allow it and instantiate the type bounds... but we don't.)
- return MoreTypes.asDeclared(element.asType()).getTypeArguments().isEmpty()
- || !types.isSameType(types.erasure(element.asType()), type);
- }
- },
- null);
+ // Also validate that if the type represents a parameterized type the user didn't refer to its
+ // raw type, which we don't allow. (This is a judgement call -- we *could* allow it and
+ // instantiate the type bounds... but we don't.)
+ return !isRawParameterizedType(type);
}
/**
@@ -99,7 +88,8 @@ public final class Keys {
*/
public static boolean isComponentOrCreator(Key key) {
return !key.qualifier().isPresent()
- && key.type().getKind() == TypeKind.DECLARED
- && isAnyAnnotationPresent(asTypeElement(key.type()), allComponentAndCreatorAnnotations());
+ && isDeclared(key.type().xprocessing())
+ && hasAnyAnnotation(
+ key.type().xprocessing().getTypeElement(), allComponentAndCreatorAnnotations());
}
}
diff --git a/java/dagger/internal/codegen/base/MapType.java b/java/dagger/internal/codegen/base/MapType.java
index 4e2307a6c..c48b17036 100644
--- a/java/dagger/internal/codegen/base/MapType.java
+++ b/java/dagger/internal/codegen/base/MapType.java
@@ -18,38 +18,33 @@ package dagger.internal.codegen.base;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.langmodel.DaggerTypes.unwrapType;
+import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XType;
import com.google.auto.value.AutoValue;
-import com.google.common.base.Equivalence;
-import dagger.model.Key;
-import java.util.Map;
-import javax.lang.model.type.DeclaredType;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.spi.model.Key;
import javax.lang.model.type.TypeMirror;
-/**
- * Information about a {@link Map} {@link TypeMirror}.
- */
+/** Information about a {@link java.util.Map} {@link TypeMirror}. */
@AutoValue
public abstract class MapType {
- /**
- * The map type itself, wrapped using {@link MoreTypes#equivalence()}. Use
- * {@link #declaredMapType()} instead.
- */
- protected abstract Equivalence.Wrapper<DeclaredType> wrappedDeclaredMapType();
+ private XType type;
- /**
- * The map type itself.
- */
- private DeclaredType declaredMapType() {
- return wrappedDeclaredMapType().get();
+ /** The map type itself. */
+ abstract TypeName typeName();
+
+ /** The map type itself. */
+ private XType type() {
+ return type;
}
- /**
- * {@code true} if the map type is the raw {@link Map} type.
- */
+ /** {@code true} if the map type is the raw {@link java.util.Map} type. */
public boolean isRawType() {
- return declaredMapType().getTypeArguments().isEmpty();
+ return type().getTypeArguments().isEmpty();
}
/**
@@ -57,9 +52,9 @@ public abstract class MapType {
*
* @throws IllegalStateException if {@link #isRawType()} is true.
*/
- public TypeMirror keyType() {
+ public XType keyType() {
checkState(!isRawType());
- return declaredMapType().getTypeArguments().get(0);
+ return type().getTypeArguments().get(0);
}
/**
@@ -67,24 +62,17 @@ public abstract class MapType {
*
* @throws IllegalStateException if {@link #isRawType()} is true.
*/
- public TypeMirror valueType() {
+ public XType valueType() {
checkState(!isRawType());
- return declaredMapType().getTypeArguments().get(1);
+ return type().getTypeArguments().get(1);
}
- /**
- * {@code true} if {@link #valueType()} is a {@code clazz}.
- *
- * @throws IllegalStateException if {@link #isRawType()} is true.
- */
- public boolean valuesAreTypeOf(Class<?> clazz) {
- return MoreTypes.isType(valueType()) && MoreTypes.isTypeOf(clazz, valueType());
+ /** Returns {@code true} if the raw type of {@link #valueType()} is {@code className}. */
+ public boolean valuesAreTypeOf(ClassName className) {
+ return !isRawType() && isTypeOf(valueType(), className);
}
- /**
- * Returns {@code true} if the {@linkplain #valueType() value type} of the {@link Map} is a
- * {@linkplain FrameworkTypes#isFrameworkType(TypeMirror) framework type}.
- */
+ /** Returns {@code true} if the raw type of {@link #valueType()} is a framework type. */
public boolean valuesAreFrameworkType() {
return FrameworkTypes.isFrameworkType(valueType());
}
@@ -96,9 +84,8 @@ public abstract class MapType {
* @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a
* framework type
*/
- public TypeMirror unwrappedFrameworkValueType() {
- checkState(
- valuesAreFrameworkType(), "called unwrappedFrameworkValueType() on %s", declaredMapType());
+ public XType unwrappedFrameworkValueType() {
+ checkState(valuesAreFrameworkType(), "called unwrappedFrameworkValueType() on %s", type());
return uncheckedUnwrappedValueType();
}
@@ -107,52 +94,45 @@ public abstract class MapType {
*
* @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a
* {@code WrappingClass<V>}
- * @throws IllegalArgumentException if {@code wrappingClass} does not have exactly one type
- * parameter
*/
- public TypeMirror unwrappedValueType(Class<?> wrappingClass) {
- checkArgument(
- wrappingClass.getTypeParameters().length == 1,
- "%s must have exactly one type parameter",
- wrappingClass);
+ // TODO(b/202033221): Consider using stricter input type, e.g. FrameworkType.
+ public XType unwrappedValueType(ClassName wrappingClass) {
checkState(valuesAreTypeOf(wrappingClass), "expected values to be %s: %s", wrappingClass, this);
return uncheckedUnwrappedValueType();
}
- private TypeMirror uncheckedUnwrappedValueType() {
- return MoreTypes.asDeclared(valueType()).getTypeArguments().get(0);
+ private XType uncheckedUnwrappedValueType() {
+ return unwrapType(valueType());
}
- /**
- * {@code true} if {@code type} is a {@link Map} type.
- */
- public static boolean isMap(TypeMirror type) {
- return MoreTypes.isType(type) && MoreTypes.isTypeOf(Map.class, type);
+ /** {@code true} if {@code type} is a {@link java.util.Map} type. */
+ public static boolean isMap(XType type) {
+ return isTypeOf(type, TypeNames.MAP);
}
- /**
- * {@code true} if {@code key.type()} is a {@link Map} type.
- */
+ /** {@code true} if {@code key.type()} is a {@link java.util.Map} type. */
public static boolean isMap(Key key) {
- return isMap(key.type());
+ return isMap(key.type().xprocessing());
}
/**
* Returns a {@link MapType} for {@code type}.
*
- * @throws IllegalArgumentException if {@code type} is not a {@link Map} type
+ * @throws IllegalArgumentException if {@code type} is not a {@link java.util.Map} type
*/
- public static MapType from(TypeMirror type) {
+ public static MapType from(XType type) {
checkArgument(isMap(type), "%s is not a Map", type);
- return new AutoValue_MapType(MoreTypes.equivalence().wrap(MoreTypes.asDeclared(type)));
+ MapType mapType = new AutoValue_MapType(type.getTypeName());
+ mapType.type = type;
+ return mapType;
}
/**
* Returns a {@link MapType} for {@code key}'s {@link Key#type() type}.
*
- * @throws IllegalArgumentException if {@code key.type()} is not a {@link Map} type
+ * @throws IllegalArgumentException if {@code key.type()} is not a {@link java.util.Map} type
*/
public static MapType from(Key key) {
- return from(key.type());
+ return from(key.type().xprocessing());
}
}
diff --git a/java/dagger/internal/codegen/base/ModuleAnnotation.java b/java/dagger/internal/codegen/base/ModuleAnnotation.java
index 168873682..faca1d395 100644
--- a/java/dagger/internal/codegen/base/ModuleAnnotation.java
+++ b/java/dagger/internal/codegen/base/ModuleAnnotation.java
@@ -16,40 +16,42 @@
package dagger.internal.codegen.base;
-import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
-import static com.google.auto.common.MoreTypes.asTypeElement;
import static com.google.common.base.Preconditions.checkArgument;
-import static dagger.internal.codegen.base.MoreAnnotationValues.asAnnotationValues;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnyAnnotation;
+import static dagger.internal.codegen.xprocessing.XAnnotations.getClassName;
+import static dagger.internal.codegen.xprocessing.XElements.getAnyAnnotation;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import dagger.Module;
-import dagger.producers.ProducerModule;
-import java.lang.annotation.Annotation;
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.javapoet.TypeNames;
import java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.TypeElement;
/** A {@code @Module} or {@code @ProducerModule} annotation. */
@AutoValue
public abstract class ModuleAnnotation {
- private static final ImmutableSet<Class<? extends Annotation>> MODULE_ANNOTATIONS =
- ImmutableSet.of(Module.class, ProducerModule.class);
+ private static final ImmutableSet<ClassName> MODULE_ANNOTATIONS =
+ ImmutableSet.of(TypeNames.MODULE, TypeNames.PRODUCER_MODULE);
+
+ private XAnnotation annotation;
/** The annotation itself. */
- // This does not use AnnotationMirrors.equivalence() because we want the actual annotation
- // instance.
- public abstract AnnotationMirror annotation();
+ public final XAnnotation annotation() {
+ return annotation;
+ }
+
+ /** Returns the {@link ClassName} name of the annotation. */
+ public abstract ClassName className();
/** The simple name of the annotation. */
- public String annotationName() {
- return annotation().getAnnotationType().asElement().getSimpleName().toString();
+ public String simpleName() {
+ return className().simpleName();
}
/**
@@ -58,70 +60,55 @@ public abstract class ModuleAnnotation {
* @throws IllegalArgumentException if any of the values are error types
*/
@Memoized
- public ImmutableList<TypeElement> includes() {
- return includesAsAnnotationValues().stream()
- .map(MoreAnnotationValues::asType)
- .map(MoreTypes::asTypeElement)
+ public ImmutableList<XTypeElement> includes() {
+ return annotation.getAsTypeList("includes").stream()
+ .map(XType::getTypeElement)
.collect(toImmutableList());
}
- /** The values specified in the {@code includes} attribute. */
- @Memoized
- public ImmutableList<AnnotationValue> includesAsAnnotationValues() {
- return asAnnotationValues(getAnnotationValue(annotation(), "includes"));
- }
-
/**
* The types specified in the {@code subcomponents} attribute.
*
* @throws IllegalArgumentException if any of the values are error types
*/
@Memoized
- public ImmutableList<TypeElement> subcomponents() {
- return subcomponentsAsAnnotationValues().stream()
- .map(MoreAnnotationValues::asType)
- .map(MoreTypes::asTypeElement)
+ public ImmutableList<XTypeElement> subcomponents() {
+ return annotation.getAsTypeList("subcomponents").stream()
+ .map(XType::getTypeElement)
.collect(toImmutableList());
}
- /** The values specified in the {@code subcomponents} attribute. */
- @Memoized
- public ImmutableList<AnnotationValue> subcomponentsAsAnnotationValues() {
- return asAnnotationValues(getAnnotationValue(annotation(), "subcomponents"));
- }
-
/** Returns {@code true} if the argument is a {@code @Module} or {@code @ProducerModule}. */
- public static boolean isModuleAnnotation(AnnotationMirror annotation) {
- return MODULE_ANNOTATIONS.stream()
- .map(Class::getCanonicalName)
- .anyMatch(asTypeElement(annotation.getAnnotationType()).getQualifiedName()::contentEquals);
+ public static boolean isModuleAnnotation(XAnnotation annotation) {
+ return MODULE_ANNOTATIONS.contains(getClassName(annotation));
}
/** The module annotation types. */
- public static ImmutableSet<Class<? extends Annotation>> moduleAnnotations() {
+ public static ImmutableSet<ClassName> moduleAnnotations() {
return MODULE_ANNOTATIONS;
}
- /**
- * Creates an object that represents a {@code @Module} or {@code @ProducerModule}.
- *
- * @throws IllegalArgumentException if {@link #isModuleAnnotation(AnnotationMirror)} returns
- * {@code false}
- */
- public static ModuleAnnotation moduleAnnotation(AnnotationMirror annotation) {
+ private static ModuleAnnotation create(XAnnotation annotation) {
checkArgument(
isModuleAnnotation(annotation),
"%s is not a Module or ProducerModule annotation",
annotation);
- return new AutoValue_ModuleAnnotation(annotation);
+ ModuleAnnotation moduleAnnotation = new AutoValue_ModuleAnnotation(getClassName(annotation));
+ moduleAnnotation.annotation = annotation;
+ return moduleAnnotation;
}
/**
* Returns an object representing the {@code @Module} or {@code @ProducerModule} annotation if one
* annotates {@code typeElement}.
*/
- public static Optional<ModuleAnnotation> moduleAnnotation(TypeElement typeElement) {
- return getAnyAnnotation(typeElement, Module.class, ProducerModule.class)
- .map(ModuleAnnotation::moduleAnnotation);
+ public static Optional<ModuleAnnotation> moduleAnnotation(
+ XElement element, DaggerSuperficialValidation superficialValidation) {
+ return getAnyAnnotation(element, TypeNames.MODULE, TypeNames.PRODUCER_MODULE)
+ .map(
+ annotation -> {
+ superficialValidation.validateAnnotationOf(element, annotation);
+ return create(annotation);
+ });
}
}
diff --git a/java/dagger/internal/codegen/binding/ModuleKind.java b/java/dagger/internal/codegen/base/ModuleKind.java
index 6b52f049e..7d08aee92 100644
--- a/java/dagger/internal/codegen/binding/ModuleKind.java
+++ b/java/dagger/internal/codegen/base/ModuleKind.java
@@ -14,36 +14,31 @@
* limitations under the License.
*/
-package dagger.internal.codegen.binding;
+package dagger.internal.codegen.base;
-import static com.google.auto.common.MoreElements.asType;
import static com.google.common.base.Preconditions.checkArgument;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
-import dagger.Module;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.producers.ProducerModule;
-import java.lang.annotation.Annotation;
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.javapoet.TypeNames;
import java.util.EnumSet;
import java.util.Optional;
import java.util.Set;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.TypeElement;
/** Enumeration of the kinds of modules. */
public enum ModuleKind {
/** {@code @Module} */
- MODULE(Module.class),
+ MODULE(TypeNames.MODULE),
/** {@code @ProducerModule} */
- PRODUCER_MODULE(ProducerModule.class);
+ PRODUCER_MODULE(TypeNames.PRODUCER_MODULE);
/** Returns the annotations for modules of the given kinds. */
- public static ImmutableSet<Class<? extends Annotation>> annotationsFor(Set<ModuleKind> kinds) {
+ private static ImmutableSet<ClassName> annotationsFor(Set<ModuleKind> kinds) {
return kinds.stream().map(ModuleKind::annotation).collect(toImmutableSet());
}
@@ -54,10 +49,10 @@ public enum ModuleKind {
* @throws IllegalArgumentException if the element is annotated with more than one of the module
* annotations
*/
- public static Optional<ModuleKind> forAnnotatedElement(TypeElement element) {
+ public static Optional<ModuleKind> forAnnotatedElement(XTypeElement element) {
Set<ModuleKind> kinds = EnumSet.noneOf(ModuleKind.class);
for (ModuleKind kind : values()) {
- if (MoreElements.isAnnotationPresent(element, kind.annotation())) {
+ if (element.hasAnnotation(kind.annotation())) {
kinds.add(kind);
}
}
@@ -69,19 +64,19 @@ public enum ModuleKind {
return kinds.stream().findAny();
}
- public static void checkIsModule(TypeElement moduleElement, KotlinMetadataUtil metadataUtil) {
+ public static void checkIsModule(XTypeElement moduleElement) {
// If the type element is a Kotlin companion object, then assert it is a module if its enclosing
// type is a module.
- if (metadataUtil.isCompanionObjectClass(moduleElement)) {
- checkArgument(forAnnotatedElement(asType(moduleElement.getEnclosingElement())).isPresent());
+ if (moduleElement.isCompanionObject()) {
+ checkArgument(forAnnotatedElement(moduleElement.getEnclosingTypeElement()).isPresent());
} else {
checkArgument(forAnnotatedElement(moduleElement).isPresent());
}
}
- private final Class<? extends Annotation> moduleAnnotation;
+ private final ClassName moduleAnnotation;
- ModuleKind(Class<? extends Annotation> moduleAnnotation) {
+ ModuleKind(ClassName moduleAnnotation) {
this.moduleAnnotation = moduleAnnotation;
}
@@ -90,15 +85,17 @@ public enum ModuleKind {
*
* @throws IllegalArgumentException if the annotation is not present on the type
*/
- public AnnotationMirror getModuleAnnotation(TypeElement element) {
- Optional<AnnotationMirror> result = getAnnotationMirror(element, moduleAnnotation);
+ public XAnnotation getModuleAnnotation(XTypeElement element) {
checkArgument(
- result.isPresent(), "annotation %s is not present on type %s", moduleAnnotation, element);
- return result.get();
+ element.hasAnnotation(moduleAnnotation),
+ "annotation %s is not present on type %s",
+ moduleAnnotation,
+ element);
+ return element.getAnnotation(moduleAnnotation);
}
/** Returns the annotation that marks a module of this kind. */
- public Class<? extends Annotation> annotation() {
+ public ClassName annotation() {
return moduleAnnotation;
}
diff --git a/java/dagger/internal/codegen/base/MoreAnnotationMirrors.java b/java/dagger/internal/codegen/base/MoreAnnotationMirrors.java
index 234ecc10e..708b9dc39 100644
--- a/java/dagger/internal/codegen/base/MoreAnnotationMirrors.java
+++ b/java/dagger/internal/codegen/base/MoreAnnotationMirrors.java
@@ -16,24 +16,16 @@
package dagger.internal.codegen.base;
-import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
-import static dagger.internal.codegen.base.MoreAnnotationValues.asAnnotationValues;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-
import com.google.auto.common.AnnotationMirrors;
import com.google.common.base.Equivalence;
-import com.google.common.collect.ImmutableList;
import java.util.Optional;
import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Name;
-import javax.lang.model.type.TypeMirror;
/**
* A utility class for working with {@link AnnotationMirror} instances, similar to {@link
* AnnotationMirrors}.
*/
public final class MoreAnnotationMirrors {
-
private MoreAnnotationMirrors() {}
/**
@@ -53,21 +45,4 @@ public final class MoreAnnotationMirrors {
Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedOptional) {
return wrappedOptional.map(Equivalence.Wrapper::get);
}
-
- public static Name simpleName(AnnotationMirror annotationMirror) {
- return annotationMirror.getAnnotationType().asElement().getSimpleName();
- }
-
- /**
- * Returns the list of types that is the value named {@code name} from {@code annotationMirror}.
- *
- * @throws IllegalArgumentException unless that member represents an array of types
- */
- public static ImmutableList<TypeMirror> getTypeListValue(
- AnnotationMirror annotationMirror, String name) {
- return asAnnotationValues(getAnnotationValue(annotationMirror, name))
- .stream()
- .map(MoreAnnotationValues::asType)
- .collect(toImmutableList());
- }
}
diff --git a/java/dagger/internal/codegen/base/MoreAnnotationValues.java b/java/dagger/internal/codegen/base/MoreAnnotationValues.java
index 1ee50da11..26175b88d 100644
--- a/java/dagger/internal/codegen/base/MoreAnnotationValues.java
+++ b/java/dagger/internal/codegen/base/MoreAnnotationValues.java
@@ -25,7 +25,6 @@ import java.util.Optional;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.AnnotationValueVisitor;
-import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.SimpleAnnotationValueVisitor8;
/** Utility methods for working with {@link AnnotationValue} instances. */
@@ -54,28 +53,6 @@ public final class MoreAnnotationValues {
}
};
- /**
- * Returns the type represented by an annotation value.
- *
- * @throws IllegalArgumentException unless {@code annotationValue} represents a single type
- */
- public static TypeMirror asType(AnnotationValue annotationValue) {
- return AS_TYPE.visit(annotationValue);
- }
-
- private static final AnnotationValueVisitor<TypeMirror, Void> AS_TYPE =
- new SimpleAnnotationValueVisitor8<TypeMirror, Void>() {
- @Override
- public TypeMirror visitType(TypeMirror t, Void p) {
- return t;
- }
-
- @Override
- protected TypeMirror defaultAction(Object o, Void p) {
- throw new TypeNotPresentException(o.toString(), null);
- }
- };
-
/** Returns the int value of an annotation */
public static int getIntValue(AnnotationMirror annotation, String valueName) {
return (int) getAnnotationValue(annotation, valueName).getValue();
diff --git a/java/dagger/internal/codegen/base/MultibindingAnnotations.java b/java/dagger/internal/codegen/base/MultibindingAnnotations.java
deleted file mode 100644
index 424f92a20..000000000
--- a/java/dagger/internal/codegen/base/MultibindingAnnotations.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2016 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.base;
-
-import static dagger.internal.codegen.langmodel.DaggerElements.getAllAnnotations;
-
-import com.google.common.collect.ImmutableSet;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.IntoSet;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-
-/**
- * Utility methods related to processing {@link IntoSet}, {@link ElementsIntoSet}, and {@link
- * IntoMap}.
- */
-public final class MultibindingAnnotations {
- public static ImmutableSet<AnnotationMirror> forElement(Element method) {
- return getAllAnnotations(method, IntoSet.class, ElementsIntoSet.class, IntoMap.class);
- }
-}
diff --git a/java/dagger/internal/codegen/base/OptionalType.java b/java/dagger/internal/codegen/base/OptionalType.java
index 15056828e..d4f3c0536 100644
--- a/java/dagger/internal/codegen/base/OptionalType.java
+++ b/java/dagger/internal/codegen/base/OptionalType.java
@@ -17,22 +17,21 @@
package dagger.internal.codegen.base;
import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
+import static dagger.internal.codegen.extension.DaggerStreams.valuesOf;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
-import com.google.common.base.Equivalence;
+import com.google.common.collect.ImmutableMap;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
-import dagger.model.Key;
-import java.util.Optional;
-import javax.lang.model.element.Name;
-import javax.lang.model.type.DeclaredType;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.spi.model.Key;
import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVisitor;
-import javax.lang.model.util.SimpleTypeVisitor8;
/**
* Information about an {@code Optional} {@link TypeMirror}.
@@ -41,44 +40,58 @@ import javax.lang.model.util.SimpleTypeVisitor8;
*/
@AutoValue
public abstract class OptionalType {
+ private XType type;
/** A variant of {@code Optional}. */
public enum OptionalKind {
/** {@link com.google.common.base.Optional}. */
- GUAVA_OPTIONAL(com.google.common.base.Optional.class, "absent"),
+ GUAVA_OPTIONAL(TypeNames.GUAVA_OPTIONAL, "absent"),
/** {@link java.util.Optional}. */
- JDK_OPTIONAL(java.util.Optional.class, "empty"),
- ;
+ JDK_OPTIONAL(TypeNames.JDK_OPTIONAL, "empty");
- private final Class<?> clazz;
- private final String absentFactoryMethodName;
+ // Keep a cache from class name to OptionalKind for quick look-up.
+ private static final ImmutableMap<ClassName, OptionalKind> OPTIONAL_KIND_BY_CLASS_NAME =
+ valuesOf(OptionalKind.class)
+ .collect(toImmutableMap(value -> value.className, value -> value));
- OptionalKind(Class<?> clazz, String absentFactoryMethodName) {
- this.clazz = clazz;
- this.absentFactoryMethodName = absentFactoryMethodName;
+ private final ClassName className;
+ private final String absentMethodName;
+
+ OptionalKind(ClassName className, String absentMethodName) {
+ this.className = className;
+ this.absentMethodName = absentMethodName;
+ }
+
+ private static boolean isOptionalKind(XTypeElement type) {
+ return OPTIONAL_KIND_BY_CLASS_NAME.containsKey(type.getClassName());
+ }
+
+ private static OptionalKind of(XTypeElement type) {
+ return OPTIONAL_KIND_BY_CLASS_NAME.get(type.getClassName());
}
/** Returns {@code valueType} wrapped in the correct class. */
public ParameterizedTypeName of(TypeName valueType) {
- return ParameterizedTypeName.get(ClassName.get(clazz), valueType);
+ return ParameterizedTypeName.get(className, valueType);
}
/** Returns an expression for the absent/empty value. */
public CodeBlock absentValueExpression() {
- return CodeBlock.of("$T.$L()", clazz, absentFactoryMethodName);
+ return CodeBlock.of("$T.$L()", className, absentMethodName);
}
/**
* Returns an expression for the absent/empty value, parameterized with {@link #valueType()}.
*/
public CodeBlock parameterizedAbsentValueExpression(OptionalType optionalType) {
- return CodeBlock.of("$T.<$T>$L()", clazz, optionalType.valueType(), absentFactoryMethodName);
+ return CodeBlock.of(
+ "$T.<$T>$L()", className, optionalType.valueType().getTypeName(), absentMethodName);
}
/** Returns an expression for the present {@code value}. */
public CodeBlock presentExpression(CodeBlock value) {
- return CodeBlock.of("$T.of($L)", clazz, value);
+ return CodeBlock.of("$T.of($L)", className, value);
}
/**
@@ -86,56 +99,36 @@ public abstract class OptionalType {
* matter what type the value is.
*/
public CodeBlock presentObjectExpression(CodeBlock value) {
- return CodeBlock.of("$T.<$T>of($L)", clazz, Object.class, value);
+ return CodeBlock.of("$T.<$T>of($L)", className, TypeName.OBJECT, value);
}
}
- private static final TypeVisitor<Optional<OptionalKind>, Void> OPTIONAL_KIND =
- new SimpleTypeVisitor8<Optional<OptionalKind>, Void>(Optional.empty()) {
- @Override
- public Optional<OptionalKind> visitDeclared(DeclaredType t, Void p) {
- for (OptionalKind optionalKind : OptionalKind.values()) {
- Name qualifiedName = MoreElements.asType(t.asElement()).getQualifiedName();
- if (qualifiedName.contentEquals(optionalKind.clazz.getCanonicalName())) {
- return Optional.of(optionalKind);
- }
- }
- return Optional.empty();
- }
- };
-
- /**
- * The optional type itself, wrapped using {@link MoreTypes#equivalence()}.
- *
- * @deprecated Use {@link #declaredOptionalType()} instead.
- */
- @Deprecated
- protected abstract Equivalence.Wrapper<DeclaredType> wrappedDeclaredOptionalType();
+ /** The optional type itself. */
+ abstract TypeName typeName();
/** The optional type itself. */
- @SuppressWarnings("deprecation")
- private DeclaredType declaredOptionalType() {
- return wrappedDeclaredOptionalType().get();
+ private XType type() {
+ return type;
}
/** Which {@code Optional} type is used. */
public OptionalKind kind() {
- return declaredOptionalType().accept(OPTIONAL_KIND, null).get();
+ return OptionalKind.of(type().getTypeElement());
}
/** The value type. */
- public TypeMirror valueType() {
- return declaredOptionalType().getTypeArguments().get(0);
+ public XType valueType() {
+ return type().getTypeArguments().get(0);
}
/** Returns {@code true} if {@code type} is an {@code Optional} type. */
- private static boolean isOptional(TypeMirror type) {
- return type.accept(OPTIONAL_KIND, null).isPresent();
+ private static boolean isOptional(XType type) {
+ return isDeclared(type) && OptionalKind.isOptionalKind(type.getTypeElement());
}
/** Returns {@code true} if {@code key.type()} is an {@code Optional} type. */
public static boolean isOptional(Key key) {
- return isOptional(key.type());
+ return isOptional(key.type().xprocessing());
}
/**
@@ -143,9 +136,11 @@ public abstract class OptionalType {
*
* @throws IllegalArgumentException if {@code type} is not an {@code Optional} type
*/
- public static OptionalType from(TypeMirror type) {
+ public static OptionalType from(XType type) {
checkArgument(isOptional(type), "%s must be an Optional", type);
- return new AutoValue_OptionalType(MoreTypes.equivalence().wrap(MoreTypes.asDeclared(type)));
+ OptionalType optionalType = new AutoValue_OptionalType(type.getTypeName());
+ optionalType.type = type;
+ return optionalType;
}
/**
@@ -154,6 +149,6 @@ public abstract class OptionalType {
* @throws IllegalArgumentException if {@code key.type()} is not an {@code Optional} type
*/
public static OptionalType from(Key key) {
- return from(key.type());
+ return from(key.type().xprocessing());
}
}
diff --git a/java/dagger/internal/codegen/base/ProducerAnnotations.java b/java/dagger/internal/codegen/base/ProducerAnnotations.java
new file mode 100644
index 000000000..ad3b9b39f
--- /dev/null
+++ b/java/dagger/internal/codegen/base/ProducerAnnotations.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.base;
+
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XProcessingEnv;
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.javapoet.TypeNames;
+
+/**
+ * Helper methods for getting types of producer annotations.
+ *
+ * <p>Note:These should only be used for cases where the annotations don't exist in the user's code.
+ * For example, all producer components implicitly have {@code @ProductionScope}, but it doesn't
+ * appear in the user's code. We need to get a reference to the scope annotation though to reuse
+ * classes from regular Dagger like the {@code ComponentDescriptor}.
+ */
+public final class ProducerAnnotations {
+ private static final ClassName ANNOTATION_USAGES =
+ ClassName.get("dagger.producers.internal", "AnnotationUsages");
+ private static final ClassName PRODUCTION_USAGE =
+ ANNOTATION_USAGES.nestedClass("ProductionUsage");
+ private static final ClassName PRODUCTION_IMPLEMENTATION_USAGE =
+ ANNOTATION_USAGES.nestedClass("ProductionImplementationUsage");
+ private static final ClassName PRODUCTION_SCOPE_USAGE =
+ ANNOTATION_USAGES.nestedClass("ProductionScopeUsage");
+
+ /** Returns a {@link dagger.producers.internal.ProductionImplementation} qualifier. */
+ // TODO(bcorso): We could probably remove the need for this if we define a new type,
+ // "ProductionImplementationExecutor", rather than binding "@ProductionImplementation Executor".
+ public static XAnnotation productionImplementationQualifier(XProcessingEnv processingEnv) {
+ return processingEnv.findTypeElement(PRODUCTION_IMPLEMENTATION_USAGE)
+ .getAnnotation(TypeNames.PRODUCTION_IMPLEMENTATION);
+ }
+
+ /** Returns a {@link dagger.producers.Production} qualifier. */
+ // TODO(bcorso): We could probably remove the need for this. It's currently only used in
+ // "DependsOnProductionExecutorValidator", but we could implement that without this.
+ public static XAnnotation productionQualifier(XProcessingEnv processingEnv) {
+ return processingEnv.findTypeElement(PRODUCTION_USAGE).getAnnotation(TypeNames.PRODUCTION);
+ }
+
+ /** Returns a {@link dagger.producers.ProductionScope} scope. */
+ // TODO(bcorso): We could probably remove the need for this, but it would require changing
+ // Dagger SPI's public API. In particular, Scope should probably only require a ClassName rather
+ // than an actual annotation type.
+ public static XAnnotation productionScope(XProcessingEnv processingEnv) {
+ return processingEnv.findTypeElement(PRODUCTION_SCOPE_USAGE)
+ .getAnnotation(TypeNames.PRODUCTION_SCOPE);
+ }
+
+ private ProducerAnnotations() {}
+}
diff --git a/java/dagger/internal/codegen/base/RequestKinds.java b/java/dagger/internal/codegen/base/RequestKinds.java
index 95d5ef4f9..b4a17647f 100644
--- a/java/dagger/internal/codegen/base/RequestKinds.java
+++ b/java/dagger/internal/codegen/base/RequestKinds.java
@@ -16,9 +16,9 @@
package dagger.internal.codegen.base;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.auto.common.MoreTypes.asDeclared;
import static com.google.auto.common.MoreTypes.isType;
-import static com.google.auto.common.MoreTypes.isTypeOf;
import static com.google.common.base.Preconditions.checkArgument;
import static dagger.internal.codegen.javapoet.TypeNames.lazyOf;
import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf;
@@ -26,22 +26,22 @@ import static dagger.internal.codegen.javapoet.TypeNames.producedOf;
import static dagger.internal.codegen.javapoet.TypeNames.producerOf;
import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
import static dagger.internal.codegen.langmodel.DaggerTypes.checkTypePresent;
-import static dagger.model.RequestKind.LAZY;
-import static dagger.model.RequestKind.PRODUCED;
-import static dagger.model.RequestKind.PRODUCER;
-import static dagger.model.RequestKind.PROVIDER;
-import static dagger.model.RequestKind.PROVIDER_OF_LAZY;
+import static dagger.internal.codegen.langmodel.DaggerTypes.isTypeOf;
+import static dagger.internal.codegen.langmodel.DaggerTypes.unwrapType;
+import static dagger.spi.model.RequestKind.LAZY;
+import static dagger.spi.model.RequestKind.PRODUCED;
+import static dagger.spi.model.RequestKind.PRODUCER;
+import static dagger.spi.model.RequestKind.PROVIDER;
+import static dagger.spi.model.RequestKind.PROVIDER_OF_LAZY;
import static javax.lang.model.type.TypeKind.DECLARED;
+import androidx.room.compiler.processing.XType;
import com.google.common.collect.ImmutableMap;
-import com.google.common.util.concurrent.ListenableFuture;
+import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeName;
-import dagger.Lazy;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.RequestKind;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import javax.inject.Provider;
+import dagger.spi.model.RequestKind;
import javax.lang.model.type.TypeMirror;
/** Utility methods for {@link RequestKind}s. */
@@ -55,13 +55,13 @@ public final class RequestKinds {
return type;
case PROVIDER_OF_LAZY:
- return types.wrapType(requestType(LAZY, type, types), Provider.class);
+ return types.wrapType(requestType(LAZY, type, types), TypeNames.PROVIDER);
case FUTURE:
- return types.wrapType(type, ListenableFuture.class);
+ return types.wrapType(type, TypeNames.LISTENABLE_FUTURE);
default:
- return types.wrapType(type, frameworkClass(requestKind));
+ return types.wrapType(type, frameworkClassName(requestKind));
}
}
@@ -94,12 +94,17 @@ public final class RequestKinds {
}
}
- private static final ImmutableMap<RequestKind, Class<?>> FRAMEWORK_CLASSES =
+ private static final ImmutableMap<RequestKind, ClassName> FRAMEWORK_CLASSES =
ImmutableMap.of(
- PROVIDER, Provider.class,
- LAZY, Lazy.class,
- PRODUCER, Producer.class,
- PRODUCED, Produced.class);
+ PROVIDER, TypeNames.PROVIDER,
+ LAZY, TypeNames.LAZY,
+ PRODUCER, TypeNames.PRODUCER,
+ PRODUCED, TypeNames.PRODUCED);
+
+ /** Returns the {@link RequestKind} that matches the wrapping types (if any) of {@code type}. */
+ public static RequestKind getRequestKind(XType type) {
+ return getRequestKind(toJavac(type));
+ }
/** Returns the {@link RequestKind} that matches the wrapping types (if any) of {@code type}. */
public static RequestKind getRequestKind(TypeMirror type) {
@@ -112,8 +117,8 @@ public final class RequestKinds {
return RequestKind.INSTANCE;
}
for (RequestKind kind : FRAMEWORK_CLASSES.keySet()) {
- if (isTypeOf(frameworkClass(kind), type)) {
- if (kind.equals(PROVIDER) && getRequestKind(DaggerTypes.unwrapType(type)).equals(LAZY)) {
+ if (isTypeOf(frameworkClassName(kind), type)) {
+ if (kind.equals(PROVIDER) && getRequestKind(unwrapType(type)).equals(LAZY)) {
return PROVIDER_OF_LAZY;
}
return kind;
@@ -131,6 +136,30 @@ public final class RequestKinds {
* @throws IllegalArgumentException if {@code type} is not wrapped with {@code requestKind}'s
* framework class(es).
*/
+ public static XType extractKeyType(XType type) {
+ return extractKeyType(getRequestKind(type), type);
+ }
+
+ private static XType extractKeyType(RequestKind requestKind, XType type) {
+ switch (requestKind) {
+ case INSTANCE:
+ return type;
+ case PROVIDER_OF_LAZY:
+ return extractKeyType(LAZY, extractKeyType(PROVIDER, type));
+ default:
+ return unwrapType(type);
+ }
+ }
+
+ /**
+ * Unwraps the framework class(es) of {@code requestKind} from {@code type}. If {@code
+ * requestKind} is {@link RequestKind#INSTANCE}, this acts as an identity function.
+ *
+ * @throws TypeNotPresentException if {@code type} is an {@link javax.lang.model.type.ErrorType},
+ * which may mean that the type will be generated in a later round of processing
+ * @throws IllegalArgumentException if {@code type} is not wrapped with {@code requestKind}'s
+ * framework class(es).
+ */
public static TypeMirror extractKeyType(TypeMirror type) {
return extractKeyType(getRequestKind(type), type);
}
@@ -143,13 +172,13 @@ public final class RequestKinds {
return extractKeyType(LAZY, extractKeyType(PROVIDER, type));
default:
checkArgument(isType(type));
- return DaggerTypes.unwrapType(type);
+ return unwrapType(type);
}
}
/**
* A dagger- or {@code javax.inject}-defined class for {@code requestKind} that that can wrap
- * another type but share the same {@link dagger.model.Key}.
+ * another type but share the same {@link dagger.spi.model.Key}.
*
* <p>For example, {@code Provider<String>} and {@code Lazy<String>} can both be requested if a
* key exists for {@code String}; they all share the same key.
@@ -159,10 +188,10 @@ public final class RequestKinds {
* classes, and {@link RequestKind#FUTURE} is wrapped with a {@link ListenableFuture}, but for
* historical/implementation reasons has not had an associated framework class.
*/
- public static Class<?> frameworkClass(RequestKind requestKind) {
- Class<?> result = FRAMEWORK_CLASSES.get(requestKind);
- checkArgument(result != null, "no framework class for %s", requestKind);
- return result;
+ public static ClassName frameworkClassName(RequestKind requestKind) {
+ checkArgument(
+ FRAMEWORK_CLASSES.containsKey(requestKind), "no framework class for %s", requestKind);
+ return FRAMEWORK_CLASSES.get(requestKind);
}
/**
diff --git a/java/dagger/internal/codegen/base/Scopes.java b/java/dagger/internal/codegen/base/Scopes.java
index f2c39cea0..b4cc323f0 100644
--- a/java/dagger/internal/codegen/base/Scopes.java
+++ b/java/dagger/internal/codegen/base/Scopes.java
@@ -16,48 +16,17 @@
package dagger.internal.codegen.base;
-import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.base.DiagnosticFormatting.stripCommonTypePrefixes;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import com.google.auto.common.AnnotationMirrors;
-import com.google.common.collect.ImmutableSet;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.model.Scope;
-import dagger.producers.ProductionScope;
-import java.lang.annotation.Annotation;
-import java.util.Optional;
-import javax.inject.Singleton;
-import javax.lang.model.element.Element;
+import androidx.room.compiler.processing.XProcessingEnv;
+import dagger.spi.model.DaggerAnnotation;
+import dagger.spi.model.Scope;
/** Common names and convenience methods for {@link Scope}s. */
public final class Scopes {
-
- /** Returns a representation for {@link ProductionScope @ProductionScope} scope. */
- public static Scope productionScope(DaggerElements elements) {
- return scope(elements, ProductionScope.class);
- }
-
- /** Returns a representation for {@link Singleton @Singleton} scope. */
- public static Scope singletonScope(DaggerElements elements) {
- return scope(elements, Singleton.class);
- }
-
- /**
- * Creates a {@link Scope} object from the {@link javax.inject.Scope}-annotated annotation type.
- */
- private static Scope scope(
- DaggerElements elements, Class<? extends Annotation> scopeAnnotationClass) {
- return Scope.scope(SimpleAnnotationMirror.of(elements.getTypeElement(scopeAnnotationClass)));
- }
-
- /**
- * Returns at most one associated scoped annotation from the source code element, throwing an
- * exception if there are more than one.
- */
- public static Optional<Scope> uniqueScopeOf(Element element) {
- // TODO(ronshapiro): Use MoreCollectors.toOptional() once we can use guava-jre
- return Optional.ofNullable(getOnlyElement(scopesOf(element), null));
+ /** Returns a representation for {@link dagger.producers.ProductionScope} scope. */
+ public static Scope productionScope(XProcessingEnv processingEnv) {
+ return Scope.scope(DaggerAnnotation.from(ProducerAnnotations.productionScope(processingEnv)));
}
/**
@@ -69,12 +38,4 @@ public final class Scopes {
public static String getReadableSource(Scope scope) {
return stripCommonTypePrefixes(scope.toString());
}
-
- /** Returns all of the associated scopes for a source code element. */
- public static ImmutableSet<Scope> scopesOf(Element element) {
- return AnnotationMirrors.getAnnotatedAnnotations(element, javax.inject.Scope.class)
- .stream()
- .map(Scope::scope)
- .collect(toImmutableSet());
- }
}
diff --git a/java/dagger/internal/codegen/base/SetType.java b/java/dagger/internal/codegen/base/SetType.java
index a75a6d316..54d4228e4 100644
--- a/java/dagger/internal/codegen/base/SetType.java
+++ b/java/dagger/internal/codegen/base/SetType.java
@@ -16,105 +16,96 @@
package dagger.internal.codegen.base;
+import static com.google.auto.common.MoreTypes.isType;
import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.codegen.langmodel.DaggerTypes.isTypeOf;
+import static dagger.internal.codegen.langmodel.DaggerTypes.unwrapType;
+import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XType;
import com.google.auto.value.AutoValue;
-import com.google.common.base.Equivalence;
-import dagger.model.Key;
-import java.util.Set;
-import javax.lang.model.type.DeclaredType;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.spi.model.Key;
import javax.lang.model.type.TypeMirror;
-/**
- * Information about a {@link Set} {@link TypeMirror}.
- */
+/** Information about a {@link java.util.Set} {@link TypeMirror}. */
@AutoValue
public abstract class SetType {
- /**
- * The set type itself, wrapped using {@link MoreTypes#equivalence()}. Use
- * {@link #declaredSetType()} instead.
- */
- protected abstract Equivalence.Wrapper<DeclaredType> wrappedDeclaredSetType();
+ private XType type;
- /**
- * The set type itself.
- */
- private DeclaredType declaredSetType() {
- return wrappedDeclaredSetType().get();
+ /** The set type itself. */
+ abstract TypeName typeName();
+
+ /** The set type itself. */
+ private XType type() {
+ return type;
}
- /**
- * {@code true} if the set type is the raw {@link Set} type.
- */
+ /** {@code true} if the set type is the raw {@link java.util.Set} type. */
public boolean isRawType() {
- return declaredSetType().getTypeArguments().isEmpty();
+ return type().getTypeArguments().isEmpty();
}
- /**
- * The element type.
- */
- public TypeMirror elementType() {
- return declaredSetType().getTypeArguments().get(0);
+ /** Returns the element type. */
+ public XType elementType() {
+ return unwrapType(type());
}
- /**
- * {@code true} if {@link #elementType()} is a {@code clazz}.
- */
- public boolean elementsAreTypeOf(Class<?> clazz) {
- return MoreTypes.isType(elementType()) && MoreTypes.isTypeOf(clazz, elementType());
+ /** Returns {@code true} if {@link #elementType()} is of type {@code className}. */
+ public boolean elementsAreTypeOf(ClassName className) {
+ return !isRawType() && isTypeOf(elementType(), className);
}
/**
* {@code T} if {@link #elementType()} is a {@code WrappingClass<T>}.
*
* @throws IllegalStateException if {@link #elementType()} is not a {@code WrappingClass<T>}
- * @throws IllegalArgumentException if {@code wrappingClass} does not have exactly one type
- * parameter
*/
- public TypeMirror unwrappedElementType(Class<?> wrappingClass) {
- checkArgument(
- wrappingClass.getTypeParameters().length == 1,
- "%s must have exactly one type parameter",
- wrappingClass);
+ // TODO(b/202033221): Consider using stricter input type, e.g. FrameworkType.
+ public XType unwrappedElementType(ClassName wrappingClass) {
checkArgument(
elementsAreTypeOf(wrappingClass),
"expected elements to be %s, but this type is %s",
wrappingClass,
- declaredSetType());
- return MoreTypes.asDeclared(elementType()).getTypeArguments().get(0);
+ type());
+ return unwrapType(elementType());
}
- /**
- * {@code true} if {@code type} is a {@link Set} type.
- */
+ /** {@code true} if {@code type} is a {@link java.util.Set} type. */
+ public static boolean isSet(XType type) {
+ return isTypeOf(type, TypeNames.SET);
+ }
+
+ /** {@code true} if {@code type} is a {@link java.util.Set} type. */
public static boolean isSet(TypeMirror type) {
- return MoreTypes.isType(type) && MoreTypes.isTypeOf(Set.class, type);
+ return isType(type) && isTypeOf(TypeNames.SET, type);
}
- /**
- * {@code true} if {@code key.type()} is a {@link Set} type.
- */
+ /** {@code true} if {@code key.type()} is a {@link java.util.Set} type. */
public static boolean isSet(Key key) {
- return isSet(key.type());
+ return isSet(key.type().xprocessing());
}
/**
* Returns a {@link SetType} for {@code type}.
*
- * @throws IllegalArgumentException if {@code type} is not a {@link Set} type
+ * @throws IllegalArgumentException if {@code type} is not a {@link java.util.Set} type
*/
- public static SetType from(TypeMirror type) {
+ public static SetType from(XType type) {
checkArgument(isSet(type), "%s must be a Set", type);
- return new AutoValue_SetType(MoreTypes.equivalence().wrap(MoreTypes.asDeclared(type)));
+ SetType setType = new AutoValue_SetType(type.getTypeName());
+ setType.type = type;
+ return setType;
}
/**
* Returns a {@link SetType} for {@code key}'s {@link Key#type() type}.
*
- * @throws IllegalArgumentException if {@code key.type()} is not a {@link Set} type
+ * @throws IllegalArgumentException if {@code key.type()} is not a {@link java.util.Set} type
*/
public static SetType from(Key key) {
- return from (key.type());
+ return from(key.type().xprocessing());
}
}
diff --git a/java/dagger/internal/codegen/base/SimpleAnnotationMirror.java b/java/dagger/internal/codegen/base/SimpleAnnotationMirror.java
deleted file mode 100644
index 9690691eb..000000000
--- a/java/dagger/internal/codegen/base/SimpleAnnotationMirror.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2016 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.base;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.base.Functions;
-import com.google.common.base.Joiner;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import java.util.Map;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-
-/** A representation of an annotation. */
-public final class SimpleAnnotationMirror implements AnnotationMirror {
- private final TypeElement annotationType;
- private final ImmutableMap<String, ? extends AnnotationValue> namedValues;
- private final ImmutableMap<ExecutableElement, ? extends AnnotationValue> elementValues;
-
- private SimpleAnnotationMirror(
- TypeElement annotationType, Map<String, ? extends AnnotationValue> namedValues) {
- checkArgument(
- annotationType.getKind().equals(ElementKind.ANNOTATION_TYPE),
- "annotationType must be an annotation: %s",
- annotationType);
- checkArgument(
- FluentIterable.from(methodsIn(annotationType.getEnclosedElements()))
- .transform(element -> element.getSimpleName().toString())
- .toSet()
- .equals(namedValues.keySet()),
- "namedValues must have values for exactly the members in %s: %s",
- annotationType,
- namedValues);
- this.annotationType = annotationType;
- this.namedValues = ImmutableMap.copyOf(namedValues);
- this.elementValues =
- Maps.toMap(
- methodsIn(annotationType.getEnclosedElements()),
- Functions.compose(
- Functions.forMap(namedValues), element -> element.getSimpleName().toString()));
- }
-
- @Override
- public DeclaredType getAnnotationType() {
- return MoreTypes.asDeclared(annotationType.asType());
- }
-
- @Override
- public Map<ExecutableElement, ? extends AnnotationValue> getElementValues() {
- return elementValues;
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder("@").append(annotationType.getQualifiedName());
- if (!namedValues.isEmpty()) {
- builder
- .append('(')
- .append(Joiner.on(", ").withKeyValueSeparator(" = ").join(namedValues))
- .append(')');
- }
- return builder.toString();
- }
-
- /**
- * An object representing an annotation instance.
- *
- * @param annotationType must be an annotation type with no members
- */
- public static AnnotationMirror of(TypeElement annotationType) {
- return of(annotationType, ImmutableMap.<String, AnnotationValue>of());
- }
-
- /**
- * An object representing an annotation instance.
- *
- * @param annotationType must be an annotation type
- * @param namedValues a value for every annotation member, including those with defaults, indexed
- * by simple name
- */
- private static AnnotationMirror of(
- TypeElement annotationType, Map<String, ? extends AnnotationValue> namedValues) {
- return new SimpleAnnotationMirror(annotationType, namedValues);
- }
-}
diff --git a/java/dagger/internal/codegen/base/SimpleTypeAnnotationValue.java b/java/dagger/internal/codegen/base/SimpleTypeAnnotationValue.java
deleted file mode 100644
index d595bcb70..000000000
--- a/java/dagger/internal/codegen/base/SimpleTypeAnnotationValue.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.base;
-
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.AnnotationValueVisitor;
-import javax.lang.model.type.TypeMirror;
-
-/** An {@link AnnotationValue} that contains a {@link TypeMirror}. */
-final class SimpleTypeAnnotationValue implements AnnotationValue {
- private final TypeMirror value;
-
- SimpleTypeAnnotationValue(TypeMirror value) {
- this.value = value;
- }
-
- @Override
- public TypeMirror getValue() {
- return value;
- }
-
- @Override
- public String toString() {
- return value + ".class";
- }
-
- @Override
- public <R, P> R accept(AnnotationValueVisitor<R, P> visitor, P parameter) {
- return visitor.visitType(getValue(), parameter);
- }
-}
diff --git a/java/dagger/internal/codegen/base/SourceFileGenerationException.java b/java/dagger/internal/codegen/base/SourceFileGenerationException.java
index 5553dd85b..9ca72b835 100644
--- a/java/dagger/internal/codegen/base/SourceFileGenerationException.java
+++ b/java/dagger/internal/codegen/base/SourceFileGenerationException.java
@@ -19,10 +19,10 @@ package dagger.internal.codegen.base;
import static com.google.common.base.Preconditions.checkNotNull;
import static javax.tools.Diagnostic.Kind.ERROR;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XMessager;
import com.squareup.javapoet.ClassName;
import java.util.Optional;
-import javax.annotation.processing.Messager;
-import javax.lang.model.element.Element;
/**
* An exception thrown to indicate that a source file could not be generated.
@@ -32,10 +32,10 @@ import javax.lang.model.element.Element;
* for that.
*/
public final class SourceFileGenerationException extends Exception {
- private final Element associatedElement;
+ private final XElement associatedElement;
SourceFileGenerationException(
- Optional<ClassName> generatedClassName, Throwable cause, Element associatedElement) {
+ Optional<ClassName> generatedClassName, Throwable cause, XElement associatedElement) {
super(createMessage(generatedClassName, cause.getMessage()), cause);
this.associatedElement = checkNotNull(associatedElement);
}
@@ -48,7 +48,7 @@ public final class SourceFileGenerationException extends Exception {
message);
}
- public void printMessageTo(Messager messager) {
+ public void printMessageTo(XMessager messager) {
messager.printMessage(ERROR, getMessage(), associatedElement);
}
}
diff --git a/java/dagger/internal/codegen/base/SourceFileGenerator.java b/java/dagger/internal/codegen/base/SourceFileGenerator.java
index ada67d30d..d55ac1113 100644
--- a/java/dagger/internal/codegen/base/SourceFileGenerator.java
+++ b/java/dagger/internal/codegen/base/SourceFileGenerator.java
@@ -16,12 +16,17 @@
package dagger.internal.codegen.base;
-
+import static androidx.room.compiler.processing.JavaPoetExtKt.addOriginatingElement;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.auto.common.GeneratedAnnotations.generatedAnnotation;
import static com.google.common.base.Preconditions.checkNotNull;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.compat.XConverters;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -34,10 +39,7 @@ import dagger.internal.codegen.javapoet.AnnotationSpecs;
import dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression;
import dagger.internal.codegen.langmodel.DaggerElements;
import java.util.Optional;
-import javax.annotation.processing.Filer;
-import javax.annotation.processing.Messager;
import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
/**
* A template class that provides a framework for properly handling IO while generating source files
@@ -49,11 +51,11 @@ import javax.lang.model.element.Element;
public abstract class SourceFileGenerator<T> {
private static final String GENERATED_COMMENTS = "https://dagger.dev";
- private final Filer filer;
+ private final XFiler filer;
private final DaggerElements elements;
private final SourceVersion sourceVersion;
- public SourceFileGenerator(Filer filer, DaggerElements elements, SourceVersion sourceVersion) {
+ public SourceFileGenerator(XFiler filer, DaggerElements elements, SourceVersion sourceVersion) {
this.filer = checkNotNull(filer);
this.elements = checkNotNull(elements);
this.sourceVersion = checkNotNull(sourceVersion);
@@ -67,7 +69,7 @@ public abstract class SourceFileGenerator<T> {
* Generates a source file to be compiled for {@code T}. Writes any generation exception to {@code
* messager} and does not throw.
*/
- public void generate(T input, Messager messager) {
+ public void generate(T input, XMessager messager) {
try {
generate(input);
} catch (SourceFileGenerationException e) {
@@ -79,7 +81,7 @@ public abstract class SourceFileGenerator<T> {
public void generate(T input) throws SourceFileGenerationException {
for (TypeSpec.Builder type : topLevelTypes(input)) {
try {
- buildJavaFile(input, type).writeTo(filer);
+ buildJavaFile(input, type).writeTo(XConverters.toJavac(filer));
} catch (Exception e) {
// if the code above threw a SFGE, use that
Throwables.propagateIfPossible(e, SourceFileGenerationException.class);
@@ -90,7 +92,7 @@ public abstract class SourceFileGenerator<T> {
}
private JavaFile buildJavaFile(T input, TypeSpec.Builder typeSpecBuilder) {
- typeSpecBuilder.addOriginatingElement(originatingElement(input));
+ addOriginatingElement(typeSpecBuilder, originatingElement(input));
typeSpecBuilder.addAnnotation(DaggerGenerated.class);
Optional<AnnotationSpec> generatedAnnotation =
generatedAnnotation(elements, sourceVersion)
@@ -112,7 +114,10 @@ public abstract class SourceFileGenerator<T> {
JavaFile.Builder javaFileBuilder =
JavaFile.builder(
- elements.getPackageOf(originatingElement(input)).getQualifiedName().toString(),
+ elements
+ .getPackageOf(toJavac(originatingElement(input)))
+ .getQualifiedName()
+ .toString(),
typeSpecBuilder.build())
.skipJavaLangImports(true);
if (!generatedAnnotation.isPresent()) {
@@ -122,7 +127,7 @@ public abstract class SourceFileGenerator<T> {
}
/** Returns the originating element of the generating type. */
- public abstract Element originatingElement(T input);
+ public abstract XElement originatingElement(T input);
/**
* Returns {@link TypeSpec.Builder types} be generated for {@code T}, or an empty list if no types
diff --git a/java/dagger/internal/codegen/base/TarjanSCCs.java b/java/dagger/internal/codegen/base/TarjanSCCs.java
new file mode 100644
index 000000000..ab9a0fdae
--- /dev/null
+++ b/java/dagger/internal/codegen/base/TarjanSCCs.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.base;
+
+import static com.google.common.base.Preconditions.checkState;
+import static java.lang.Math.min;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.graph.SuccessorsFunction;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An implementation of Tarjan's algorithm for finding the SCC of a graph. This is based on the
+ * psuedo code algorithm here:
+ * http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
+ */
+public final class TarjanSCCs {
+
+ /** Returns the set of strongly connected components in reverse topological order. */
+ public static <NodeT> ImmutableSet<ImmutableSet<NodeT>> compute(
+ ImmutableCollection<NodeT> nodes, SuccessorsFunction<NodeT> successorsFunction) {
+ return new TarjanSCC<>(nodes, successorsFunction).compute();
+ }
+
+ private static class TarjanSCC<NodeT> {
+ private final ImmutableCollection<NodeT> nodes;
+ private final SuccessorsFunction<NodeT> successorsFunction;
+ private final Deque<NodeT> stack;
+ private final Set<NodeT> onStack;
+ private final Map<NodeT, Integer> indexes;
+ private final Map<NodeT, Integer> lowLinks;
+ private final List<ImmutableSet<NodeT>> stronglyConnectedComponents = new ArrayList<>();
+
+ TarjanSCC(ImmutableCollection<NodeT> nodes, SuccessorsFunction<NodeT> successorsFunction) {
+ this.nodes = nodes;
+ this.successorsFunction = successorsFunction;
+ this.stack = new ArrayDeque<>(nodes.size());
+ this.onStack = Sets.newHashSetWithExpectedSize(nodes.size());
+ this.indexes = Maps.newHashMapWithExpectedSize(nodes.size());
+ this.lowLinks = Maps.newHashMapWithExpectedSize(nodes.size());
+ }
+
+ private ImmutableSet<ImmutableSet<NodeT>> compute() {
+ checkState(indexes.isEmpty(), "TarjanSCC#compute() can only be called once per instance!");
+ for (NodeT node : nodes) {
+ if (!indexes.containsKey(node)) {
+ stronglyConnect(node);
+ }
+ }
+ return ImmutableSet.copyOf(stronglyConnectedComponents);
+ }
+
+ private void stronglyConnect(NodeT node) {
+ // Set the index and lowLink for node to the smallest unused index and add it to the stack
+ lowLinks.put(node, indexes.size());
+ indexes.put(node, indexes.size());
+ stack.push(node);
+ onStack.add(node);
+
+ for (NodeT successor : successorsFunction.successors(node)) {
+ if (!indexes.containsKey(successor)) {
+ // Successor has not been processed.
+ stronglyConnect(successor);
+ lowLinks.put(node, min(lowLinks.get(node), lowLinks.get(successor)));
+ } else if (onStack.contains(successor)) {
+ // Successor is on the stack and hence in the current SCC.
+ lowLinks.put(node, min(lowLinks.get(node), indexes.get(successor)));
+ } else {
+ // Successor is not on the stack and hence in an already processed SCC, so ignore.
+ }
+ }
+
+ // If node is the root of the SCC, pop the stack until reaching the root to get all SCC nodes.
+ if (lowLinks.get(node).equals(indexes.get(node))) {
+ ImmutableSet.Builder<NodeT> scc = ImmutableSet.builder();
+ NodeT currNode;
+ do {
+ currNode = stack.pop();
+ onStack.remove(currNode);
+ scc.add(currNode);
+ } while (!node.equals(currNode));
+ stronglyConnectedComponents.add(scc.build());
+ }
+ }
+ }
+
+ private TarjanSCCs() {}
+}
diff --git a/java/dagger/internal/codegen/binding/AnnotationExpression.java b/java/dagger/internal/codegen/binding/AnnotationExpression.java
index de0aea586..82f282d9b 100644
--- a/java/dagger/internal/codegen/binding/AnnotationExpression.java
+++ b/java/dagger/internal/codegen/binding/AnnotationExpression.java
@@ -17,8 +17,10 @@
package dagger.internal.codegen.binding;
import static com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults;
+import static com.google.auto.common.MoreTypes.asArray;
import static dagger.internal.codegen.binding.SourceFiles.classFileName;
import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
+import static dagger.internal.codegen.javapoet.TypeNames.rawTypeName;
import static java.util.stream.Collectors.toList;
import com.google.auto.common.MoreElements;
@@ -26,17 +28,14 @@ import com.google.auto.common.MoreTypes;
import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.TypeName;
import java.util.List;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.SimpleAnnotationValueVisitor6;
-import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.SimpleAnnotationValueVisitor8;
/**
* Returns an expression creating an instance of the visited annotation type. Its parameter must be
@@ -50,7 +49,7 @@ import javax.lang.model.util.SimpleTypeVisitor6;
* but in code it would have to be {@code new int[] {1, 2, 3}}.
*/
public class AnnotationExpression
- extends SimpleAnnotationValueVisitor6<CodeBlock, AnnotationValue> {
+ extends SimpleAnnotationValueVisitor8<CodeBlock, AnnotationValue> {
private final AnnotationMirror annotation;
private final ClassName creatorClass;
@@ -104,7 +103,10 @@ public class AnnotationExpression
* annotation}.
*/
CodeBlock getValueExpression(TypeMirror valueType, AnnotationValue value) {
- return ARRAY_LITERAL_PREFIX.visit(valueType, this.visit(value, value));
+ CodeBlock codeBlock = visit(value, value);
+ return valueType.getKind() == TypeKind.ARRAY
+ ? CodeBlock.of("new $T[] $L", rawTypeName(asArray(valueType).getComponentType()), codeBlock)
+ : codeBlock;
}
@Override
@@ -170,39 +172,4 @@ public class AnnotationExpression
}
return CodeBlock.of("{$L}", makeParametersCodeBlock(codeBlocks.build()));
}
-
- /**
- * If the visited type is an array, prefixes the parameter code block with {@code new T[]}, where
- * {@code T} is the raw array component type.
- */
- private static final SimpleTypeVisitor6<CodeBlock, CodeBlock> ARRAY_LITERAL_PREFIX =
- new SimpleTypeVisitor6<CodeBlock, CodeBlock>() {
-
- @Override
- public CodeBlock visitArray(ArrayType t, CodeBlock p) {
- return CodeBlock.of("new $T[] $L", RAW_TYPE_NAME.visit(t.getComponentType()), p);
- }
-
- @Override
- protected CodeBlock defaultAction(TypeMirror e, CodeBlock p) {
- return p;
- }
- };
-
- /**
- * If the visited type is an array, returns the name of its raw component type; otherwise returns
- * the name of the type itself.
- */
- private static final SimpleTypeVisitor6<TypeName, Void> RAW_TYPE_NAME =
- new SimpleTypeVisitor6<TypeName, Void>() {
- @Override
- public TypeName visitDeclared(DeclaredType t, Void p) {
- return ClassName.get(MoreTypes.asTypeElement(t));
- }
-
- @Override
- protected TypeName defaultAction(TypeMirror e, Void p) {
- return TypeName.get(e);
- }
- };
}
diff --git a/java/dagger/internal/codegen/binding/AssistedInjectionAnnotations.java b/java/dagger/internal/codegen/binding/AssistedInjectionAnnotations.java
index f9929aef6..49ecd88e8 100644
--- a/java/dagger/internal/codegen/binding/AssistedInjectionAnnotations.java
+++ b/java/dagger/internal/codegen/binding/AssistedInjectionAnnotations.java
@@ -16,25 +16,28 @@
package dagger.internal.codegen.binding;
-import static com.google.auto.common.MoreElements.asExecutable;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.auto.common.MoreTypes.asExecutable;
-import static com.google.auto.common.MoreTypes.asTypeElement;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.base.MoreAnnotationValues.getStringValue;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.util.ElementFilter.constructorsIn;
-
+import static dagger.internal.codegen.langmodel.DaggerElements.isAnnotationPresent;
+import static dagger.internal.codegen.xprocessing.XElements.asConstructor;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static kotlin.streams.jdk8.StreamsKt.asStream;
+
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XConstructorType;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XHasModifiers;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XMethodType;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.XVariableElement;
import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.base.Equivalence;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -42,46 +45,36 @@ import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
-import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingKind;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.spi.model.BindingKind;
import java.util.List;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
+import java.util.Optional;
import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
/** Assisted injection utility methods. */
public final class AssistedInjectionAnnotations {
- /** Returns the factory method for the given factory {@link TypeElement}. */
- public static ExecutableElement assistedFactoryMethod(
- TypeElement factory, DaggerElements elements) {
- return getOnlyElement(assistedFactoryMethods(factory, elements));
+ /** Returns the factory method for the given factory {@link XTypeElement}. */
+ public static XMethodElement assistedFactoryMethod(XTypeElement factory) {
+ return getOnlyElement(assistedFactoryMethods(factory));
}
- /** Returns the list of abstract factory methods for the given factory {@link TypeElement}. */
- public static ImmutableSet<ExecutableElement> assistedFactoryMethods(
- TypeElement factory, DaggerElements elements) {
- return elements.getLocalAndInheritedMethods(factory).stream()
- .filter(method -> method.getModifiers().contains(ABSTRACT))
- .filter(method -> !method.isDefault())
+ /** Returns the list of abstract factory methods for the given factory {@link XTypeElement}. */
+ public static ImmutableSet<XMethodElement> assistedFactoryMethods(XTypeElement factory) {
+ return asStream(factory.getAllNonPrivateInstanceMethods())
+ .filter(XHasModifiers::isAbstract)
+ .filter(method -> !method.isJavaDefault())
.collect(toImmutableSet());
}
/** Returns {@code true} if the element uses assisted injection. */
- public static boolean isAssistedInjectionType(TypeElement typeElement) {
- ImmutableSet<ExecutableElement> injectConstructors = assistedInjectedConstructors(typeElement);
- return !injectConstructors.isEmpty()
- && isAnnotationPresent(getOnlyElement(injectConstructors), AssistedInject.class);
+ public static boolean isAssistedInjectionType(XTypeElement typeElement) {
+ return assistedInjectedConstructors(typeElement).stream()
+ .anyMatch(constructor -> constructor.hasAnnotation(TypeNames.ASSISTED_INJECT));
}
/** Returns {@code true} if this binding is an assisted factory. */
- public static boolean isAssistedFactoryType(Element element) {
- return isAnnotationPresent(element, AssistedFactory.class);
+ public static boolean isAssistedFactoryType(XElement element) {
+ return element.hasAnnotation(TypeNames.ASSISTED_FACTORY);
}
/**
@@ -91,25 +84,22 @@ public final class AssistedInjectionAnnotations {
* of each parameter will be the name given in the {@link
* dagger.assisted.AssistedInject}-annotated constructor.
*/
- public static ImmutableList<ParameterSpec> assistedParameterSpecs(
- Binding binding, DaggerTypes types) {
+ public static ImmutableList<ParameterSpec> assistedParameterSpecs(Binding binding) {
checkArgument(binding.kind() == BindingKind.ASSISTED_INJECTION);
- ExecutableElement constructor = asExecutable(binding.bindingElement().get());
- ExecutableType constructorType =
- asExecutable(types.asMemberOf(asDeclared(binding.key().type()), constructor));
+ XConstructorElement constructor = asConstructor(binding.bindingElement().get());
+ XConstructorType constructorType = constructor.asMemberOf(binding.key().type().xprocessing());
return assistedParameterSpecs(constructor.getParameters(), constructorType.getParameterTypes());
}
private static ImmutableList<ParameterSpec> assistedParameterSpecs(
- List<? extends VariableElement> paramElements, List<? extends TypeMirror> paramTypes) {
+ List<? extends XVariableElement> paramElements, List<XType> paramTypes) {
ImmutableList.Builder<ParameterSpec> assistedParameterSpecs = ImmutableList.builder();
for (int i = 0; i < paramElements.size(); i++) {
- VariableElement paramElement = paramElements.get(i);
- TypeMirror paramType = paramTypes.get(i);
+ XVariableElement paramElement = paramElements.get(i);
+ XType paramType = paramTypes.get(i);
if (isAssistedParameter(paramElement)) {
assistedParameterSpecs.add(
- ParameterSpec.builder(TypeName.get(paramType), paramElement.getSimpleName().toString())
- .build());
+ ParameterSpec.builder(paramType.getTypeName(), getSimpleName(paramElement)).build());
}
}
return assistedParameterSpecs.build();
@@ -122,14 +112,13 @@ public final class AssistedInjectionAnnotations {
* of each parameter will be the name given in the {@link
* dagger.assisted.AssistedInject}-annotated constructor.
*/
- public static ImmutableList<ParameterSpec> assistedFactoryParameterSpecs(
- Binding binding, DaggerElements elements, DaggerTypes types) {
+ public static ImmutableList<ParameterSpec> assistedFactoryParameterSpecs(Binding binding) {
checkArgument(binding.kind() == BindingKind.ASSISTED_FACTORY);
- AssistedFactoryMetadata metadata =
- AssistedFactoryMetadata.create(binding.bindingElement().get().asType(), elements, types);
- ExecutableType factoryMethodType =
- asExecutable(types.asMemberOf(asDeclared(binding.key().type()), metadata.factoryMethod()));
+ XTypeElement factory = asTypeElement(binding.bindingElement().get());
+ AssistedFactoryMetadata metadata = AssistedFactoryMetadata.create(factory.getType());
+ XMethodType factoryMethodType =
+ metadata.factoryMethod().asMemberOf(binding.key().type().xprocessing());
return assistedParameterSpecs(
// Use the order of the parameters from the @AssistedFactory method but use the parameter
// names of the @AssistedInject constructor.
@@ -140,81 +129,82 @@ public final class AssistedInjectionAnnotations {
}
/** Returns the constructors in {@code type} that are annotated with {@link AssistedInject}. */
- public static ImmutableSet<ExecutableElement> assistedInjectedConstructors(TypeElement type) {
- return constructorsIn(type.getEnclosedElements()).stream()
- .filter(constructor -> isAnnotationPresent(constructor, AssistedInject.class))
+ public static ImmutableSet<XConstructorElement> assistedInjectedConstructors(XTypeElement type) {
+ return type.getConstructors().stream()
+ .filter(constructor -> constructor.hasAnnotation(TypeNames.ASSISTED_INJECT))
.collect(toImmutableSet());
}
- public static ImmutableList<VariableElement> assistedParameters(Binding binding) {
+ public static ImmutableList<XVariableElement> assistedParameters(Binding binding) {
return binding.kind() == BindingKind.ASSISTED_INJECTION
- ? assistedParameters(asExecutable(binding.bindingElement().get()))
+ ? asConstructor(binding.bindingElement().get()).getParameters().stream()
+ .filter(AssistedInjectionAnnotations::isAssistedParameter)
+ .collect(toImmutableList())
: ImmutableList.of();
}
- private static ImmutableList<VariableElement> assistedParameters(ExecutableElement constructor) {
- return constructor.getParameters().stream()
- .filter(AssistedInjectionAnnotations::isAssistedParameter)
- .collect(toImmutableList());
+ /** Returns {@code true} if this binding is uses assisted injection. */
+ public static boolean isAssistedParameter(XVariableElement param) {
+ return param.hasAnnotation(TypeNames.ASSISTED);
}
/** Returns {@code true} if this binding is uses assisted injection. */
public static boolean isAssistedParameter(VariableElement param) {
- return isAnnotationPresent(MoreElements.asVariable(param), Assisted.class);
+ return isAnnotationPresent(MoreElements.asVariable(param), TypeNames.ASSISTED);
}
/** Metadata about an {@link dagger.assisted.AssistedFactory} annotated type. */
@AutoValue
public abstract static class AssistedFactoryMetadata {
- public static AssistedFactoryMetadata create(
- TypeMirror factory, DaggerElements elements, DaggerTypes types) {
- DeclaredType factoryType = asDeclared(factory);
- TypeElement factoryElement = asTypeElement(factoryType);
- ExecutableElement factoryMethod = assistedFactoryMethod(factoryElement, elements);
- ExecutableType factoryMethodType = asExecutable(types.asMemberOf(factoryType, factoryMethod));
- DeclaredType assistedInjectType = asDeclared(factoryMethodType.getReturnType());
+ public static AssistedFactoryMetadata create(XType factoryType) {
+ XTypeElement factoryElement = factoryType.getTypeElement();
+ XMethodElement factoryMethod = assistedFactoryMethod(factoryElement);
+ XMethodType factoryMethodType = factoryMethod.asMemberOf(factoryType);
+ XType assistedInjectType = factoryMethodType.getReturnType();
+ XTypeElement assistedInjectElement = assistedInjectType.getTypeElement();
return new AutoValue_AssistedInjectionAnnotations_AssistedFactoryMetadata(
factoryElement,
factoryType,
factoryMethod,
factoryMethodType,
- asTypeElement(assistedInjectType),
+ assistedInjectElement,
assistedInjectType,
- AssistedInjectionAnnotations.assistedInjectAssistedParameters(assistedInjectType, types),
+ AssistedInjectionAnnotations.assistedInjectAssistedParameters(assistedInjectType),
AssistedInjectionAnnotations.assistedFactoryAssistedParameters(
factoryMethod, factoryMethodType));
}
- public abstract TypeElement factory();
+ public abstract XTypeElement factory();
- public abstract DeclaredType factoryType();
+ public abstract XType factoryType();
- public abstract ExecutableElement factoryMethod();
+ public abstract XMethodElement factoryMethod();
- public abstract ExecutableType factoryMethodType();
+ public abstract XMethodType factoryMethodType();
- public abstract TypeElement assistedInjectElement();
+ public abstract XTypeElement assistedInjectElement();
- public abstract DeclaredType assistedInjectType();
+ public abstract XType assistedInjectType();
public abstract ImmutableList<AssistedParameter> assistedInjectAssistedParameters();
public abstract ImmutableList<AssistedParameter> assistedFactoryAssistedParameters();
@Memoized
- public ImmutableMap<AssistedParameter, VariableElement> assistedInjectAssistedParametersMap() {
- ImmutableMap.Builder<AssistedParameter, VariableElement> builder = ImmutableMap.builder();
+ public ImmutableMap<AssistedParameter, XVariableElement> assistedInjectAssistedParametersMap() {
+ ImmutableMap.Builder<AssistedParameter, XVariableElement> builder = ImmutableMap.builder();
for (AssistedParameter assistedParameter : assistedInjectAssistedParameters()) {
- builder.put(assistedParameter, assistedParameter.variableElement);
+ builder.put(assistedParameter, assistedParameter.element());
}
return builder.build();
}
@Memoized
- public ImmutableMap<AssistedParameter, VariableElement> assistedFactoryAssistedParametersMap() {
- ImmutableMap.Builder<AssistedParameter, VariableElement> builder = ImmutableMap.builder();
+ public ImmutableMap<AssistedParameter, XVariableElement>
+ assistedFactoryAssistedParametersMap() {
+ ImmutableMap.Builder<AssistedParameter, XVariableElement> builder = ImmutableMap.builder();
for (AssistedParameter assistedParameter : assistedFactoryAssistedParameters()) {
- builder.put(assistedParameter, assistedParameter.variableElement);
+ builder.put(assistedParameter, assistedParameter.element());
}
return builder.build();
}
@@ -228,32 +218,34 @@ public final class AssistedInjectionAnnotations {
*/
@AutoValue
public abstract static class AssistedParameter {
- public static AssistedParameter create(VariableElement parameter, TypeMirror parameterType) {
+ public static AssistedParameter create(XVariableElement parameter, XType parameterType) {
AssistedParameter assistedParameter =
new AutoValue_AssistedInjectionAnnotations_AssistedParameter(
- getAnnotationMirror(parameter, Assisted.class)
- .map(assisted -> getStringValue(assisted, "value"))
+ Optional.ofNullable(parameter.getAnnotation(TypeNames.ASSISTED))
+ .map(assisted -> assisted.getAsString("value"))
.orElse(""),
- MoreTypes.equivalence().wrap(parameterType));
- assistedParameter.variableElement = parameter;
+ parameterType.getTypeName());
+ assistedParameter.parameterElement = parameter;
+ assistedParameter.parameterType = parameterType;
return assistedParameter;
}
- private VariableElement variableElement;
+ private XVariableElement parameterElement;
+ private XType parameterType;
/** Returns the string qualifier from the {@link Assisted#value()}. */
public abstract String qualifier();
- /** Returns the wrapper for the type annotated with {@link Assisted}. */
- public abstract Equivalence.Wrapper<TypeMirror> wrappedType();
+ /** Returns the type annotated with {@link Assisted}. */
+ abstract TypeName typeName();
/** Returns the type annotated with {@link Assisted}. */
- public final TypeMirror type() {
- return wrappedType().get();
+ public final XType type() {
+ return parameterType;
}
- public final VariableElement variableElement() {
- return variableElement;
+ public final XVariableElement element() {
+ return parameterElement;
}
@Override
@@ -265,31 +257,31 @@ public final class AssistedInjectionAnnotations {
}
public static ImmutableList<AssistedParameter> assistedInjectAssistedParameters(
- DeclaredType assistedInjectType, DaggerTypes types) {
+ XType assistedInjectType) {
// We keep track of the constructor both as an ExecutableElement to access @Assisted
// parameters and as an ExecutableType to access the resolved parameter types.
- ExecutableElement assistedInjectConstructor =
- getOnlyElement(assistedInjectedConstructors(asTypeElement(assistedInjectType)));
- ExecutableType assistedInjectConstructorType =
- asExecutable(types.asMemberOf(assistedInjectType, assistedInjectConstructor));
+ XConstructorElement assistedInjectConstructor =
+ getOnlyElement(assistedInjectedConstructors(assistedInjectType.getTypeElement()));
+ XConstructorType assistedInjectConstructorType =
+ assistedInjectConstructor.asMemberOf(assistedInjectType);
ImmutableList.Builder<AssistedParameter> builder = ImmutableList.builder();
for (int i = 0; i < assistedInjectConstructor.getParameters().size(); i++) {
- VariableElement parameter = assistedInjectConstructor.getParameters().get(i);
- TypeMirror parameterType = assistedInjectConstructorType.getParameterTypes().get(i);
- if (isAnnotationPresent(parameter, Assisted.class)) {
+ XVariableElement parameter = assistedInjectConstructor.getParameters().get(i);
+ XType parameterType = assistedInjectConstructorType.getParameterTypes().get(i);
+ if (parameter.hasAnnotation(TypeNames.ASSISTED)) {
builder.add(AssistedParameter.create(parameter, parameterType));
}
}
return builder.build();
}
- public static ImmutableList<AssistedParameter> assistedFactoryAssistedParameters(
- ExecutableElement factoryMethod, ExecutableType factoryMethodType) {
+ private static ImmutableList<AssistedParameter> assistedFactoryAssistedParameters(
+ XMethodElement factoryMethod, XMethodType factoryMethodType) {
ImmutableList.Builder<AssistedParameter> builder = ImmutableList.builder();
for (int i = 0; i < factoryMethod.getParameters().size(); i++) {
- VariableElement parameter = factoryMethod.getParameters().get(i);
- TypeMirror parameterType = factoryMethodType.getParameterTypes().get(i);
+ XVariableElement parameter = factoryMethod.getParameters().get(i);
+ XType parameterType = factoryMethodType.getParameterTypes().get(i);
builder.add(AssistedParameter.create(parameter, parameterType));
}
return builder.build();
diff --git a/java/dagger/internal/codegen/binding/BUILD b/java/dagger/internal/codegen/binding/BUILD
index ff8db8f60..54211d858 100644
--- a/java/dagger/internal/codegen/binding/BUILD
+++ b/java/dagger/internal/codegen/binding/BUILD
@@ -32,16 +32,17 @@ java_library(
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/kotlin",
"//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "//java/dagger/internal/guava:graph",
- "//java/dagger/model:internal-proxies",
+ "//java/dagger/internal/codegen/xprocessing",
"//java/dagger/producers",
"//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:value",
+ "//third_party/java/error_prone:annotations",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/graph",
+ "//third_party/java/guava/util/concurrent",
+ "//third_party/java/javapoet",
+ "@maven//:org_jetbrains_kotlin_kotlin_stdlib_jdk8",
],
)
diff --git a/java/dagger/internal/codegen/binding/Binding.java b/java/dagger/internal/codegen/binding/Binding.java
index 0d4eef65e..47d5d40de 100644
--- a/java/dagger/internal/codegen/binding/Binding.java
+++ b/java/dagger/internal/codegen/binding/Binding.java
@@ -16,34 +16,25 @@
package dagger.internal.codegen.binding;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.base.Suppliers.memoize;
import static javax.lang.model.element.Modifier.ABSTRACT;
import static javax.lang.model.element.Modifier.STATIC;
import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
-import dagger.model.Scope;
-import java.util.List;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Scope;
import java.util.Optional;
import java.util.Set;
-import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.TypeParameterElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.SimpleTypeVisitor6;
/**
- * An abstract type for classes representing a Dagger binding. Particularly, contains the {@link
- * Element} that generated the binding and the {@link DependencyRequest} instances that are required
- * to satisfy the binding, but leaves the specifics of the <i>mechanism</i> of the binding to the
+ * An abstract type for classes representing a Dagger binding. Particularly, contains the element
+ * that generated the binding and the {@link DependencyRequest} instances that are required to
+ * satisfy the binding, but leaves the specifics of the <i>mechanism</i> of the binding to the
* subtypes.
*/
public abstract class Binding extends BindingDeclaration {
@@ -56,7 +47,7 @@ public abstract class Binding extends BindingDeclaration {
if (!bindingElement().isPresent() || !contributingModule().isPresent()) {
return false;
}
- Set<Modifier> modifiers = bindingElement().get().getModifiers();
+ Set<Modifier> modifiers = toJavac(bindingElement().get()).getModifiers();
return !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC);
}
@@ -121,45 +112,4 @@ public abstract class Binding extends BindingDeclaration {
public Optional<Scope> scope() {
return Optional.empty();
}
-
- // TODO(sameb): Remove the TypeElement parameter and pull it from the TypeMirror.
- static boolean hasNonDefaultTypeParameters(
- TypeElement element, TypeMirror type, DaggerTypes types) {
- // If the element has no type parameters, nothing can be wrong.
- if (element.getTypeParameters().isEmpty()) {
- return false;
- }
-
- List<TypeMirror> defaultTypes = Lists.newArrayList();
- for (TypeParameterElement parameter : element.getTypeParameters()) {
- defaultTypes.add(parameter.asType());
- }
-
- List<TypeMirror> actualTypes =
- type.accept(
- new SimpleTypeVisitor6<List<TypeMirror>, Void>() {
- @Override
- protected List<TypeMirror> defaultAction(TypeMirror e, Void p) {
- return ImmutableList.of();
- }
-
- @Override
- public List<TypeMirror> visitDeclared(DeclaredType t, Void p) {
- return ImmutableList.<TypeMirror>copyOf(t.getTypeArguments());
- }
- },
- null);
-
- // The actual type parameter size can be different if the user is using a raw type.
- if (defaultTypes.size() != actualTypes.size()) {
- return true;
- }
-
- for (int i = 0; i < defaultTypes.size(); i++) {
- if (!types.isSameType(defaultTypes.get(i), actualTypes.get(i))) {
- return true;
- }
- }
- return false;
- }
}
diff --git a/java/dagger/internal/codegen/binding/BindingDeclaration.java b/java/dagger/internal/codegen/binding/BindingDeclaration.java
index 712260fb7..353921ace 100644
--- a/java/dagger/internal/codegen/binding/BindingDeclaration.java
+++ b/java/dagger/internal/codegen/binding/BindingDeclaration.java
@@ -16,16 +16,17 @@
package dagger.internal.codegen.binding;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static dagger.internal.codegen.extension.Optionals.emptiesLast;
import static java.util.Comparator.comparing;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.model.BindingKind;
-import dagger.model.Key;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XTypeElement;
+import dagger.internal.codegen.xprocessing.XElements;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.Key;
import java.util.Comparator;
import java.util.Optional;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
/** An object that declares or specifies a binding. */
public abstract class BindingDeclaration {
@@ -48,18 +49,18 @@ public abstract class BindingDeclaration {
declaration.contributingModule().isPresent()
? declaration.contributingModule()
: declaration.bindingTypeElement(),
- emptiesLast(comparing((TypeElement type) -> type.getQualifiedName().toString())))
+ emptiesLast(comparing(XTypeElement::getQualifiedName)))
.thenComparing(
(BindingDeclaration declaration) -> declaration.bindingElement(),
emptiesLast(
- comparing((Element element) -> element.getSimpleName().toString())
- .thenComparing((Element element) -> element.asType().toString())));
+ comparing((XElement element) -> toJavac(element).getSimpleName().toString())
+ .thenComparing((XElement element) -> toJavac(element).asType().toString())));
/** The {@link Key} of this declaration. */
public abstract Key key();
/**
- * The {@link Element} that declares this binding. Absent for {@linkplain BindingKind binding
+ * The {@link XElement} that declares this binding. Absent for {@linkplain BindingKind binding
* kinds} that are not always declared by exactly one element.
*
* <p>For example, consider {@link BindingKind#MULTIBOUND_SET}. A component with many
@@ -68,14 +69,14 @@ public abstract class BindingDeclaration {
* contribute a synthetic binding, but since multiple {@code @Multibinds} methods can coexist in
* the same component (and contribute to one single binding), it has no binding element.
*/
- public abstract Optional<Element> bindingElement();
+ public abstract Optional<XElement> bindingElement();
/**
* The type enclosing the {@link #bindingElement()}, or {@link Optional#empty()} if {@link
* #bindingElement()} is empty.
*/
- public final Optional<TypeElement> bindingTypeElement() {
- return bindingElement().map(DaggerElements::closestEnclosingTypeElement);
+ public final Optional<XTypeElement> bindingTypeElement() {
+ return bindingElement().map(XElements::closestEnclosingTypeElement);
}
/**
@@ -83,5 +84,5 @@ public abstract class BindingDeclaration {
* the class that contains {@link #bindingElement()}. Absent if {@link #bindingElement()} is
* empty.
*/
- public abstract Optional<TypeElement> contributingModule();
+ public abstract Optional<XTypeElement> contributingModule();
}
diff --git a/java/dagger/internal/codegen/binding/BindingDeclarationFormatter.java b/java/dagger/internal/codegen/binding/BindingDeclarationFormatter.java
index 84764973b..a69ddaa6b 100644
--- a/java/dagger/internal/codegen/binding/BindingDeclarationFormatter.java
+++ b/java/dagger/internal/codegen/binding/BindingDeclarationFormatter.java
@@ -16,30 +16,24 @@
package dagger.internal.codegen.binding;
-import static com.google.common.collect.Sets.immutableEnumSet;
+import static androidx.room.compiler.processing.XElementKt.isMethodParameter;
+import static androidx.room.compiler.processing.XElementKt.isTypeElement;
import static dagger.internal.codegen.base.DiagnosticFormatting.stripCommonTypePrefixes;
import static dagger.internal.codegen.base.ElementFormatter.elementToString;
-import static javax.lang.model.element.ElementKind.PARAMETER;
-import static javax.lang.model.type.TypeKind.DECLARED;
-import static javax.lang.model.type.TypeKind.EXECUTABLE;
+import static dagger.internal.codegen.xprocessing.XElements.asExecutable;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+import static dagger.internal.codegen.xprocessing.XElements.isExecutable;
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import dagger.internal.codegen.base.Formatter;
import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeKind;
/**
* Formats a {@link BindingDeclaration} into a {@link String} suitable for use in error messages.
*/
public final class BindingDeclarationFormatter extends Formatter<BindingDeclaration> {
- private static final ImmutableSet<TypeKind> FORMATTABLE_ELEMENT_TYPE_KINDS =
- immutableEnumSet(EXECUTABLE, DECLARED);
-
private final MethodSignatureFormatter methodSignatureFormatter;
@Inject
@@ -57,9 +51,10 @@ public final class BindingDeclarationFormatter extends Formatter<BindingDeclarat
return true;
}
if (bindingDeclaration.bindingElement().isPresent()) {
- Element bindingElement = bindingDeclaration.bindingElement().get();
- return bindingElement.getKind().equals(PARAMETER)
- || FORMATTABLE_ELEMENT_TYPE_KINDS.contains(bindingElement.asType().getKind());
+ XElement bindingElement = bindingDeclaration.bindingElement().get();
+ return isMethodParameter(bindingElement)
+ || isTypeElement(bindingElement)
+ || isExecutable(bindingElement);
}
// TODO(dpb): validate whether what this is doing is correct
return false;
@@ -72,26 +67,17 @@ public final class BindingDeclarationFormatter extends Formatter<BindingDeclarat
}
if (bindingDeclaration.bindingElement().isPresent()) {
- Element bindingElement = bindingDeclaration.bindingElement().get();
- if (bindingElement.getKind().equals(PARAMETER)) {
+ XElement bindingElement = bindingDeclaration.bindingElement().get();
+ if (isMethodParameter(bindingElement)) {
return elementToString(bindingElement);
+ } else if (isTypeElement(bindingElement)) {
+ return stripCommonTypePrefixes(asTypeElement(bindingElement).getType().toString());
+ } else if (isExecutable(bindingElement)) {
+ return methodSignatureFormatter.format(
+ asExecutable(bindingElement),
+ bindingDeclaration.contributingModule().map(XTypeElement::getType));
}
-
- switch (bindingElement.asType().getKind()) {
- case EXECUTABLE:
- return methodSignatureFormatter.format(
- MoreElements.asExecutable(bindingElement),
- bindingDeclaration
- .contributingModule()
- .map(module -> MoreTypes.asDeclared(module.asType())));
-
- case DECLARED:
- return stripCommonTypePrefixes(bindingElement.asType().toString());
-
- default:
- throw new IllegalArgumentException(
- "Formatting unsupported for element: " + bindingElement);
- }
+ throw new IllegalArgumentException("Formatting unsupported for element: " + bindingElement);
}
return String.format(
@@ -100,7 +86,7 @@ public final class BindingDeclarationFormatter extends Formatter<BindingDeclarat
}
private String formatSubcomponentDeclaration(SubcomponentDeclaration subcomponentDeclaration) {
- ImmutableList<TypeElement> moduleSubcomponents =
+ ImmutableList<XTypeElement> moduleSubcomponents =
subcomponentDeclaration.moduleAnnotation().subcomponents();
int index = moduleSubcomponents.indexOf(subcomponentDeclaration.subcomponentType());
StringBuilder annotationValue = new StringBuilder();
@@ -118,7 +104,7 @@ public final class BindingDeclarationFormatter extends Formatter<BindingDeclarat
return String.format(
"@%s(subcomponents = %s) for %s",
- subcomponentDeclaration.moduleAnnotation().annotationName(),
+ subcomponentDeclaration.moduleAnnotation().simpleName(),
annotationValue,
subcomponentDeclaration.contributingModule().get());
}
diff --git a/java/dagger/internal/codegen/binding/BindingFactory.java b/java/dagger/internal/codegen/binding/BindingFactory.java
index eb7c1322a..5146c35e1 100644
--- a/java/dagger/internal/codegen/binding/BindingFactory.java
+++ b/java/dagger/internal/codegen/binding/BindingFactory.java
@@ -16,69 +16,68 @@
package dagger.internal.codegen.binding;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.auto.common.MoreTypes.asDeclared;
+import static androidx.room.compiler.processing.XElementKt.isMethod;
+import static androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static androidx.room.compiler.processing.XElementKt.isVariableElement;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.base.MoreAnnotationMirrors.wrapOptionalInEquivalence;
-import static dagger.internal.codegen.base.Scopes.uniqueScopeOf;
-import static dagger.internal.codegen.binding.Binding.hasNonDefaultTypeParameters;
import static dagger.internal.codegen.binding.ComponentDescriptor.isComponentProductionMethod;
import static dagger.internal.codegen.binding.ConfigurationAnnotations.getNullableType;
-import static dagger.internal.codegen.binding.ContributionBinding.bindingKindForMultibindingKey;
import static dagger.internal.codegen.binding.MapKeys.getMapKey;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.model.BindingKind.ASSISTED_FACTORY;
-import static dagger.model.BindingKind.ASSISTED_INJECTION;
-import static dagger.model.BindingKind.BOUND_INSTANCE;
-import static dagger.model.BindingKind.COMPONENT;
-import static dagger.model.BindingKind.COMPONENT_DEPENDENCY;
-import static dagger.model.BindingKind.COMPONENT_PRODUCTION;
-import static dagger.model.BindingKind.COMPONENT_PROVISION;
-import static dagger.model.BindingKind.DELEGATE;
-import static dagger.model.BindingKind.INJECTION;
-import static dagger.model.BindingKind.MEMBERS_INJECTOR;
-import static dagger.model.BindingKind.OPTIONAL;
-import static dagger.model.BindingKind.PRODUCTION;
-import static dagger.model.BindingKind.PROVISION;
-import static dagger.model.BindingKind.SUBCOMPONENT_CREATOR;
-import static javax.lang.model.element.ElementKind.CONSTRUCTOR;
-import static javax.lang.model.element.ElementKind.METHOD;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
+import static dagger.internal.codegen.xprocessing.XElements.asMethod;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+import static dagger.internal.codegen.xprocessing.XElements.asVariable;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
+import static dagger.spi.model.BindingKind.ASSISTED_FACTORY;
+import static dagger.spi.model.BindingKind.ASSISTED_INJECTION;
+import static dagger.spi.model.BindingKind.BOUND_INSTANCE;
+import static dagger.spi.model.BindingKind.COMPONENT;
+import static dagger.spi.model.BindingKind.COMPONENT_DEPENDENCY;
+import static dagger.spi.model.BindingKind.COMPONENT_PRODUCTION;
+import static dagger.spi.model.BindingKind.COMPONENT_PROVISION;
+import static dagger.spi.model.BindingKind.DELEGATE;
+import static dagger.spi.model.BindingKind.INJECTION;
+import static dagger.spi.model.BindingKind.MEMBERS_INJECTOR;
+import static dagger.spi.model.BindingKind.OPTIONAL;
+import static dagger.spi.model.BindingKind.PRODUCTION;
+import static dagger.spi.model.BindingKind.PROVISION;
+import static dagger.spi.model.BindingKind.SUBCOMPONENT_CREATOR;
+
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XConstructorType;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XExecutableParameterElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XMethodType;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.XVariableElement;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Iterables;
+import com.squareup.javapoet.ClassName;
import dagger.Module;
-import dagger.assisted.AssistedInject;
import dagger.internal.codegen.base.ContributionType;
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.SetType;
import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
import dagger.internal.codegen.binding.ProductionBinding.ProductionKind;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.RequestKind;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.DaggerType;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
+import dagger.spi.model.RequestKind;
import java.util.Optional;
import java.util.function.BiFunction;
import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
/** A factory for {@link Binding} objects. */
public final class BindingFactory {
@@ -86,30 +85,24 @@ public final class BindingFactory {
private final KeyFactory keyFactory;
private final DependencyRequestFactory dependencyRequestFactory;
private final InjectionSiteFactory injectionSiteFactory;
- private final DaggerElements elements;
private final InjectionAnnotations injectionAnnotations;
- private final KotlinMetadataUtil metadataUtil;
@Inject
BindingFactory(
DaggerTypes types,
- DaggerElements elements,
KeyFactory keyFactory,
DependencyRequestFactory dependencyRequestFactory,
InjectionSiteFactory injectionSiteFactory,
- InjectionAnnotations injectionAnnotations,
- KotlinMetadataUtil metadataUtil) {
+ InjectionAnnotations injectionAnnotations) {
this.types = types;
- this.elements = elements;
this.keyFactory = keyFactory;
this.dependencyRequestFactory = dependencyRequestFactory;
this.injectionSiteFactory = injectionSiteFactory;
this.injectionAnnotations = injectionAnnotations;
- this.metadataUtil = metadataUtil;
}
/**
- * Returns an {@link dagger.model.BindingKind#INJECTION} binding.
+ * Returns an {@link dagger.spi.model.BindingKind#INJECTION} binding.
*
* @param constructorElement the {@code @Inject}-annotated constructor
* @param resolvedType the parameterized type if the constructor is for a generic class and the
@@ -117,91 +110,69 @@ public final class BindingFactory {
*/
// TODO(dpb): See if we can just pass the parameterized type and not also the constructor.
public ProvisionBinding injectionBinding(
- ExecutableElement constructorElement, Optional<TypeMirror> resolvedType) {
- checkArgument(constructorElement.getKind().equals(CONSTRUCTOR));
- checkArgument(
- isAnnotationPresent(constructorElement, Inject.class)
- || isAnnotationPresent(constructorElement, AssistedInject.class));
- checkArgument(!injectionAnnotations.getQualifier(constructorElement).isPresent());
-
- ExecutableType constructorType = MoreTypes.asExecutable(constructorElement.asType());
- DeclaredType constructedType =
- MoreTypes.asDeclared(constructorElement.getEnclosingElement().asType());
+ XConstructorElement constructorElement, Optional<XType> resolvedEnclosingType) {
+ checkArgument(InjectionAnnotations.hasInjectOrAssistedInjectAnnotation(constructorElement));
+
+ XConstructorType constructorType = constructorElement.getExecutableType();
+ XType enclosingType = constructorElement.getEnclosingElement().getType();
// If the class this is constructing has some type arguments, resolve everything.
- if (!constructedType.getTypeArguments().isEmpty() && resolvedType.isPresent()) {
- DeclaredType resolved = MoreTypes.asDeclared(resolvedType.get());
- // Validate that we're resolving from the correct type.
- checkState(
- types.isSameType(types.erasure(resolved), types.erasure(constructedType)),
- "erased expected type: %s, erased actual type: %s",
- types.erasure(resolved),
- types.erasure(constructedType));
- constructorType = MoreTypes.asExecutable(types.asMemberOf(resolved, constructorElement));
- constructedType = resolved;
+ if (!enclosingType.getTypeArguments().isEmpty() && resolvedEnclosingType.isPresent()) {
+ checkIsSameErasedType(resolvedEnclosingType.get(), enclosingType);
+ enclosingType = resolvedEnclosingType.get();
+ constructorType = constructorElement.asMemberOf(enclosingType);
}
// Collect all dependency requests within the provision method.
// Note: we filter out @Assisted parameters since these aren't considered dependency requests.
ImmutableSet.Builder<DependencyRequest> provisionDependencies = ImmutableSet.builder();
for (int i = 0; i < constructorElement.getParameters().size(); i++) {
- VariableElement parameter = constructorElement.getParameters().get(i);
- TypeMirror parameterType = constructorType.getParameterTypes().get(i);
+ XExecutableParameterElement parameter = constructorElement.getParameters().get(i);
+ XType parameterType = constructorType.getParameterTypes().get(i);
if (!AssistedInjectionAnnotations.isAssistedParameter(parameter)) {
provisionDependencies.add(
dependencyRequestFactory.forRequiredResolvedVariable(parameter, parameterType));
}
}
- Key key = keyFactory.forInjectConstructorWithResolvedType(constructedType);
ProvisionBinding.Builder builder =
ProvisionBinding.builder()
.contributionType(ContributionType.UNIQUE)
.bindingElement(constructorElement)
- .key(key)
+ .key(keyFactory.forInjectConstructorWithResolvedType(enclosingType))
.provisionDependencies(provisionDependencies.build())
- .injectionSites(injectionSiteFactory.getInjectionSites(constructedType))
+ .injectionSites(injectionSiteFactory.getInjectionSites(enclosingType))
.kind(
- isAnnotationPresent(constructorElement, AssistedInject.class)
+ constructorElement.hasAnnotation(TypeNames.ASSISTED_INJECT)
? ASSISTED_INJECTION
: INJECTION)
- .scope(uniqueScopeOf(constructorElement.getEnclosingElement()));
+ .scope(injectionAnnotations.getScope(constructorElement.getEnclosingElement()));
- TypeElement bindingTypeElement = MoreElements.asType(constructorElement.getEnclosingElement());
- if (hasNonDefaultTypeParameters(bindingTypeElement, key.type(), types)) {
+ if (hasNonDefaultTypeParameters(enclosingType)) {
builder.unresolved(injectionBinding(constructorElement, Optional.empty()));
}
return builder.build();
}
public ProvisionBinding assistedFactoryBinding(
- TypeElement factory, Optional<TypeMirror> resolvedType) {
+ XTypeElement factory, Optional<XType> resolvedFactoryType) {
// If the class this is constructing has some type arguments, resolve everything.
- DeclaredType factoryType = MoreTypes.asDeclared(factory.asType());
- if (!factoryType.getTypeArguments().isEmpty() && resolvedType.isPresent()) {
- DeclaredType resolved = MoreTypes.asDeclared(resolvedType.get());
- // Validate that we're resolving from the correct type by checking that the erasure of the
- // resolvedType is the same as the erasure of the factoryType.
- checkState(
- types.isSameType(types.erasure(resolved), types.erasure(factoryType)),
- "erased expected type: %s, erased actual type: %s",
- types.erasure(resolved),
- types.erasure(factoryType));
- factoryType = resolved;
+ XType factoryType = factory.getType();
+ if (!factoryType.getTypeArguments().isEmpty() && resolvedFactoryType.isPresent()) {
+ checkIsSameErasedType(resolvedFactoryType.get(), factoryType);
+ factoryType = resolvedFactoryType.get();
}
- ExecutableElement factoryMethod =
- AssistedInjectionAnnotations.assistedFactoryMethod(factory, elements);
- ExecutableType factoryMethodType =
- MoreTypes.asExecutable(types.asMemberOf(factoryType, factoryMethod));
+ XMethodElement factoryMethod = AssistedInjectionAnnotations.assistedFactoryMethod(factory);
+ XMethodType factoryMethodType = factoryMethod.asMemberOf(factoryType);
return ProvisionBinding.builder()
.contributionType(ContributionType.UNIQUE)
- .key(Key.builder(factoryType).build())
+ .key(Key.builder(DaggerType.from(factoryType)).build())
.bindingElement(factory)
.provisionDependencies(
ImmutableSet.of(
DependencyRequest.builder()
- .key(Key.builder(factoryMethodType.getReturnType()).build())
+ .key(Key.builder(DaggerType.from(factoryMethodType.getReturnType())).build())
.kind(RequestKind.PROVIDER)
.build()))
.kind(ASSISTED_FACTORY)
@@ -209,13 +180,13 @@ public final class BindingFactory {
}
/**
- * Returns a {@link dagger.model.BindingKind#PROVISION} binding for a {@code @Provides}-annotated
- * method.
+ * Returns a {@link dagger.spi.model.BindingKind#PROVISION} binding for a
+ * {@code @Provides}-annotated method.
*
* @param contributedBy the installed module that declares or inherits the method
*/
public ProvisionBinding providesMethodBinding(
- ExecutableElement providesMethod, TypeElement contributedBy) {
+ XMethodElement providesMethod, XTypeElement contributedBy) {
return setMethodBindingProperties(
ProvisionBinding.builder(),
providesMethod,
@@ -223,19 +194,19 @@ public final class BindingFactory {
keyFactory.forProvidesMethod(providesMethod, contributedBy),
this::providesMethodBinding)
.kind(PROVISION)
- .scope(uniqueScopeOf(providesMethod))
+ .scope(injectionAnnotations.getScope(providesMethod))
.nullableType(getNullableType(providesMethod))
.build();
}
/**
- * Returns a {@link dagger.model.BindingKind#PRODUCTION} binding for a {@code @Produces}-annotated
- * method.
+ * Returns a {@link dagger.spi.model.BindingKind#PRODUCTION} binding for a
+ * {@code @Produces}-annotated method.
*
* @param contributedBy the installed module that declares or inherits the method
*/
public ProductionBinding producesMethodBinding(
- ExecutableElement producesMethod, TypeElement contributedBy) {
+ XMethodElement producesMethod, XTypeElement contributedBy) {
// TODO(beder): Add nullability checking with Java 8.
ProductionBinding.Builder builder =
setMethodBindingProperties(
@@ -255,35 +226,29 @@ public final class BindingFactory {
private <C extends ContributionBinding, B extends ContributionBinding.Builder<C, B>>
B setMethodBindingProperties(
B builder,
- ExecutableElement method,
- TypeElement contributedBy,
+ XMethodElement method,
+ XTypeElement contributedBy,
Key key,
- BiFunction<ExecutableElement, TypeElement, C> create) {
- checkArgument(method.getKind().equals(METHOD));
- ExecutableType methodType =
- MoreTypes.asExecutable(
- types.asMemberOf(MoreTypes.asDeclared(contributedBy.asType()), method));
- if (!types.isSameType(methodType, method.asType())) {
- builder.unresolved(create.apply(method, MoreElements.asType(method.getEnclosingElement())));
+ BiFunction<XMethodElement, XTypeElement, C> create) {
+ XMethodType methodType = method.asMemberOf(contributedBy.getType());
+ if (!types.isSameType(toJavac(methodType), toJavac(method.getExecutableType()))) {
+ checkState(isTypeElement(method.getEnclosingElement()));
+ builder.unresolved(create.apply(method, asTypeElement(method.getEnclosingElement())));
}
- boolean isKotlinObject =
- metadataUtil.isObjectClass(contributedBy)
- || metadataUtil.isCompanionObjectClass(contributedBy);
return builder
.contributionType(ContributionType.fromBindingElement(method))
.bindingElement(method)
.contributingModule(contributedBy)
- .isContributingModuleKotlinObject(isKotlinObject)
.key(key)
.dependencies(
- dependencyRequestFactory.forRequiredResolvedVariables(
+ dependencyRequestFactory.forRequiredResolvedXVariables(
method.getParameters(), methodType.getParameterTypes()))
.wrappedMapKeyAnnotation(wrapOptionalInEquivalence(getMapKey(method)));
}
/**
- * Returns a {@link dagger.model.BindingKind#MULTIBOUND_MAP} or {@link
- * dagger.model.BindingKind#MULTIBOUND_SET} binding given a set of multibinding contribution
+ * Returns a {@link dagger.spi.model.BindingKind#MULTIBOUND_MAP} or {@link
+ * dagger.spi.model.BindingKind#MULTIBOUND_SET} binding given a set of multibinding contribution
* bindings.
*
* @param key a key that may be satisfied by a multibinding
@@ -303,33 +268,44 @@ public final class BindingFactory {
.build();
}
+ private static BindingKind bindingKindForMultibindingKey(Key key) {
+ if (SetType.isSet(key)) {
+ return BindingKind.MULTIBOUND_SET;
+ } else if (MapType.isMap(key)) {
+ return BindingKind.MULTIBOUND_MAP;
+ } else {
+ throw new IllegalArgumentException(String.format("key is not for a set or map: %s", key));
+ }
+ }
+
private boolean multibindingRequiresProduction(
Key key, Iterable<ContributionBinding> multibindingContributions) {
if (MapType.isMap(key)) {
MapType mapType = MapType.from(key);
- if (mapType.valuesAreTypeOf(Producer.class) || mapType.valuesAreTypeOf(Produced.class)) {
+ if (mapType.valuesAreTypeOf(TypeNames.PRODUCER)
+ || mapType.valuesAreTypeOf(TypeNames.PRODUCED)) {
return true;
}
- } else if (SetType.isSet(key) && SetType.from(key).elementsAreTypeOf(Produced.class)) {
+ } else if (SetType.isSet(key) && SetType.from(key).elementsAreTypeOf(TypeNames.PRODUCED)) {
return true;
}
return Iterables.any(
multibindingContributions, binding -> binding.bindingType().equals(BindingType.PRODUCTION));
}
- /** Returns a {@link dagger.model.BindingKind#COMPONENT} binding for the component. */
- public ProvisionBinding componentBinding(TypeElement componentDefinitionType) {
+ /** Returns a {@link dagger.spi.model.BindingKind#COMPONENT} binding for the component. */
+ public ProvisionBinding componentBinding(XTypeElement componentDefinitionType) {
checkNotNull(componentDefinitionType);
return ProvisionBinding.builder()
.contributionType(ContributionType.UNIQUE)
.bindingElement(componentDefinitionType)
- .key(keyFactory.forType(componentDefinitionType.asType()))
+ .key(keyFactory.forType(componentDefinitionType.getType()))
.kind(COMPONENT)
.build();
}
/**
- * Returns a {@link dagger.model.BindingKind#COMPONENT_DEPENDENCY} binding for a component's
+ * Returns a {@link dagger.spi.model.BindingKind#COMPONENT_DEPENDENCY} binding for a component's
* dependency.
*/
public ProvisionBinding componentDependencyBinding(ComponentRequirement dependency) {
@@ -343,20 +319,18 @@ public final class BindingFactory {
}
/**
- * Returns a {@link dagger.model.BindingKind#COMPONENT_PROVISION} or {@link
- * dagger.model.BindingKind#COMPONENT_PRODUCTION} binding for a method on a component's
+ * Returns a {@link dagger.spi.model.BindingKind#COMPONENT_PROVISION} or {@link
+ * dagger.spi.model.BindingKind#COMPONENT_PRODUCTION} binding for a method on a component's
* dependency.
*
* @param componentDescriptor the component with the dependency, not the dependency that has the
* method
*/
public ContributionBinding componentDependencyMethodBinding(
- ComponentDescriptor componentDescriptor, ExecutableElement dependencyMethod) {
- checkArgument(dependencyMethod.getKind().equals(METHOD));
+ ComponentDescriptor componentDescriptor, XMethodElement dependencyMethod) {
checkArgument(dependencyMethod.getParameters().isEmpty());
ContributionBinding.Builder<?, ?> builder;
- if (componentDescriptor.isProduction()
- && isComponentProductionMethod(elements, dependencyMethod)) {
+ if (componentDescriptor.isProduction() && isComponentProductionMethod(dependencyMethod)) {
builder =
ProductionBinding.builder()
.key(keyFactory.forProductionComponentMethod(dependencyMethod))
@@ -368,7 +342,7 @@ public final class BindingFactory {
.key(keyFactory.forComponentMethod(dependencyMethod))
.nullableType(getNullableType(dependencyMethod))
.kind(COMPONENT_PROVISION)
- .scope(uniqueScopeOf(dependencyMethod));
+ .scope(injectionAnnotations.getScope(dependencyMethod));
}
return builder
.contributionType(ContributionType.UNIQUE)
@@ -377,15 +351,15 @@ public final class BindingFactory {
}
/**
- * Returns a {@link dagger.model.BindingKind#BOUND_INSTANCE} binding for a
+ * Returns a {@link dagger.spi.model.BindingKind#BOUND_INSTANCE} binding for a
* {@code @BindsInstance}-annotated builder setter method or factory method parameter.
*/
- ProvisionBinding boundInstanceBinding(ComponentRequirement requirement, Element element) {
- checkArgument(element instanceof VariableElement || element instanceof ExecutableElement);
- VariableElement parameterElement =
- element instanceof VariableElement
- ? MoreElements.asVariable(element)
- : getOnlyElement(MoreElements.asExecutable(element).getParameters());
+ ProvisionBinding boundInstanceBinding(ComponentRequirement requirement, XElement element) {
+ checkArgument(isVariableElement(element) || isMethod(element));
+ XVariableElement parameterElement =
+ isVariableElement(element)
+ ? asVariable(element)
+ : getOnlyElement(asMethod(element).getParameters());
return ProvisionBinding.builder()
.contributionType(ContributionType.UNIQUE)
.bindingElement(element)
@@ -396,20 +370,18 @@ public final class BindingFactory {
}
/**
- * Returns a {@link dagger.model.BindingKind#SUBCOMPONENT_CREATOR} binding declared by a component
- * method that returns a subcomponent builder. Use {{@link
+ * Returns a {@link dagger.spi.model.BindingKind#SUBCOMPONENT_CREATOR} binding declared by a
+ * component method that returns a subcomponent builder. Use {{@link
* #subcomponentCreatorBinding(ImmutableSet)}} for bindings declared using {@link
* Module#subcomponents()}.
*
* @param component the component that declares or inherits the method
*/
ProvisionBinding subcomponentCreatorBinding(
- ExecutableElement subcomponentCreatorMethod, TypeElement component) {
- checkArgument(subcomponentCreatorMethod.getKind().equals(METHOD));
+ XMethodElement subcomponentCreatorMethod, XTypeElement component) {
checkArgument(subcomponentCreatorMethod.getParameters().isEmpty());
Key key =
- keyFactory.forSubcomponentCreatorMethod(
- subcomponentCreatorMethod, asDeclared(component.asType()));
+ keyFactory.forSubcomponentCreatorMethod(subcomponentCreatorMethod, component.getType());
return ProvisionBinding.builder()
.contributionType(ContributionType.UNIQUE)
.bindingElement(subcomponentCreatorMethod)
@@ -419,8 +391,8 @@ public final class BindingFactory {
}
/**
- * Returns a {@link dagger.model.BindingKind#SUBCOMPONENT_CREATOR} binding declared using {@link
- * Module#subcomponents()}.
+ * Returns a {@link dagger.spi.model.BindingKind#SUBCOMPONENT_CREATOR} binding declared using
+ * {@link Module#subcomponents()}.
*/
ProvisionBinding subcomponentCreatorBinding(
ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations) {
@@ -433,7 +405,7 @@ public final class BindingFactory {
}
/**
- * Returns a {@link dagger.model.BindingKind#DELEGATE} binding.
+ * Returns a {@link dagger.spi.model.BindingKind#DELEGATE} binding.
*
* @param delegateDeclaration the {@code @Binds}-annotated declaration
* @param actualBinding the binding that satisfies the {@code @Binds} declaration
@@ -445,15 +417,15 @@ public final class BindingFactory {
return buildDelegateBinding(
ProductionBinding.builder().nullableType(actualBinding.nullableType()),
delegateDeclaration,
- Producer.class);
+ TypeNames.PRODUCER);
case PROVISION:
return buildDelegateBinding(
ProvisionBinding.builder()
- .scope(uniqueScopeOf(delegateDeclaration.bindingElement().get()))
+ .scope(injectionAnnotations.getScope(delegateDeclaration.bindingElement().get()))
.nullableType(actualBinding.nullableType()),
delegateDeclaration,
- Provider.class);
+ TypeNames.PROVIDER);
case MEMBERS_INJECTION: // fall-through to throw
}
@@ -461,28 +433,25 @@ public final class BindingFactory {
}
/**
- * Returns a {@link dagger.model.BindingKind#DELEGATE} binding used when there is no binding that
- * satisfies the {@code @Binds} declaration.
+ * Returns a {@link dagger.spi.model.BindingKind#DELEGATE} binding used when there is no binding
+ * that satisfies the {@code @Binds} declaration.
*/
public ContributionBinding unresolvedDelegateBinding(DelegateDeclaration delegateDeclaration) {
return buildDelegateBinding(
- ProvisionBinding.builder().scope(uniqueScopeOf(delegateDeclaration.bindingElement().get())),
+ ProvisionBinding.builder()
+ .scope(injectionAnnotations.getScope(delegateDeclaration.bindingElement().get())),
delegateDeclaration,
- Provider.class);
+ TypeNames.PROVIDER);
}
private ContributionBinding buildDelegateBinding(
ContributionBinding.Builder<?, ?> builder,
DelegateDeclaration delegateDeclaration,
- Class<?> frameworkType) {
- boolean isKotlinObject =
- metadataUtil.isObjectClass(delegateDeclaration.contributingModule().get())
- || metadataUtil.isCompanionObjectClass(delegateDeclaration.contributingModule().get());
+ ClassName frameworkType) {
return builder
.contributionType(delegateDeclaration.contributionType())
.bindingElement(delegateDeclaration.bindingElement().get())
.contributingModule(delegateDeclaration.contributingModule().get())
- .isContributingModuleKotlinObject(isKotlinObject)
.key(keyFactory.forDelegateBinding(delegateDeclaration, frameworkType))
.dependencies(delegateDeclaration.delegateRequest())
.wrappedMapKeyAnnotation(delegateDeclaration.wrappedMapKey())
@@ -491,7 +460,7 @@ public final class BindingFactory {
}
/**
- * Returns an {@link dagger.model.BindingKind#OPTIONAL} binding for {@code key}.
+ * Returns an {@link dagger.spi.model.BindingKind#OPTIONAL} binding for {@code key}.
*
* @param requestKind the kind of request for the optional binding
* @param underlyingKeyBindings the possibly empty set of bindings that exist in the component for
@@ -523,56 +492,78 @@ public final class BindingFactory {
.build();
}
- /** Returns a {@link dagger.model.BindingKind#MEMBERS_INJECTOR} binding. */
+ /** Returns a {@link dagger.spi.model.BindingKind#MEMBERS_INJECTOR} binding. */
public ProvisionBinding membersInjectorBinding(
Key key, MembersInjectionBinding membersInjectionBinding) {
return ProvisionBinding.builder()
.key(key)
.contributionType(ContributionType.UNIQUE)
.kind(MEMBERS_INJECTOR)
- .bindingElement(MoreTypes.asTypeElement(membersInjectionBinding.key().type()))
+ .bindingElement(membersInjectionBinding.key().type().xprocessing().getTypeElement())
.provisionDependencies(membersInjectionBinding.dependencies())
.injectionSites(membersInjectionBinding.injectionSites())
.build();
}
/**
- * Returns a {@link dagger.model.BindingKind#MEMBERS_INJECTION} binding.
+ * Returns a {@link dagger.spi.model.BindingKind#MEMBERS_INJECTION} binding.
*
* @param resolvedType if {@code declaredType} is a generic class and {@code resolvedType} is a
* parameterization of that type, the returned binding will be for the resolved type
*/
// TODO(dpb): See if we can just pass one nongeneric/parameterized type.
- public MembersInjectionBinding membersInjectionBinding(
- DeclaredType declaredType, Optional<TypeMirror> resolvedType) {
+ public MembersInjectionBinding membersInjectionBinding(XType type, Optional<XType> resolvedType) {
// If the class this is injecting has some type arguments, resolve everything.
- if (!declaredType.getTypeArguments().isEmpty() && resolvedType.isPresent()) {
- DeclaredType resolved = asDeclared(resolvedType.get());
- // Validate that we're resolving from the correct type.
- checkState(
- types.isSameType(types.erasure(resolved), types.erasure(declaredType)),
- "erased expected type: %s, erased actual type: %s",
- types.erasure(resolved),
- types.erasure(declaredType));
- declaredType = resolved;
+ if (!type.getTypeArguments().isEmpty() && resolvedType.isPresent()) {
+ checkIsSameErasedType(resolvedType.get(), type);
+ type = resolvedType.get();
}
- ImmutableSortedSet<InjectionSite> injectionSites =
- injectionSiteFactory.getInjectionSites(declaredType);
+ ImmutableSortedSet<InjectionSite> injectionSites = injectionSiteFactory.getInjectionSites(type);
ImmutableSet<DependencyRequest> dependencies =
injectionSites.stream()
.flatMap(injectionSite -> injectionSite.dependencies().stream())
.collect(toImmutableSet());
- Key key = keyFactory.forMembersInjectedType(declaredType);
- TypeElement typeElement = MoreElements.asType(declaredType.asElement());
- return new AutoValue_MembersInjectionBinding(
- key,
+ return MembersInjectionBinding.create(
+ keyFactory.forMembersInjectedType(type),
dependencies,
- typeElement,
- hasNonDefaultTypeParameters(typeElement, key.type(), types)
+ hasNonDefaultTypeParameters(type)
? Optional.of(
- membersInjectionBinding(asDeclared(typeElement.asType()), Optional.empty()))
+ membersInjectionBinding(type.getTypeElement().getType(), Optional.empty()))
: Optional.empty(),
injectionSites);
}
+
+ private void checkIsSameErasedType(XType type1, XType type2) {
+ checkState(
+ types.isSameType(types.erasure(toJavac(type1)), types.erasure(toJavac(type2))),
+ "erased expected type: %s, erased actual type: %s",
+ types.erasure(toJavac(type1)),
+ types.erasure(toJavac(type2)));
+ }
+
+ private static boolean hasNonDefaultTypeParameters(XType type) {
+ // If the type is not declared, then it can't have type parameters.
+ if (!isDeclared(type)) {
+ return false;
+ }
+
+ // If the element has no type parameters, none can be non-default.
+ XType defaultType = type.getTypeElement().getType();
+ if (defaultType.getTypeArguments().isEmpty()) {
+ return false;
+ }
+
+ // The actual type parameter size can be different if the user is using a raw type.
+ if (defaultType.getTypeArguments().size() != type.getTypeArguments().size()) {
+ return true;
+ }
+
+ for (int i = 0; i < defaultType.getTypeArguments().size(); i++) {
+ if (!defaultType.getTypeArguments().get(i).isSameType(type.getTypeArguments().get(i))) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/java/dagger/internal/codegen/binding/BindingGraph.java b/java/dagger/internal/codegen/binding/BindingGraph.java
index 533d113f1..ee5a54b94 100644
--- a/java/dagger/internal/codegen/binding/BindingGraph.java
+++ b/java/dagger/internal/codegen/binding/BindingGraph.java
@@ -18,12 +18,16 @@ package dagger.internal.codegen.binding;
import static com.google.common.collect.Iterables.transform;
import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
+import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
import static dagger.internal.codegen.extension.DaggerStreams.presentValues;
import static dagger.internal.codegen.extension.DaggerStreams.stream;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XExecutableParameterElement;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableList;
@@ -31,24 +35,28 @@ import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Maps;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
import com.google.common.graph.ImmutableNetwork;
import com.google.common.graph.Traverser;
-import dagger.model.BindingGraph.ChildFactoryMethodEdge;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.BindingGraph.Edge;
-import dagger.model.BindingGraph.Node;
-import dagger.model.ComponentPath;
-import dagger.model.Key;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
+import dagger.internal.codegen.base.TarjanSCCs;
+import dagger.spi.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.spi.model.BindingGraph.ComponentNode;
+import dagger.spi.model.BindingGraph.DependencyEdge;
+import dagger.spi.model.BindingGraph.Edge;
+import dagger.spi.model.BindingGraph.Node;
+import dagger.spi.model.ComponentPath;
+import dagger.spi.model.DaggerTypeElement;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
+import java.util.Set;
+import java.util.stream.Stream;
/**
* A graph that represents a single component or subcomponent within a fully validated top-level
@@ -57,8 +65,12 @@ import javax.lang.model.element.VariableElement;
@AutoValue
public abstract class BindingGraph {
+ /**
+ * A graph that represents the entire network of nodes from all components, subcomponents and
+ * their bindings.
+ */
@AutoValue
- abstract static class TopLevelBindingGraph extends dagger.model.BindingGraph {
+ public abstract static class TopLevelBindingGraph extends dagger.spi.model.BindingGraph {
static TopLevelBindingGraph create(
ImmutableNetwork<Node, Edge> network, boolean isFullBindingGraph) {
TopLevelBindingGraph topLevelBindingGraph =
@@ -82,15 +94,18 @@ public abstract class BindingGraph {
// AutoValue to prevent exposing this data outside of the class.
topLevelBindingGraph.componentNodes = componentNodes;
topLevelBindingGraph.subcomponentNodes = subcomponentNodesBuilder.build();
+ topLevelBindingGraph.frameworkTypeBindings =
+ frameworkRequestBindingSet(network, topLevelBindingGraph.bindings());
return topLevelBindingGraph;
}
private ImmutableMap<ComponentPath, ComponentNode> componentNodes;
private ImmutableSetMultimap<ComponentNode, ComponentNode> subcomponentNodes;
+ private ImmutableSet<Binding> frameworkTypeBindings;
TopLevelBindingGraph() {}
- // This overrides dagger.model.BindingGraph with a more efficient implementation.
+ // This overrides dagger.spi.model.BindingGraph with a more efficient implementation.
@Override
public Optional<ComponentNode> componentNode(ComponentPath componentPath) {
return componentNodes.containsKey(componentPath)
@@ -117,6 +132,61 @@ public abstract class BindingGraph {
ImmutableListMultimap<ComponentPath, BindingNode> bindingsByComponent() {
return Multimaps.index(transform(bindings(), BindingNode.class::cast), Node::componentPath);
}
+
+ /** Returns a {@link Comparator} in the same order as {@link Network#nodes()}. */
+ @Memoized
+ Comparator<Node> nodeOrder() {
+ Map<Node, Integer> nodeOrderMap = Maps.newHashMapWithExpectedSize(network().nodes().size());
+ int i = 0;
+ for (Node node : network().nodes()) {
+ nodeOrderMap.put(node, i++);
+ }
+ return (n1, n2) -> nodeOrderMap.get(n1).compareTo(nodeOrderMap.get(n2));
+ }
+
+ /** Returns the set of strongly connected nodes in this graph in reverse topological order. */
+ @Memoized
+ public ImmutableSet<ImmutableSet<Node>> stronglyConnectedNodes() {
+ return TarjanSCCs.<Node>compute(
+ ImmutableSet.copyOf(network().nodes()),
+ // NetworkBuilder does not have a stable successor order, so we have to roll our own
+ // based on the node order, which is stable.
+ // TODO(bcorso): Fix once https://github.com/google/guava/issues/2650 is fixed.
+ node ->
+ network().successors(node).stream().sorted(nodeOrder()).collect(toImmutableList()));
+ }
+
+ public boolean hasFrameworkRequest(Binding binding) {
+ return frameworkTypeBindings.contains(binding);
+ }
+
+ private static ImmutableSet<Binding> frameworkRequestBindingSet(
+ ImmutableNetwork<Node, Edge> network, ImmutableSet<dagger.spi.model.Binding> bindings) {
+ Set<Binding> frameworkRequestBindings = new HashSet<>();
+ for (dagger.spi.model.Binding binding : bindings) {
+ ImmutableList<DependencyEdge> edges =
+ network.inEdges(binding).stream()
+ .flatMap(instancesOf(DependencyEdge.class))
+ .collect(toImmutableList());
+ for (DependencyEdge edge : edges) {
+ DependencyRequest request = edge.dependencyRequest();
+ switch (request.kind()) {
+ case INSTANCE:
+ case FUTURE:
+ continue;
+ case PRODUCED:
+ case PRODUCER:
+ case MEMBERS_INJECTION:
+ case PROVIDER_OF_LAZY:
+ case LAZY:
+ case PROVIDER:
+ frameworkRequestBindings.add(((BindingNode) binding).delegate());
+ break;
+ }
+ }
+ }
+ return ImmutableSet.copyOf(frameworkRequestBindings);
+ }
}
static BindingGraph create(
@@ -128,42 +198,34 @@ public abstract class BindingGraph {
Optional<BindingGraph> parent,
ComponentNode componentNode,
TopLevelBindingGraph topLevelBindingGraph) {
- List<BindingNode> reachableBindingNodes = new ArrayList<>();
- for (ComponentPath path = componentNode.componentPath();
- !path.components().isEmpty();
- path = ComponentPath.create(path.components().subList(0, path.components().size() - 1))) {
- reachableBindingNodes.addAll(topLevelBindingGraph.bindingsByComponent().get(path));
- }
-
- // Construct the maps of the ContributionBindings and MembersInjectionBindings.
- Map<Key, BindingNode> contributionBindings = new HashMap<>();
- Map<Key, BindingNode> membersInjectionBindings = new HashMap<>();
- for (BindingNode bindingNode : reachableBindingNodes) {
- Map<Key, BindingNode> bindingsMap;
- if (bindingNode.delegate() instanceof ContributionBinding) {
- bindingsMap = contributionBindings;
- } else if (bindingNode.delegate() instanceof MembersInjectionBinding) {
- bindingsMap = membersInjectionBindings;
- } else {
- throw new AssertionError("Unexpected binding node type: " + bindingNode.delegate());
- }
-
- // TODO(bcorso): Mapping binding nodes by key is flawed since bindings that depend on local
- // multibindings can have multiple nodes (one in each component). In this case, we choose the
- // node in the child-most component since this is likely the node that users of this
- // BindingGraph will want (and to remain consisted with LegacyBindingGraph). However, ideally
- // we would avoid this ambiguity by getting dependencies directly from the top-level network.
- // In particular, rather than using a Binding's list of DependencyRequests (which only
- // contains the key) we would use the top-level network to find the DependencyEdges for a
- // particular BindingNode.
- Key key = bindingNode.key();
- if (!bindingsMap.containsKey(key)
- // Always choose the child-most binding node.
- || bindingNode.componentPath().components().size()
- > bindingsMap.get(key).componentPath().components().size()) {
- bindingsMap.put(key, bindingNode);
- }
- }
+ // TODO(bcorso): Mapping binding nodes by key is flawed since bindings that depend on local
+ // multibindings can have multiple nodes (one in each component). In this case, we choose the
+ // node in the child-most component since this is likely the node that users of this
+ // BindingGraph will want (and to remain consistent with LegacyBindingGraph). However, ideally
+ // we would avoid this ambiguity by getting dependencies directly from the top-level network.
+ // In particular, rather than using a Binding's list of DependencyRequests (which only
+ // contains the key) we would use the top-level network to find the DependencyEdges for a
+ // particular BindingNode.
+ Map<Key, BindingNode> contributionBindings = new LinkedHashMap<>();
+ Map<Key, BindingNode> membersInjectionBindings = new LinkedHashMap<>();
+
+ // Construct the maps of the ContributionBindings and MembersInjectionBindings by iterating
+ // bindings from this component and then from each successive parent. If a binding exists in
+ // multple components, this order ensures that the child-most binding is always chosen first.
+ Stream.iterate(componentNode.componentPath(), ComponentPath::parent)
+ // Stream.iterate is inifinte stream so we need limit it to the known size of the path.
+ .limit(componentNode.componentPath().components().size())
+ .flatMap(path -> topLevelBindingGraph.bindingsByComponent().get(path).stream())
+ .forEach(
+ bindingNode -> {
+ if (bindingNode.delegate() instanceof ContributionBinding) {
+ contributionBindings.putIfAbsent(bindingNode.key(), bindingNode);
+ } else if (bindingNode.delegate() instanceof MembersInjectionBinding) {
+ membersInjectionBindings.putIfAbsent(bindingNode.key(), bindingNode);
+ } else {
+ throw new AssertionError("Unexpected binding node type: " + bindingNode.delegate());
+ }
+ });
BindingGraph bindingGraph = new AutoValue_BindingGraph(componentNode, topLevelBindingGraph);
@@ -185,6 +247,7 @@ public abstract class BindingGraph {
contributionBindings.values().stream()
.map(BindingNode::contributingModule)
.flatMap(presentValues())
+ .map(DaggerTypeElement::xprocessing)
.collect(toImmutableSet());
return bindingGraph;
@@ -194,7 +257,7 @@ public abstract class BindingGraph {
private ImmutableMap<Key, BindingNode> membersInjectionBindings;
private ImmutableSet<ModuleDescriptor> inheritedModules;
private ImmutableSet<ModuleDescriptor> ownedModules;
- private ImmutableSet<TypeElement> bindingModules;
+ private ImmutableSet<XTypeElement> bindingModules;
BindingGraph() {}
@@ -214,6 +277,30 @@ public abstract class BindingGraph {
return ((ComponentNodeImpl) componentNode()).componentDescriptor();
}
+ /**
+ * Returns the {@link ContributionBinding} for the given {@link Key} in this component or {@link
+ * Optional#empty()} if one doesn't exist.
+ */
+ public final Optional<Binding> localContributionBinding(Key key) {
+ return contributionBindings.containsKey(key)
+ ? Optional.of(contributionBindings.get(key))
+ .filter(bindingNode -> bindingNode.componentPath().equals(componentPath()))
+ .map(BindingNode::delegate)
+ : Optional.empty();
+ }
+
+ /**
+ * Returns the {@link MembersInjectionBinding} for the given {@link Key} in this component or
+ * {@link Optional#empty()} if one doesn't exist.
+ */
+ public final Optional<Binding> localMembersInjectionBinding(Key key) {
+ return membersInjectionBindings.containsKey(key)
+ ? Optional.of(membersInjectionBindings.get(key))
+ .filter(bindingNode -> bindingNode.componentPath().equals(componentPath()))
+ .map(BindingNode::delegate)
+ : Optional.empty();
+ }
+
/** Returns the {@link ContributionBinding} for the given {@link Key}. */
public final ContributionBinding contributionBinding(Key key) {
return (ContributionBinding) contributionBindings.get(key).delegate();
@@ -229,9 +316,9 @@ public abstract class BindingGraph {
: Optional.empty();
}
- /** Returns the {@link TypeElement} for the component this graph represents. */
- public final TypeElement componentTypeElement() {
- return componentPath().currentComponent();
+ /** Returns the {@link XTypeElement} for the component this graph represents. */
+ public final XTypeElement componentTypeElement() {
+ return componentPath().currentComponent().xprocessing();
}
/**
@@ -242,8 +329,10 @@ public abstract class BindingGraph {
* subcomponents}, this set will be the transitive modules that are not owned by any of their
* ancestors.
*/
- public final ImmutableSet<TypeElement> ownedModuleTypes() {
- return ownedModules.stream().map(ModuleDescriptor::moduleElement).collect(toImmutableSet());
+ public final ImmutableSet<XTypeElement> ownedModuleTypes() {
+ return ownedModules.stream()
+ .map(ModuleDescriptor::moduleElement)
+ .collect(toImmutableSet());
}
/**
@@ -252,7 +341,7 @@ public abstract class BindingGraph {
* <p>This factory method is the one defined in the parent component's interface.
*
* <p>In the example below, the {@link BindingGraph#factoryMethod} for {@code ChildComponent}
- * would return the {@link ExecutableElement}: {@code childComponent(ChildModule1)} .
+ * would return the {@link XExecutableElement}: {@code childComponent(ChildModule1)} .
*
* <pre><code>
* {@literal @Component}
@@ -262,24 +351,25 @@ public abstract class BindingGraph {
* </code></pre>
*/
// TODO(b/73294201): Consider returning the resolved ExecutableType for the factory method.
- public final Optional<ExecutableElement> factoryMethod() {
+ public final Optional<XExecutableElement> factoryMethod() {
return topLevelBindingGraph().network().inEdges(componentNode()).stream()
.filter(edge -> edge instanceof ChildFactoryMethodEdge)
- .map(edge -> ((ChildFactoryMethodEdge) edge).factoryMethod())
+ .map(edge -> ((ChildFactoryMethodEdge) edge).factoryMethod().xprocessing())
.collect(toOptional());
}
/**
* Returns a map between the {@linkplain ComponentRequirement component requirement} and the
- * corresponding {@link VariableElement} for each module parameter in the {@linkplain
+ * corresponding {@link XExecutableParameterElement} for each module parameter in the {@linkplain
* BindingGraph#factoryMethod factory method}.
*/
// TODO(dpb): Consider disallowing modules if none of their bindings are used.
- public final ImmutableMap<ComponentRequirement, VariableElement> factoryMethodParameters() {
+ public final ImmutableMap<ComponentRequirement, XExecutableParameterElement>
+ factoryMethodParameters() {
return factoryMethod().get().getParameters().stream()
.collect(
toImmutableMap(
- parameter -> ComponentRequirement.forModule(parameter.asType()),
+ parameter -> ComponentRequirement.forModule(parameter.getType()),
parameter -> parameter));
}
@@ -294,7 +384,7 @@ public abstract class BindingGraph {
*/
@Memoized
public ImmutableSet<ComponentRequirement> componentRequirements() {
- ImmutableSet<TypeElement> requiredModules =
+ ImmutableSet<XTypeElement> requiredModules =
stream(Traverser.forTree(BindingGraph::subgraphs).depthFirstPostOrder(this))
.flatMap(graph -> graph.bindingModules.stream())
.filter(ownedModuleTypes()::contains)
@@ -312,11 +402,16 @@ public abstract class BindingGraph {
return requirements.build();
}
- /** Returns all {@link ComponentDescriptor}s in the {@link TopLevelBindingGraph}. */
- public final ImmutableSet<ComponentDescriptor> componentDescriptors() {
+ /**
+ * Returns all {@link ComponentDescriptor}s in the {@link TopLevelBindingGraph} mapped by the
+ * component path.
+ */
+ @Memoized
+ public ImmutableMap<ComponentPath, ComponentDescriptor> componentDescriptorsByPath() {
return topLevelBindingGraph().componentNodes().stream()
- .map(componentNode -> ((ComponentNodeImpl) componentNode).componentDescriptor())
- .collect(toImmutableSet());
+ .map(ComponentNodeImpl.class::cast)
+ .collect(
+ toImmutableMap(ComponentNode::componentPath, ComponentNodeImpl::componentDescriptor));
}
@Memoized
@@ -326,15 +421,9 @@ public abstract class BindingGraph {
.collect(toImmutableList());
}
- public final ImmutableSet<BindingNode> bindingNodes(Key key) {
- ImmutableSet.Builder<BindingNode> builder = ImmutableSet.builder();
- if (contributionBindings.containsKey(key)) {
- builder.add(contributionBindings.get(key));
- }
- if (membersInjectionBindings.containsKey(key)) {
- builder.add(membersInjectionBindings.get(key));
- }
- return builder.build();
+ /** Returns the list of all {@link BindingNode}s local to this component. */
+ public ImmutableList<BindingNode> localBindingNodes() {
+ return topLevelBindingGraph().bindingsByComponent().get(componentPath());
}
@Memoized
diff --git a/java/dagger/internal/codegen/binding/BindingGraphConverter.java b/java/dagger/internal/codegen/binding/BindingGraphConverter.java
index b882b37a9..7d24bca89 100644
--- a/java/dagger/internal/codegen/binding/BindingGraphConverter.java
+++ b/java/dagger/internal/codegen/binding/BindingGraphConverter.java
@@ -16,13 +16,18 @@
package dagger.internal.codegen.binding;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static androidx.room.compiler.processing.compat.XConverters.toXProcessing;
import static com.google.auto.common.MoreTypes.asTypeElement;
import static com.google.common.base.Verify.verify;
import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import static dagger.internal.codegen.extension.DaggerGraphs.unreachableNodes;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.model.BindingKind.SUBCOMPONENT_CREATOR;
+import static dagger.spi.model.BindingKind.SUBCOMPONENT_CREATOR;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableList;
@@ -35,14 +40,16 @@ import com.google.common.graph.Network;
import com.google.common.graph.NetworkBuilder;
import dagger.internal.codegen.binding.BindingGraph.TopLevelBindingGraph;
import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.Edge;
-import dagger.model.BindingGraph.MissingBinding;
-import dagger.model.BindingGraph.Node;
-import dagger.model.ComponentPath;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
+import dagger.spi.model.BindingGraph.ComponentNode;
+import dagger.spi.model.BindingGraph.DependencyEdge;
+import dagger.spi.model.BindingGraph.Edge;
+import dagger.spi.model.BindingGraph.MissingBinding;
+import dagger.spi.model.BindingGraph.Node;
+import dagger.spi.model.ComponentPath;
+import dagger.spi.model.DaggerExecutableElement;
+import dagger.spi.model.DaggerTypeElement;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
@@ -54,18 +61,21 @@ import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
-/** Converts {@link BindingGraph}s to {@link dagger.model.BindingGraph}s. */
+/** Converts {@link BindingGraph}s to {@link dagger.spi.model.BindingGraph}s. */
final class BindingGraphConverter {
+ private final XProcessingEnv processingEnv;
private final BindingDeclarationFormatter bindingDeclarationFormatter;
@Inject
- BindingGraphConverter(BindingDeclarationFormatter bindingDeclarationFormatter) {
+ BindingGraphConverter(
+ XProcessingEnv processingEnv, BindingDeclarationFormatter bindingDeclarationFormatter) {
+ this.processingEnv = processingEnv;
this.bindingDeclarationFormatter = bindingDeclarationFormatter;
}
/**
- * Creates the external {@link dagger.model.BindingGraph} representing the given internal {@link
- * BindingGraph}.
+ * Creates the external {@link dagger.spi.model.BindingGraph} representing the given internal
+ * {@link BindingGraph}.
*/
BindingGraph convert(LegacyBindingGraph legacyBindingGraph, boolean isFullBindingGraph) {
MutableNetwork<Node, Edge> network = asNetwork(legacyBindingGraph);
@@ -86,7 +96,7 @@ final class BindingGraphConverter {
}
private MutableNetwork<Node, Edge> asNetwork(LegacyBindingGraph graph) {
- Converter converter = new Converter(bindingDeclarationFormatter);
+ Converter converter = new Converter();
converter.visitRootComponent(graph);
return converter.network;
}
@@ -116,14 +126,13 @@ final class BindingGraphConverter {
}
}
- private static final class Converter {
+ private final class Converter {
/** The path from the root graph to the currently visited graph. */
private final Deque<LegacyBindingGraph> bindingGraphPath = new ArrayDeque<>();
/** The {@link ComponentPath} for each component in {@link #bindingGraphPath}. */
private final Deque<ComponentPath> componentPaths = new ArrayDeque<>();
- private final BindingDeclarationFormatter bindingDeclarationFormatter;
private final MutableNetwork<Node, Edge> network =
NetworkBuilder.directed().allowsParallelEdges(true).allowsSelfLoops(true).build();
private final Set<BindingNode> bindings = new HashSet<>();
@@ -131,11 +140,6 @@ final class BindingGraphConverter {
private final Map<ResolvedBindingsWithPath, ImmutableSet<BindingNode>> resolvedBindingsMap =
new HashMap<>();
- /** Constructs a converter for a root (component, not subcomponent) binding graph. */
- private Converter(BindingDeclarationFormatter bindingDeclarationFormatter) {
- this.bindingDeclarationFormatter = bindingDeclarationFormatter;
- }
-
private void visitRootComponent(LegacyBindingGraph graph) {
visitComponent(graph, null);
}
@@ -164,6 +168,7 @@ final class BindingGraphConverter {
bindingGraphPath.stream()
.map(LegacyBindingGraph::componentDescriptor)
.map(ComponentDescriptor::typeElement)
+ .map(DaggerTypeElement::from)
.collect(toImmutableList()));
componentPaths.addLast(graphPath);
ComponentNode currentComponent =
@@ -188,7 +193,7 @@ final class BindingGraphConverter {
&& binding.componentPath().equals(currentComponent.componentPath())) {
network.addEdge(
binding,
- subcomponentNode(binding.key().type(), graph),
+ subcomponentNode(binding.key().type().java(), graph),
new SubcomponentCreatorBindingEdgeImpl(
resolvedBindings.subcomponentDeclarations()));
}
@@ -235,11 +240,11 @@ final class BindingGraphConverter {
private void visitSubcomponentFactoryMethod(
ComponentNode parentComponent,
ComponentNode currentComponent,
- ExecutableElement factoryMethod) {
+ XMethodElement factoryMethod) {
network.addEdge(
parentComponent,
currentComponent,
- new ChildFactoryMethodEdgeImpl(factoryMethod));
+ new ChildFactoryMethodEdgeImpl(DaggerExecutableElement.from(factoryMethod)));
}
/**
@@ -256,7 +261,7 @@ final class BindingGraphConverter {
*/
private ComponentPath pathFromRootToAncestor(TypeElement ancestor) {
for (ComponentPath componentPath : componentPaths) {
- if (componentPath.currentComponent().equals(ancestor)) {
+ if (componentPath.currentComponent().java().equals(ancestor)) {
return componentPath;
}
}
@@ -271,7 +276,7 @@ final class BindingGraphConverter {
*/
private LegacyBindingGraph graphForAncestor(TypeElement ancestor) {
for (LegacyBindingGraph graph : bindingGraphPath) {
- if (graph.componentDescriptor().typeElement().equals(ancestor)) {
+ if (toJavac(graph.componentDescriptor().typeElement()).equals(ancestor)) {
return graph;
}
}
@@ -281,8 +286,8 @@ final class BindingGraphConverter {
}
/**
- * Adds a {@link dagger.model.BindingGraph.DependencyEdge} from a node to the binding(s) that
- * satisfy a dependency request.
+ * Adds a {@link dagger.spi.model.BindingGraph.DependencyEdge} from a node to the binding(s)
+ * that satisfy a dependency request.
*/
private void addDependencyEdges(Node source, DependencyRequest dependencyRequest) {
ResolvedBindings dependencies = resolvedDependencies(source, dependencyRequest);
@@ -325,7 +330,7 @@ final class BindingGraphConverter {
private ResolvedBindings resolvedDependencies(
Node source, DependencyRequest dependencyRequest) {
- return graphForAncestor(source.componentPath().currentComponent())
+ return graphForAncestor(source.componentPath().currentComponent().java())
.resolvedBindings(bindingRequest(dependencyRequest));
}
@@ -373,11 +378,13 @@ final class BindingGraphConverter {
private ComponentNode subcomponentNode(
TypeMirror subcomponentBuilderType, LegacyBindingGraph graph) {
- TypeElement subcomponentBuilderElement = asTypeElement(subcomponentBuilderType);
+ XTypeElement subcomponentBuilderElement =
+ toXProcessing(asTypeElement(subcomponentBuilderType), processingEnv);
ComponentDescriptor subcomponent =
graph.componentDescriptor().getChildComponentWithBuilderType(subcomponentBuilderElement);
return ComponentNodeImpl.create(
- componentPath().childPath(subcomponent.typeElement()), subcomponent);
+ componentPath().childPath(DaggerTypeElement.from(subcomponent.typeElement())),
+ subcomponent);
}
}
diff --git a/java/dagger/internal/codegen/binding/BindingGraphFactory.java b/java/dagger/internal/codegen/binding/BindingGraphFactory.java
index a94f6b01e..ab0e90792 100644
--- a/java/dagger/internal/codegen/binding/BindingGraphFactory.java
+++ b/java/dagger/internal/codegen/binding/BindingGraphFactory.java
@@ -16,7 +16,8 @@
package dagger.internal.codegen.binding;
-import static com.google.auto.common.MoreTypes.asTypeElement;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static androidx.room.compiler.processing.compat.XConverters.toXProcessing;
import static com.google.auto.common.MoreTypes.isType;
import static com.google.auto.common.MoreTypes.isTypeOf;
import static com.google.common.base.Preconditions.checkArgument;
@@ -26,16 +27,19 @@ import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedFactoryType;
import static dagger.internal.codegen.binding.ComponentDescriptor.isComponentContributionMethod;
import static dagger.internal.codegen.binding.SourceFiles.generatedMonitoringModuleName;
-import static dagger.model.BindingKind.ASSISTED_INJECTION;
-import static dagger.model.BindingKind.DELEGATE;
-import static dagger.model.BindingKind.INJECTION;
-import static dagger.model.BindingKind.OPTIONAL;
-import static dagger.model.BindingKind.SUBCOMPONENT_CREATOR;
-import static dagger.model.RequestKind.MEMBERS_INJECTION;
+import static dagger.internal.codegen.xprocessing.XElements.asMethod;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
+import static dagger.spi.model.BindingKind.ASSISTED_INJECTION;
+import static dagger.spi.model.BindingKind.DELEGATE;
+import static dagger.spi.model.BindingKind.INJECTION;
+import static dagger.spi.model.BindingKind.OPTIONAL;
+import static dagger.spi.model.BindingKind.SUBCOMPONENT_CREATOR;
+import static dagger.spi.model.RequestKind.MEMBERS_INJECTION;
import static java.util.function.Predicate.isEqual;
import static javax.lang.model.util.ElementFilter.methodsIn;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -47,17 +51,17 @@ import dagger.MembersInjector;
import dagger.Reusable;
import dagger.internal.codegen.base.ClearableCache;
import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.base.DaggerSuperficialValidation;
import dagger.internal.codegen.base.Keys;
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.OptionalType;
import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.Scope;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
import dagger.producers.internal.ProductionExecutorModule;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
+import dagger.spi.model.Scope;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
@@ -70,16 +74,15 @@ import java.util.Optional;
import java.util.Queue;
import java.util.Set;
import javax.inject.Inject;
-import javax.inject.Provider;
import javax.inject.Singleton;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeKind;
/** A factory for {@link BindingGraph} objects. */
@Singleton
public final class BindingGraphFactory implements ClearableCache {
+ private final XProcessingEnv processingEnv;
private final DaggerElements elements;
private final InjectBindingRegistry injectBindingRegistry;
private final KeyFactory keyFactory;
@@ -91,6 +94,7 @@ public final class BindingGraphFactory implements ClearableCache {
@Inject
BindingGraphFactory(
+ XProcessingEnv processingEnv,
DaggerElements elements,
InjectBindingRegistry injectBindingRegistry,
KeyFactory keyFactory,
@@ -98,6 +102,7 @@ public final class BindingGraphFactory implements ClearableCache {
ModuleDescriptor.Factory moduleDescriptorFactory,
BindingGraphConverter bindingGraphConverter,
CompilerOptions compilerOptions) {
+ this.processingEnv = processingEnv;
this.elements = elements;
this.injectBindingRegistry = injectBindingRegistry;
this.keyFactory = keyFactory;
@@ -138,7 +143,7 @@ public final class BindingGraphFactory implements ClearableCache {
for (ComponentRequirement dependency : componentDescriptor.dependencies()) {
explicitBindingsBuilder.add(bindingFactory.componentDependencyBinding(dependency));
List<ExecutableElement> dependencyMethods =
- methodsIn(elements.getAllMembers(dependency.typeElement()));
+ methodsIn(elements.getAllMembers(toJavac(dependency.typeElement())));
// Within a component dependency, we want to allow the same method to appear multiple
// times assuming it is the exact same method. We do this by tracking a set of bindings
@@ -147,9 +152,10 @@ public final class BindingGraphFactory implements ClearableCache {
HashMultimap<String, ContributionBinding> dedupeBindings = HashMultimap.create();
for (ExecutableElement method : dependencyMethods) {
// MembersInjection methods aren't "provided" explicitly, so ignore them.
- if (isComponentContributionMethod(elements, method)) {
- ContributionBinding binding = bindingFactory.componentDependencyMethodBinding(
- componentDescriptor, method);
+ if (isComponentContributionMethod(method)) {
+ ContributionBinding binding =
+ bindingFactory.componentDependencyMethodBinding(
+ componentDescriptor, asMethod(toXProcessing(method, processingEnv)));
if (dedupeBindings.put(
method.getSimpleName().toString(),
// Remove the binding element since we know that will be different, but everything
@@ -284,15 +290,16 @@ public final class BindingGraphFactory implements ClearableCache {
* @throws TypeNotPresentException if the module has not been generated yet. This will cause the
* processor to retry in a later processing round.
*/
- private ModuleDescriptor descriptorForMonitoringModule(TypeElement componentDefinitionType) {
+ private ModuleDescriptor descriptorForMonitoringModule(XTypeElement componentDefinitionType) {
return moduleDescriptorFactory.create(
- elements.checkTypePresent(
- generatedMonitoringModuleName(componentDefinitionType).toString()));
+ DaggerSuperficialValidation.requireTypeElement(
+ processingEnv, generatedMonitoringModuleName(componentDefinitionType)));
}
/** Returns a descriptor {@link ProductionExecutorModule}. */
private ModuleDescriptor descriptorForProductionExecutorModule() {
- return moduleDescriptorFactory.create(elements.getTypeElement(ProductionExecutorModule.class));
+ return moduleDescriptorFactory.create(
+ processingEnv.findTypeElement(TypeNames.PRODUCTION_EXECTUTOR_MODULE));
}
/** Indexes {@code bindingDeclarations} by {@link BindingDeclaration#key()}. */
@@ -411,19 +418,21 @@ public final class BindingGraphFactory implements ClearableCache {
}
// Add members injector binding
- if (isType(requestKey.type()) && isTypeOf(MembersInjector.class, requestKey.type())) {
+ if (isType(requestKey.type().java())
+ && isTypeOf(MembersInjector.class, requestKey.type().java())) {
injectBindingRegistry
.getOrFindMembersInjectorProvisionBinding(requestKey)
.ifPresent(bindings::add);
}
// Add Assisted Factory binding
- if (isType(requestKey.type())
- && requestKey.type().getKind() == TypeKind.DECLARED
- && isAssistedFactoryType(asTypeElement(requestKey.type()))) {
+ if (isType(requestKey.type().java())
+ && isDeclared(requestKey.type().xprocessing())
+ && isAssistedFactoryType(requestKey.type().xprocessing().getTypeElement())) {
bindings.add(
bindingFactory.assistedFactoryBinding(
- asTypeElement(requestKey.type()), Optional.of(requestKey.type())));
+ requestKey.type().xprocessing().getTypeElement(),
+ Optional.of(requestKey.type().xprocessing())));
}
// If there are no bindings, add the implicit @Inject-constructed binding if there is one.
@@ -486,7 +495,8 @@ public final class BindingGraphFactory implements ClearableCache {
checkArgument(subcomponentCreatorBinding.kind().equals(SUBCOMPONENT_CREATOR));
Resolver owningResolver = getOwningResolver(subcomponentCreatorBinding).get();
- TypeElement builderType = MoreTypes.asTypeElement(subcomponentCreatorBinding.key().type());
+ XTypeElement builderType =
+ subcomponentCreatorBinding.key().type().xprocessing().getTypeElement();
owningResolver.subcomponentsToResolve.add(
owningResolver.componentDescriptor.getChildComponentWithBuilderType(builderType));
}
@@ -515,9 +525,13 @@ public final class BindingGraphFactory implements ClearableCache {
private ImmutableSet<Key> keysMatchingRequestUncached(Key requestKey) {
ImmutableSet.Builder<Key> keys = ImmutableSet.builder();
keys.add(requestKey);
- keyFactory.unwrapSetKey(requestKey, Produced.class).ifPresent(keys::add);
- keyFactory.rewrapMapKey(requestKey, Producer.class, Provider.class).ifPresent(keys::add);
- keyFactory.rewrapMapKey(requestKey, Provider.class, Producer.class).ifPresent(keys::add);
+ keyFactory.unwrapSetKey(requestKey, TypeNames.PRODUCED).ifPresent(keys::add);
+ keyFactory
+ .rewrapMapKey(requestKey, TypeNames.PRODUCER, TypeNames.PROVIDER)
+ .ifPresent(keys::add);
+ keyFactory
+ .rewrapMapKey(requestKey, TypeNames.PROVIDER, TypeNames.PRODUCER)
+ .ifPresent(keys::add);
keys.addAll(keyFactory.implicitFrameworkMapKeys(requestKey));
return keys.build();
}
@@ -585,7 +599,7 @@ public final class BindingGraphFactory implements ClearableCache {
parentResolver.get().resolvedContributionBindings.get(requestKey);
return parentResolvedBindings.owningComponent(binding);
} else {
- return componentDescriptor.typeElement();
+ return toJavac(componentDescriptor.typeElement());
}
}
diff --git a/java/dagger/internal/codegen/binding/BindingNode.java b/java/dagger/internal/codegen/binding/BindingNode.java
index 78d440da6..aa0f6cb8e 100644
--- a/java/dagger/internal/codegen/binding/BindingNode.java
+++ b/java/dagger/internal/codegen/binding/BindingNode.java
@@ -24,25 +24,25 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import dagger.BindsOptionalOf;
import dagger.Module;
-import dagger.model.BindingKind;
-import dagger.model.ComponentPath;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.Scope;
import dagger.multibindings.Multibinds;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.ComponentPath;
+import dagger.spi.model.DaggerElement;
+import dagger.spi.model.DaggerTypeElement;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
+import dagger.spi.model.Scope;
import java.util.Optional;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
/**
- * An implementation of {@link dagger.model.Binding} that also exposes {@link BindingDeclaration}s
- * associated with the binding.
+ * An implementation of {@link dagger.spi.model.Binding} that also exposes {@link
+ * BindingDeclaration}s associated with the binding.
*/
-// TODO(dpb): Consider a supertype of dagger.model.Binding that
+// TODO(dpb): Consider a supertype of dagger.spi.model.Binding that
// dagger.internal.codegen.binding.Binding
// could also implement.
@AutoValue
-public abstract class BindingNode implements dagger.model.Binding {
+public abstract class BindingNode implements dagger.spi.model.Binding {
public static BindingNode create(
ComponentPath component,
Binding delegate,
@@ -72,8 +72,8 @@ public abstract class BindingNode implements dagger.model.Binding {
public abstract ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations();
/**
- * The {@link Element}s (other than the binding's {@link #bindingElement()}) that are associated
- * with the binding.
+ * The elements (other than the binding's {@link #bindingElement()}) that are associated with the
+ * binding.
*
* <ul>
* <li>{@linkplain BindsOptionalOf optional binding} declarations
@@ -97,13 +97,13 @@ public abstract class BindingNode implements dagger.model.Binding {
}
@Override
- public Optional<Element> bindingElement() {
- return delegate().bindingElement();
+ public Optional<DaggerElement> bindingElement() {
+ return delegate().bindingElement().map(DaggerElement::from);
}
@Override
- public Optional<TypeElement> contributingModule() {
- return delegate().contributingModule();
+ public Optional<DaggerTypeElement> contributingModule() {
+ return delegate().contributingModule().map(DaggerTypeElement::from);
}
@Override
diff --git a/java/dagger/internal/codegen/binding/BindingRequest.java b/java/dagger/internal/codegen/binding/BindingRequest.java
index d61d9cfba..6bb572dc6 100644
--- a/java/dagger/internal/codegen/binding/BindingRequest.java
+++ b/java/dagger/internal/codegen/binding/BindingRequest.java
@@ -16,13 +16,15 @@
package dagger.internal.codegen.binding;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static dagger.internal.codegen.base.RequestKinds.requestType;
+import androidx.room.compiler.processing.XType;
import com.google.auto.value.AutoValue;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.RequestKind;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
+import dagger.spi.model.RequestKind;
import java.util.Optional;
import javax.lang.model.type.TypeMirror;
@@ -47,12 +49,12 @@ public abstract class BindingRequest {
// associated with that FrameworkType as well, because we want to ensure that if a request
// comes in for that as a dependency first and as a framework instance later, they resolve to
// the same binding expression.
- // TODO(cgdecker): Instead of doing this, make ComponentBindingExpressions create a
- // BindingExpression for the RequestKind that simply delegates to the BindingExpression for the
- // FrameworkType. Then there are separate BindingExpressions, but we don't end up doing weird
- // things like creating two fields when there should only be one.
+ // TODO(cgdecker): Instead of doing this, make ComponentRequestRepresentations create a
+ // RequestRepresentation for the RequestKind that simply delegates to the RequestRepresentation
+ // for the FrameworkType. Then there are separate RequestRepresentations, but we don't end up
+ // doing weird things like creating two fields when there should only be one.
return new AutoValue_BindingRequest(
- key, Optional.of(requestKind), FrameworkType.forRequestKind(requestKind));
+ key, requestKind, FrameworkType.forRequestKind(requestKind));
}
/**
@@ -67,30 +69,27 @@ public abstract class BindingRequest {
/** Returns the {@link Key} for the requested binding. */
public abstract Key key();
- /** Returns the request kind associated with this request, if any. */
- public abstract Optional<RequestKind> requestKind();
+ /** Returns the request kind associated with this request. */
+ public abstract RequestKind requestKind();
/** Returns the framework type associated with this request, if any. */
public abstract Optional<FrameworkType> frameworkType();
/** Returns whether this request is of the given kind. */
public final boolean isRequestKind(RequestKind requestKind) {
- return requestKind.equals(requestKind().orElse(null));
+ return requestKind.equals(requestKind());
+ }
+
+ public final TypeMirror requestedType(XType contributedType, DaggerTypes types) {
+ return requestedType(toJavac(contributedType), types);
}
public final TypeMirror requestedType(TypeMirror contributedType, DaggerTypes types) {
- if (requestKind().isPresent()) {
- return requestType(requestKind().get(), contributedType, types);
- }
- return types.wrapType(contributedType, frameworkType().get().frameworkClass());
+ return requestType(requestKind(), contributedType, types);
}
/** Returns a name that can be used for the kind of request this is. */
public final String kindName() {
- Object requestKindObject =
- requestKind().isPresent()
- ? requestKind().get()
- : frameworkType().get().frameworkClass().getSimpleName();
- return requestKindObject.toString();
+ return requestKind().toString();
}
}
diff --git a/java/dagger/internal/codegen/binding/BindsTypeChecker.java b/java/dagger/internal/codegen/binding/BindsTypeChecker.java
index d850fd373..2010597b2 100644
--- a/java/dagger/internal/codegen/binding/BindsTypeChecker.java
+++ b/java/dagger/internal/codegen/binding/BindsTypeChecker.java
@@ -16,15 +16,16 @@
package dagger.internal.codegen.binding;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.collect.Iterables.getOnlyElement;
+import androidx.room.compiler.processing.XType;
import com.google.auto.common.MoreTypes;
import com.google.common.collect.ImmutableList;
import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.util.Map;
-import java.util.Set;
import javax.inject.Inject;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
@@ -35,14 +36,14 @@ import javax.lang.model.type.TypeMirror;
* Checks the assignability of one type to another, given a {@link ContributionType} context. This
* is used by {@link dagger.internal.codegen.validation.BindsMethodValidator} to validate that the
* right-hand- side of a {@link dagger.Binds} method is valid, as well as in {@link
- * dagger.internal.codegen.writing.DelegateBindingExpression} when the right-hand-side in generated
- * code might be an erased type due to accessibility.
+ * dagger.internal.codegen.writing.DelegateRequestRepresentation} when the right-hand-side in
+ * generated code might be an erased type due to accessibility.
*/
public final class BindsTypeChecker {
private final DaggerTypes types;
private final DaggerElements elements;
- // TODO(bcorso): Make this pkg-private. Used by DelegateBindingExpression.
+ // TODO(bcorso): Make this pkg-private. Used by DelegateRequestRepresentation.
@Inject
public BindsTypeChecker(DaggerTypes types, DaggerElements elements) {
this.types = types;
@@ -54,6 +55,15 @@ public final class BindsTypeChecker {
* ContributionType} context.
*/
public boolean isAssignable(
+ XType rightHandSide, XType leftHandSide, ContributionType contributionType) {
+ return isAssignable(toJavac(rightHandSide), toJavac(leftHandSide), contributionType);
+ }
+
+ /**
+ * Checks the assignability of {@code rightHandSide} to {@code leftHandSide} given a {@link
+ * ContributionType} context.
+ */
+ public boolean isAssignable(
TypeMirror rightHandSide, TypeMirror leftHandSide, ContributionType contributionType) {
return types.isAssignable(rightHandSide, desiredAssignableType(leftHandSide, contributionType));
}
@@ -67,6 +77,7 @@ public final class BindsTypeChecker {
DeclaredType parameterizedSetType = types.getDeclaredType(setElement(), leftHandSide);
return methodParameterType(parameterizedSetType, "add");
case SET_VALUES:
+ // TODO(b/211774331): The left hand side type should be limited to Set types.
return methodParameterType(MoreTypes.asDeclared(leftHandSide), "addAll");
case MAP:
DeclaredType parameterizedMapType =
@@ -98,11 +109,11 @@ public final class BindsTypeChecker {
}
private TypeElement setElement() {
- return elements.getTypeElement(Set.class);
+ return elements.getTypeElement(TypeNames.SET);
}
private TypeElement mapElement() {
- return elements.getTypeElement(Map.class);
+ return elements.getTypeElement(TypeNames.MAP);
}
private TypeMirror unboundedWildcard() {
diff --git a/java/dagger/internal/codegen/binding/ChildFactoryMethodEdgeImpl.java b/java/dagger/internal/codegen/binding/ChildFactoryMethodEdgeImpl.java
index c0565881a..465d17e4c 100644
--- a/java/dagger/internal/codegen/binding/ChildFactoryMethodEdgeImpl.java
+++ b/java/dagger/internal/codegen/binding/ChildFactoryMethodEdgeImpl.java
@@ -18,25 +18,25 @@ package dagger.internal.codegen.binding;
import static dagger.internal.codegen.base.ElementFormatter.elementToString;
-import dagger.model.BindingGraph.ChildFactoryMethodEdge;
-import javax.lang.model.element.ExecutableElement;
+import dagger.spi.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.spi.model.DaggerExecutableElement;
/** An implementation of {@link ChildFactoryMethodEdge}. */
public final class ChildFactoryMethodEdgeImpl implements ChildFactoryMethodEdge {
- private final ExecutableElement factoryMethod;
+ private final DaggerExecutableElement factoryMethod;
- ChildFactoryMethodEdgeImpl(ExecutableElement factoryMethod) {
+ ChildFactoryMethodEdgeImpl(DaggerExecutableElement factoryMethod) {
this.factoryMethod = factoryMethod;
}
@Override
- public ExecutableElement factoryMethod() {
+ public DaggerExecutableElement factoryMethod() {
return factoryMethod;
}
@Override
public String toString() {
- return elementToString(factoryMethod);
+ return elementToString(factoryMethod.java());
}
}
diff --git a/java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java b/java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java
index 5ea30ed42..29d5b0821 100644
--- a/java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java
+++ b/java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java
@@ -16,15 +16,19 @@
package dagger.internal.codegen.binding;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.auto.common.MoreTypes.asTypeElement;
import static com.google.common.base.Verify.verify;
import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.getCreatorAnnotations;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.getCreatorAnnotations;
+import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotations;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-
-import com.google.auto.common.MoreTypes;
+import static dagger.internal.codegen.xprocessing.XTypeElements.getAllUnimplementedMethods;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XExecutableParameterElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XMethodType;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableMap;
@@ -32,18 +36,12 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
-import dagger.BindsInstance;
-import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.base.ComponentCreatorAnnotation;
+import dagger.internal.codegen.base.ComponentCreatorKind;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
+import dagger.spi.model.DependencyRequest;
import java.util.List;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
/**
* A descriptor for a component <i>creator</i> type: that is, a type annotated with
@@ -61,10 +59,10 @@ public abstract class ComponentCreatorDescriptor {
}
/** The annotated creator type. */
- public abstract TypeElement typeElement();
+ public abstract XTypeElement typeElement();
/** The method that creates and returns a component instance. */
- public abstract ExecutableElement factoryMethod();
+ public abstract XMethodElement factoryMethod();
/**
* Multimap of component requirements to setter methods that set that requirement.
@@ -72,7 +70,7 @@ public abstract class ComponentCreatorDescriptor {
* <p>In a valid creator, there will be exactly one element per component requirement, so this
* method should only be called when validating the descriptor.
*/
- abstract ImmutableSetMultimap<ComponentRequirement, ExecutableElement> unvalidatedSetterMethods();
+ abstract ImmutableSetMultimap<ComponentRequirement, XMethodElement> unvalidatedSetterMethods();
/**
* Multimap of component requirements to factory method parameters that set that requirement.
@@ -80,7 +78,7 @@ public abstract class ComponentCreatorDescriptor {
* <p>In a valid creator, there will be exactly one element per component requirement, so this
* method should only be called when validating the descriptor.
*/
- abstract ImmutableSetMultimap<ComponentRequirement, VariableElement>
+ abstract ImmutableSetMultimap<ComponentRequirement, XExecutableParameterElement>
unvalidatedFactoryParameters();
/**
@@ -90,7 +88,7 @@ public abstract class ComponentCreatorDescriptor {
* <p>In a valid creator, there will be exactly one element per component requirement, so this
* method should only be called when validating the descriptor.
*/
- public final ImmutableSetMultimap<ComponentRequirement, Element>
+ public final ImmutableSetMultimap<ComponentRequirement, XElement>
unvalidatedRequirementElements() {
// ComponentCreatorValidator ensures that there are either setter methods or factory method
// parameters, but not both, so we can cheat a little here since we know that only one of
@@ -106,19 +104,19 @@ public abstract class ComponentCreatorDescriptor {
* set them.
*/
@Memoized
- ImmutableMap<ComponentRequirement, Element> requirementElements() {
+ ImmutableMap<ComponentRequirement, XElement> requirementElements() {
return flatten(unvalidatedRequirementElements());
}
/** Map of component requirements to setter methods for those requirements. */
@Memoized
- public ImmutableMap<ComponentRequirement, ExecutableElement> setterMethods() {
+ public ImmutableMap<ComponentRequirement, XMethodElement> setterMethods() {
return flatten(unvalidatedSetterMethods());
}
/** Map of component requirements to factory method parameters for those requirements. */
@Memoized
- public ImmutableMap<ComponentRequirement, VariableElement> factoryParameters() {
+ public ImmutableMap<ComponentRequirement, XExecutableParameterElement> factoryParameters() {
return flatten(unvalidatedFactoryParameters());
}
@@ -148,31 +146,26 @@ public abstract class ComponentCreatorDescriptor {
}
/** Returns the element in this creator that sets the given {@code requirement}. */
- final Element elementForRequirement(ComponentRequirement requirement) {
+ final XElement elementForRequirement(ComponentRequirement requirement) {
return requirementElements().get(requirement);
}
/** Creates a new {@link ComponentCreatorDescriptor} for the given creator {@code type}. */
public static ComponentCreatorDescriptor create(
- DeclaredType type,
- DaggerElements elements,
- DaggerTypes types,
- DependencyRequestFactory dependencyRequestFactory) {
- TypeElement typeElement = asTypeElement(type);
- TypeMirror componentType = typeElement.getEnclosingElement().asType();
-
- ImmutableSetMultimap.Builder<ComponentRequirement, ExecutableElement> setterMethods =
- ImmutableSetMultimap.builder();
-
- ExecutableElement factoryMethod = null;
- for (ExecutableElement method : elements.getUnimplementedMethods(typeElement)) {
- ExecutableType resolvedMethodType = MoreTypes.asExecutable(types.asMemberOf(type, method));
+ XTypeElement creator, DaggerTypes types, DependencyRequestFactory dependencyRequestFactory) {
+ XType componentType = creator.getEnclosingTypeElement().getType();
+ ImmutableSetMultimap.Builder<ComponentRequirement, XMethodElement> setterMethods =
+ ImmutableSetMultimap.builder();
+ XMethodElement factoryMethod = null;
+ for (XMethodElement method : getAllUnimplementedMethods(creator)) {
+ XMethodType resolvedMethodType = method.asMemberOf(creator.getType());
if (types.isSubtype(componentType, resolvedMethodType.getReturnType())) {
+ verify(factoryMethod == null); // validation should have ensured there's only 1.
factoryMethod = method;
} else {
- VariableElement parameter = getOnlyElement(method.getParameters());
- TypeMirror parameterType = getOnlyElement(resolvedMethodType.getParameterTypes());
+ XExecutableParameterElement parameter = getOnlyElement(method.getParameters());
+ XType parameterType = getOnlyElement(resolvedMethodType.getParameterTypes());
setterMethods.put(
requirement(method, parameter, parameterType, dependencyRequestFactory, method),
method);
@@ -180,44 +173,46 @@ public abstract class ComponentCreatorDescriptor {
}
verify(factoryMethod != null); // validation should have ensured this.
- ImmutableSetMultimap.Builder<ComponentRequirement, VariableElement> factoryParameters =
- ImmutableSetMultimap.builder();
+ ImmutableSetMultimap.Builder<ComponentRequirement, XExecutableParameterElement>
+ factoryParameters = ImmutableSetMultimap.builder();
- ExecutableType resolvedFactoryMethodType =
- MoreTypes.asExecutable(types.asMemberOf(type, factoryMethod));
- List<? extends VariableElement> parameters = factoryMethod.getParameters();
- List<? extends TypeMirror> parameterTypes = resolvedFactoryMethodType.getParameterTypes();
+ XMethodType resolvedFactoryMethodType = factoryMethod.asMemberOf(creator.getType());
+ List<XExecutableParameterElement> parameters = factoryMethod.getParameters();
+ List<XType> parameterTypes = resolvedFactoryMethodType.getParameterTypes();
for (int i = 0; i < parameters.size(); i++) {
- VariableElement parameter = parameters.get(i);
- TypeMirror parameterType = parameterTypes.get(i);
+ XExecutableParameterElement parameter = parameters.get(i);
+ XType parameterType = parameterTypes.get(i);
factoryParameters.put(
- requirement(factoryMethod, parameter, parameterType, dependencyRequestFactory, parameter),
+ requirement(
+ factoryMethod,
+ parameter,
+ parameterType,
+ dependencyRequestFactory,
+ parameter),
parameter);
}
-
// Validation should have ensured exactly one creator annotation is present on the type.
- ComponentCreatorAnnotation annotation = getOnlyElement(getCreatorAnnotations(typeElement));
+ ComponentCreatorAnnotation annotation = getOnlyElement(getCreatorAnnotations(creator));
return new AutoValue_ComponentCreatorDescriptor(
- annotation, typeElement, factoryMethod, setterMethods.build(), factoryParameters.build());
+ annotation, creator, factoryMethod, setterMethods.build(), factoryParameters.build());
}
private static ComponentRequirement requirement(
- ExecutableElement method,
- VariableElement parameter,
- TypeMirror type,
+ XMethodElement method,
+ XExecutableParameterElement parameter,
+ XType parameterType,
DependencyRequestFactory dependencyRequestFactory,
- Element elementForVariableName) {
- if (isAnnotationPresent(method, BindsInstance.class)
- || isAnnotationPresent(parameter, BindsInstance.class)) {
+ XElement elementForVariableName) {
+ if (method.hasAnnotation(TypeNames.BINDS_INSTANCE)
+ || parameter.hasAnnotation(TypeNames.BINDS_INSTANCE)) {
DependencyRequest request =
- dependencyRequestFactory.forRequiredResolvedVariable(parameter, type);
- String variableName = elementForVariableName.getSimpleName().toString();
+ dependencyRequestFactory.forRequiredResolvedVariable(parameter, parameterType);
return ComponentRequirement.forBoundInstance(
- request.key(), request.isNullable(), variableName);
+ request.key(), request.isNullable(), elementForVariableName);
}
- return moduleAnnotation(asTypeElement(type)).isPresent()
- ? ComponentRequirement.forModule(type)
- : ComponentRequirement.forDependency(type);
+ return parameterType.getTypeElement().hasAnyAnnotation(moduleAnnotations())
+ ? ComponentRequirement.forModule(parameterType)
+ : ComponentRequirement.forDependency(parameterType);
}
}
diff --git a/java/dagger/internal/codegen/binding/ComponentDescriptor.java b/java/dagger/internal/codegen/binding/ComponentDescriptor.java
index f6ea62c77..83a83556f 100644
--- a/java/dagger/internal/codegen/binding/ComponentDescriptor.java
+++ b/java/dagger/internal/codegen/binding/ComponentDescriptor.java
@@ -16,15 +16,23 @@
package dagger.internal.codegen.binding;
+import static androidx.room.compiler.processing.XElementKt.isMethod;
+import static androidx.room.compiler.processing.XTypeKt.isVoid;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.langmodel.DaggerTypes.isFutureType;
-import static javax.lang.model.element.Modifier.ABSTRACT;
+import static dagger.internal.codegen.langmodel.DaggerTypes.isTypeOf;
+import static dagger.internal.codegen.xprocessing.XTypes.isPrimitive;
import static javax.lang.model.type.TypeKind.VOID;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.base.Supplier;
@@ -35,24 +43,21 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.CheckReturnValue;
+import com.squareup.javapoet.TypeName;
import dagger.Component;
import dagger.Module;
import dagger.Subcomponent;
import dagger.internal.codegen.base.ComponentAnnotation;
-import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import dagger.model.Scope;
import dagger.producers.CancellationPolicy;
-import dagger.producers.ProductionComponent;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Scope;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
-import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
/**
@@ -67,6 +72,35 @@ import javax.lang.model.type.TypeMirror;
*/
@AutoValue
public abstract class ComponentDescriptor {
+ /** Creates a {@link ComponentDescriptor}. */
+ static ComponentDescriptor create(
+ ComponentAnnotation componentAnnotation,
+ XTypeElement component,
+ ImmutableSet<ComponentRequirement> componentDependencies,
+ ImmutableSet<ModuleDescriptor> transitiveModules,
+ ImmutableMap<XMethodElement, ComponentRequirement> dependenciesByDependencyMethod,
+ ImmutableSet<Scope> scopes,
+ ImmutableSet<ComponentDescriptor> subcomponentsFromModules,
+ ImmutableBiMap<ComponentMethodDescriptor, ComponentDescriptor> subcomponentsByFactoryMethod,
+ ImmutableBiMap<ComponentMethodDescriptor, ComponentDescriptor> subcomponentsByBuilderMethod,
+ ImmutableSet<ComponentMethodDescriptor> componentMethods,
+ Optional<ComponentCreatorDescriptor> creator) {
+ ComponentDescriptor descriptor =
+ new AutoValue_ComponentDescriptor(
+ componentAnnotation,
+ component,
+ componentDependencies,
+ transitiveModules,
+ dependenciesByDependencyMethod,
+ scopes,
+ subcomponentsFromModules,
+ subcomponentsByFactoryMethod,
+ subcomponentsByBuilderMethod,
+ componentMethods,
+ creator);
+ return descriptor;
+ }
+
/** The annotation that specifies that {@link #typeElement()} is a component. */
public abstract ComponentAnnotation annotation();
@@ -95,11 +129,11 @@ public abstract class ComponentDescriptor {
* The element that defines the component. This is the element to which the {@link #annotation()}
* was applied.
*/
- public abstract TypeElement typeElement();
+ public abstract XTypeElement typeElement();
/**
* The set of component dependencies listed in {@link Component#dependencies} or {@link
- * ProductionComponent#dependencies()}.
+ * dagger.producers.ProductionComponent#dependencies()}.
*/
public abstract ImmutableSet<ComponentRequirement> dependencies();
@@ -107,8 +141,8 @@ public abstract class ComponentDescriptor {
public final ImmutableSet<ComponentRequirement> dependenciesAndConcreteModules() {
return Stream.concat(
moduleTypes().stream()
- .filter(dep -> !dep.getModifiers().contains(ABSTRACT))
- .map(module -> ComponentRequirement.forModule(module.asType())),
+ .filter(dep -> !dep.isAbstract())
+ .map(module -> ComponentRequirement.forModule(module.getType())),
dependencies().stream())
.collect(toImmutableSet());
}
@@ -120,7 +154,7 @@ public abstract class ComponentDescriptor {
public abstract ImmutableSet<ModuleDescriptor> modules();
/** The types of the {@link #modules()}. */
- public final ImmutableSet<TypeElement> moduleTypes() {
+ public final ImmutableSet<XTypeElement> moduleTypes() {
return modules().stream().map(ModuleDescriptor::moduleElement).collect(toImmutableSet());
}
@@ -142,7 +176,7 @@ public abstract class ComponentDescriptor {
.filter(
module ->
module.bindings().stream().anyMatch(ContributionBinding::requiresModuleInstance))
- .map(module -> ComponentRequirement.forModule(module.moduleElement().asType()))
+ .map(module -> ComponentRequirement.forModule(module.moduleElement().getType()))
.forEach(requirements::add);
requirements.addAll(dependencies());
requirements.addAll(
@@ -158,15 +192,17 @@ public abstract class ComponentDescriptor {
* the enclosing type of the method; a method may be declared by a supertype of the actual
* dependency.
*/
- public abstract ImmutableMap<ExecutableElement, ComponentRequirement>
+ public abstract ImmutableMap<XMethodElement, ComponentRequirement>
dependenciesByDependencyMethod();
/** The {@linkplain #dependencies() component dependency} that defines a method. */
- public final ComponentRequirement getDependencyThatDefinesMethod(Element method) {
- checkArgument(
- method instanceof ExecutableElement, "method must be an executable element: %s", method);
- return checkNotNull(
- dependenciesByDependencyMethod().get(method), "no dependency implements %s", method);
+ public final ComponentRequirement getDependencyThatDefinesMethod(XElement method) {
+ checkArgument(isMethod(method), "method must be an executable element: %s", method);
+ checkState(
+ dependenciesByDependencyMethod().containsKey(method),
+ "no dependency implements %s",
+ method);
+ return dependenciesByDependencyMethod().get(method);
}
/** The scopes of the component. */
@@ -201,7 +237,7 @@ public abstract class ComponentDescriptor {
/** Returns a map of {@link #childComponents()} indexed by {@link #typeElement()}. */
@Memoized
- public ImmutableMap<TypeElement, ComponentDescriptor> childComponentsByElement() {
+ public ImmutableMap<XTypeElement, ComponentDescriptor> childComponentsByElement() {
return Maps.uniqueIndex(childComponents(), ComponentDescriptor::typeElement);
}
@@ -219,7 +255,7 @@ public abstract class ComponentDescriptor {
abstract ImmutableBiMap<ComponentMethodDescriptor, ComponentDescriptor>
childComponentsDeclaredByBuilderEntryPoints();
- private final Supplier<ImmutableMap<TypeElement, ComponentDescriptor>>
+ private final Supplier<ImmutableMap<XTypeElement, ComponentDescriptor>>
childComponentsByBuilderType =
Suppliers.memoize(
() ->
@@ -231,7 +267,7 @@ public abstract class ComponentDescriptor {
child -> child)));
/** Returns the child component with the given builder type. */
- final ComponentDescriptor getChildComponentWithBuilderType(TypeElement builderType) {
+ final ComponentDescriptor getChildComponentWithBuilderType(XTypeElement builderType) {
return checkNotNull(
childComponentsByBuilderType.get().get(builderType),
"no child component found for builder type %s",
@@ -283,7 +319,8 @@ public abstract class ComponentDescriptor {
*/
public final Optional<CancellationPolicy> cancellationPolicy() {
return isProduction()
- ? Optional.ofNullable(typeElement().getAnnotation(CancellationPolicy.class))
+ // TODO(bcorso): Get values from XAnnotation instead of using CancellationPolicy directly.
+ ? Optional.ofNullable(toJavac(typeElement()).getAnnotation(CancellationPolicy.class))
: Optional.empty();
}
@@ -302,7 +339,7 @@ public abstract class ComponentDescriptor {
@AutoValue
public abstract static class ComponentMethodDescriptor {
/** The method itself. Note that this may be declared on a supertype of the component. */
- public abstract ExecutableElement methodElement();
+ public abstract XMethodElement methodElement();
/**
* The dependency request for production, provision, and subcomponent creator methods. Absent
@@ -321,16 +358,16 @@ public abstract class ComponentDescriptor {
public TypeMirror resolvedReturnType(DaggerTypes types) {
checkState(dependencyRequest().isPresent());
- TypeMirror returnType = methodElement().getReturnType();
- if (returnType.getKind().isPrimitive() || returnType.getKind().equals(VOID)) {
- return returnType;
+ XType returnType = methodElement().getReturnType();
+ if (isPrimitive(returnType) || isVoid(returnType)) {
+ return toJavac(returnType);
}
return BindingRequest.bindingRequest(dependencyRequest().get())
- .requestedType(dependencyRequest().get().key().type(), types);
+ .requestedType(dependencyRequest().get().key().type().java(), types);
}
/** A {@link ComponentMethodDescriptor}builder for a method. */
- public static Builder builder(ExecutableElement method) {
+ public static Builder builder(XMethodElement method) {
return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor.Builder()
.methodElement(method);
}
@@ -340,7 +377,7 @@ public abstract class ComponentDescriptor {
@CanIgnoreReturnValue
public interface Builder {
/** @see ComponentMethodDescriptor#methodElement() */
- Builder methodElement(ExecutableElement methodElement);
+ Builder methodElement(XMethodElement methodElement);
/** @see ComponentMethodDescriptor#dependencyRequest() */
Builder dependencyRequest(DependencyRequest dependencyRequest);
@@ -362,15 +399,23 @@ public abstract class ComponentDescriptor {
* Returns {@code true} if a method could be a component entry point but not a members-injection
* method.
*/
- static boolean isComponentContributionMethod(DaggerElements elements, ExecutableElement method) {
+ static boolean isComponentContributionMethod(XMethodElement method) {
+ return isComponentContributionMethod(toJavac(method));
+ }
+
+ /**
+ * Returns {@code true} if a method could be a component entry point but not a members-injection
+ * method.
+ */
+ static boolean isComponentContributionMethod(ExecutableElement method) {
return method.getParameters().isEmpty()
&& !method.getReturnType().getKind().equals(VOID)
- && !elements.getTypeElement(Object.class).equals(method.getEnclosingElement())
+ && !isTypeOf(TypeName.OBJECT, method.getEnclosingElement().asType())
&& !NON_CONTRIBUTING_OBJECT_METHOD_NAMES.contains(method.getSimpleName().toString());
}
/** Returns {@code true} if a method could be a component production entry point. */
- static boolean isComponentProductionMethod(DaggerElements elements, ExecutableElement method) {
- return isComponentContributionMethod(elements, method) && isFutureType(method.getReturnType());
+ static boolean isComponentProductionMethod(XMethodElement method) {
+ return isComponentContributionMethod(method) && isFutureType(method.getReturnType());
}
}
diff --git a/java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java b/java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java
index f13aa50c0..94d32cd4f 100644
--- a/java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java
+++ b/java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java
@@ -16,126 +16,120 @@
package dagger.internal.codegen.binding;
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreTypes.asTypeElement;
+import static androidx.room.compiler.processing.XTypeKt.isVoid;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static androidx.room.compiler.processing.compat.XConverters.toXProcessing;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.base.ComponentAnnotation.rootComponentAnnotation;
import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotation;
+import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotations;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.creatorAnnotationsFor;
+import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
import static dagger.internal.codegen.base.Scopes.productionScope;
-import static dagger.internal.codegen.base.Scopes.scopesOf;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.creatorAnnotationsFor;
import static dagger.internal.codegen.binding.ComponentDescriptor.isComponentContributionMethod;
import static dagger.internal.codegen.binding.ConfigurationAnnotations.enclosedAnnotatedTypes;
import static dagger.internal.codegen.binding.ConfigurationAnnotations.isSubcomponentCreator;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static javax.lang.model.type.TypeKind.DECLARED;
-import static javax.lang.model.type.TypeKind.VOID;
+import static dagger.internal.codegen.xprocessing.XTypeElements.getAllUnimplementedMethods;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
import static javax.lang.model.util.ElementFilter.methodsIn;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XMethodType;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import dagger.internal.codegen.base.ComponentAnnotation;
+import dagger.internal.codegen.base.DaggerSuperficialValidation;
import dagger.internal.codegen.base.ModuleAnnotation;
import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Scope;
+import dagger.spi.model.Scope;
import java.util.Optional;
-import java.util.function.Function;
import javax.inject.Inject;
import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
/** A factory for {@link ComponentDescriptor}s. */
public final class ComponentDescriptorFactory {
+ private final XProcessingEnv processingEnv;
private final DaggerElements elements;
private final DaggerTypes types;
private final DependencyRequestFactory dependencyRequestFactory;
private final ModuleDescriptor.Factory moduleDescriptorFactory;
private final InjectionAnnotations injectionAnnotations;
+ private final DaggerSuperficialValidation superficialValidation;
@Inject
ComponentDescriptorFactory(
+ XProcessingEnv processingEnv,
DaggerElements elements,
DaggerTypes types,
DependencyRequestFactory dependencyRequestFactory,
ModuleDescriptor.Factory moduleDescriptorFactory,
- InjectionAnnotations injectionAnnotations) {
+ InjectionAnnotations injectionAnnotations,
+ DaggerSuperficialValidation superficialValidation) {
+ this.processingEnv = processingEnv;
this.elements = elements;
this.types = types;
this.dependencyRequestFactory = dependencyRequestFactory;
this.moduleDescriptorFactory = moduleDescriptorFactory;
this.injectionAnnotations = injectionAnnotations;
+ this.superficialValidation = superficialValidation;
}
/** Returns a descriptor for a root component type. */
- public ComponentDescriptor rootComponentDescriptor(TypeElement typeElement) {
- return create(
- typeElement,
- checkAnnotation(
- typeElement,
- ComponentAnnotation::rootComponentAnnotation,
- "must have a component annotation"));
+ public ComponentDescriptor rootComponentDescriptor(XTypeElement typeElement) {
+ Optional<ComponentAnnotation> annotation =
+ rootComponentAnnotation(typeElement, superficialValidation);
+ checkArgument(annotation.isPresent(), "%s must have a component annotation", typeElement);
+ return create(typeElement, annotation.get());
}
/** Returns a descriptor for a subcomponent type. */
- public ComponentDescriptor subcomponentDescriptor(TypeElement typeElement) {
- return create(
- typeElement,
- checkAnnotation(
- typeElement,
- ComponentAnnotation::subcomponentAnnotation,
- "must have a subcomponent annotation"));
+ public ComponentDescriptor subcomponentDescriptor(XTypeElement typeElement) {
+ Optional<ComponentAnnotation> annotation =
+ subcomponentAnnotation(typeElement, superficialValidation);
+ checkArgument(annotation.isPresent(), "%s must have a subcomponent annotation", typeElement);
+ return create(typeElement, annotation.get());
}
/**
* Returns a descriptor for a fictional component based on a module type in order to validate its
* bindings.
*/
- public ComponentDescriptor moduleComponentDescriptor(TypeElement typeElement) {
- return create(
- typeElement,
- ComponentAnnotation.fromModuleAnnotation(
- checkAnnotation(
- typeElement, ModuleAnnotation::moduleAnnotation, "must have a module annotation")));
- }
-
- private static <A> A checkAnnotation(
- TypeElement typeElement,
- Function<TypeElement, Optional<A>> annotationFunction,
- String message) {
- return annotationFunction
- .apply(typeElement)
- .orElseThrow(() -> new IllegalArgumentException(typeElement + " " + message));
+ public ComponentDescriptor moduleComponentDescriptor(XTypeElement typeElement) {
+ Optional<ModuleAnnotation> annotation = moduleAnnotation(typeElement, superficialValidation);
+ checkArgument(annotation.isPresent(), "%s must have a module annotation", typeElement);
+ return create(typeElement, ComponentAnnotation.fromModuleAnnotation(annotation.get()));
}
private ComponentDescriptor create(
- TypeElement typeElement, ComponentAnnotation componentAnnotation) {
+ XTypeElement typeElement, ComponentAnnotation componentAnnotation) {
ImmutableSet<ComponentRequirement> componentDependencies =
componentAnnotation.dependencyTypes().stream()
.map(ComponentRequirement::forDependency)
.collect(toImmutableSet());
- ImmutableMap.Builder<ExecutableElement, ComponentRequirement> dependenciesByDependencyMethod =
+ ImmutableMap.Builder<XMethodElement, ComponentRequirement> dependenciesByDependencyMethod =
ImmutableMap.builder();
-
for (ComponentRequirement componentDependency : componentDependencies) {
for (ExecutableElement dependencyMethod :
- methodsIn(elements.getAllMembers(componentDependency.typeElement()))) {
- if (isComponentContributionMethod(elements, dependencyMethod)) {
- dependenciesByDependencyMethod.put(dependencyMethod, componentDependency);
+ methodsIn(elements.getAllMembers(toJavac(componentDependency.typeElement())))) {
+ if (isComponentContributionMethod(dependencyMethod)) {
+ dependenciesByDependencyMethod.put(
+ (XMethodElement) toXProcessing(dependencyMethod, processingEnv), componentDependency);
}
}
}
// Start with the component's modules. For fictional components built from a module, start with
// that module.
- ImmutableSet<TypeElement> modules =
+ ImmutableSet<XTypeElement> modules =
componentAnnotation.isRealComponent()
? componentAnnotation.modules()
: ImmutableSet.of(typeElement);
@@ -143,13 +137,12 @@ public final class ComponentDescriptorFactory {
ImmutableSet<ModuleDescriptor> transitiveModules =
moduleDescriptorFactory.transitiveModules(modules);
- ImmutableSet.Builder<ComponentDescriptor> subcomponentsFromModules = ImmutableSet.builder();
- for (ModuleDescriptor module : transitiveModules) {
- for (SubcomponentDeclaration subcomponentDeclaration : module.subcomponentDeclarations()) {
- TypeElement subcomponent = subcomponentDeclaration.subcomponentType();
- subcomponentsFromModules.add(subcomponentDescriptor(subcomponent));
- }
- }
+ ImmutableSet<ComponentDescriptor> subcomponentsFromModules =
+ transitiveModules.stream()
+ .flatMap(transitiveModule -> transitiveModule.subcomponentDeclarations().stream())
+ .map(SubcomponentDeclaration::subcomponentType)
+ .map(this::subcomponentDescriptor)
+ .collect(toImmutableSet());
ImmutableSet.Builder<ComponentMethodDescriptor> componentMethodsBuilder =
ImmutableSet.builder();
@@ -158,11 +151,9 @@ public final class ComponentDescriptorFactory {
ImmutableBiMap.Builder<ComponentMethodDescriptor, ComponentDescriptor>
subcomponentsByBuilderMethod = ImmutableBiMap.builder();
if (componentAnnotation.isRealComponent()) {
- ImmutableSet<ExecutableElement> unimplementedMethods =
- elements.getUnimplementedMethods(typeElement);
- for (ExecutableElement componentMethod : unimplementedMethods) {
+ for (XMethodElement componentMethod : getAllUnimplementedMethods(typeElement)) {
ComponentMethodDescriptor componentMethodDescriptor =
- getDescriptorForComponentMethod(typeElement, componentAnnotation, componentMethod);
+ getDescriptorForComponentMethod(componentAnnotation, typeElement, componentMethod);
componentMethodsBuilder.add(componentMethodDescriptor);
componentMethodDescriptor
.subcomponent()
@@ -180,32 +171,29 @@ public final class ComponentDescriptorFactory {
}
// Validation should have ensured that this set will have at most one element.
- ImmutableSet<DeclaredType> enclosedCreators =
- creatorAnnotationsFor(componentAnnotation).stream()
- .flatMap(
- creatorAnnotation ->
- enclosedAnnotatedTypes(typeElement, creatorAnnotation).stream())
- .collect(toImmutableSet());
+ ImmutableSet<XTypeElement> enclosedCreators =
+ enclosedAnnotatedTypes(typeElement, creatorAnnotationsFor(componentAnnotation));
Optional<ComponentCreatorDescriptor> creatorDescriptor =
enclosedCreators.isEmpty()
? Optional.empty()
: Optional.of(
ComponentCreatorDescriptor.create(
- getOnlyElement(enclosedCreators), elements, types, dependencyRequestFactory));
+ getOnlyElement(enclosedCreators), types, dependencyRequestFactory));
- ImmutableSet<Scope> scopes = scopesOf(typeElement);
+ ImmutableSet<Scope> scopes = injectionAnnotations.getScopes(typeElement);
if (componentAnnotation.isProduction()) {
- scopes = ImmutableSet.<Scope>builder().addAll(scopes).add(productionScope(elements)).build();
+ scopes =
+ ImmutableSet.<Scope>builder().addAll(scopes).add(productionScope(processingEnv)).build();
}
- return new AutoValue_ComponentDescriptor(
+ return ComponentDescriptor.create(
componentAnnotation,
typeElement,
componentDependencies,
transitiveModules,
dependenciesByDependencyMethod.build(),
scopes,
- subcomponentsFromModules.build(),
+ subcomponentsFromModules,
subcomponentsByFactoryMethod.build(),
subcomponentsByBuilderMethod.build(),
componentMethodsBuilder.build(),
@@ -213,36 +201,30 @@ public final class ComponentDescriptorFactory {
}
private ComponentMethodDescriptor getDescriptorForComponentMethod(
- TypeElement componentElement,
ComponentAnnotation componentAnnotation,
- ExecutableElement componentMethod) {
+ XTypeElement componentElement,
+ XMethodElement componentMethod) {
ComponentMethodDescriptor.Builder descriptor =
ComponentMethodDescriptor.builder(componentMethod);
- ExecutableType resolvedComponentMethod =
- MoreTypes.asExecutable(
- types.asMemberOf(MoreTypes.asDeclared(componentElement.asType()), componentMethod));
- TypeMirror returnType = resolvedComponentMethod.getReturnType();
- if (returnType.getKind().equals(DECLARED)
- && !injectionAnnotations.getQualifier(componentMethod).isPresent()) {
- TypeElement returnTypeElement = asTypeElement(returnType);
- if (subcomponentAnnotation(returnTypeElement).isPresent()) {
+ XMethodType resolvedComponentMethod = componentMethod.asMemberOf(componentElement.getType());
+ XType returnType = resolvedComponentMethod.getReturnType();
+ if (isDeclared(returnType) && !injectionAnnotations.getQualifier(componentMethod).isPresent()) {
+ XTypeElement returnTypeElement = returnType.getTypeElement();
+ if (returnTypeElement.hasAnyAnnotation(subcomponentAnnotations())) {
// It's a subcomponent factory method. There is no dependency request, and there could be
// any number of parameters. Just return the descriptor.
return descriptor.subcomponent(subcomponentDescriptor(returnTypeElement)).build();
}
if (isSubcomponentCreator(returnTypeElement)) {
descriptor.subcomponent(
- subcomponentDescriptor(asType(returnTypeElement.getEnclosingElement())));
+ subcomponentDescriptor(returnTypeElement.getEnclosingTypeElement()));
}
}
switch (componentMethod.getParameters().size()) {
case 0:
- checkArgument(
- !returnType.getKind().equals(VOID),
- "component method cannot be void: %s",
- componentMethod);
+ checkArgument(!isVoid(returnType), "component method cannot be void: %s", componentMethod);
descriptor.dependencyRequest(
componentAnnotation.isProduction()
? dependencyRequestFactory.forComponentProductionMethod(
@@ -253,9 +235,11 @@ public final class ComponentDescriptorFactory {
case 1:
checkArgument(
- returnType.getKind().equals(VOID)
- || MoreTypes.equivalence()
- .equivalent(returnType, resolvedComponentMethod.getParameterTypes().get(0)),
+ isVoid(returnType)
+ // TODO(bcorso): Replace this with isSameType()?
+ || returnType
+ .getTypeName()
+ .equals(resolvedComponentMethod.getParameterTypes().get(0).getTypeName()),
"members injection method must return void or parameter type: %s",
componentMethod);
descriptor.dependencyRequest(
diff --git a/java/dagger/internal/codegen/binding/ComponentKind.java b/java/dagger/internal/codegen/binding/ComponentKind.java
deleted file mode 100644
index 1cb3d7c1c..000000000
--- a/java/dagger/internal/codegen/binding/ComponentKind.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2014 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.binding;
-
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.common.collect.Sets.immutableEnumSet;
-import static dagger.internal.codegen.extension.DaggerStreams.stream;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.extension.DaggerStreams.valuesOf;
-import static java.util.EnumSet.allOf;
-
-import com.google.common.collect.ImmutableSet;
-import dagger.Component;
-import dagger.Module;
-import dagger.Subcomponent;
-import dagger.producers.ProducerModule;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-import java.lang.annotation.Annotation;
-import java.util.Optional;
-import javax.lang.model.element.TypeElement;
-
-/** Enumeration of the different kinds of components. */
-public enum ComponentKind {
- /** {@code @Component} */
- COMPONENT(Component.class, true, false),
-
- /** {@code @Subcomponent} */
- SUBCOMPONENT(Subcomponent.class, false, false),
-
- /** {@code @ProductionComponent} */
- PRODUCTION_COMPONENT(ProductionComponent.class, true, true),
-
- /** {@code @ProductionSubcomponent} */
- PRODUCTION_SUBCOMPONENT(ProductionSubcomponent.class, false, true),
-
- /**
- * Kind for a descriptor that was generated from a {@link Module} instead of a component type in
- * order to validate the module's bindings.
- */
- MODULE(Module.class, true, false),
-
- /**
- * Kind for a descriptor was generated from a {@link ProducerModule} instead of a component type
- * in order to validate the module's bindings.
- */
- PRODUCER_MODULE(ProducerModule.class, true, true),
- ;
-
- private static final ImmutableSet<ComponentKind> ROOT_COMPONENT_KINDS =
- valuesOf(ComponentKind.class)
- .filter(kind -> !kind.isForModuleValidation())
- .filter(kind -> kind.isRoot())
- .collect(toImmutableSet());
-
- private static final ImmutableSet<ComponentKind> SUBCOMPONENT_KINDS =
- valuesOf(ComponentKind.class)
- .filter(kind -> !kind.isForModuleValidation())
- .filter(kind -> !kind.isRoot())
- .collect(toImmutableSet());
-
- /** Returns the set of kinds for root components. */
- public static ImmutableSet<ComponentKind> rootComponentKinds() {
- return ROOT_COMPONENT_KINDS;
- }
-
- /** Returns the set of kinds for subcomponents. */
- public static ImmutableSet<ComponentKind> subcomponentKinds() {
- return SUBCOMPONENT_KINDS;
- }
-
- /** Returns the annotations for components of the given kinds. */
- public static ImmutableSet<Class<? extends Annotation>> annotationsFor(
- Iterable<ComponentKind> kinds) {
- return stream(kinds).map(ComponentKind::annotation).collect(toImmutableSet());
- }
-
- /** Returns the set of component kinds the given {@code element} has annotations for. */
- public static ImmutableSet<ComponentKind> getComponentKinds(TypeElement element) {
- return valuesOf(ComponentKind.class)
- .filter(kind -> isAnnotationPresent(element, kind.annotation()))
- .collect(toImmutableSet());
- }
-
- /**
- * Returns the kind of an annotated element if it is annotated with one of the {@linkplain
- * #annotation() annotations}.
- *
- * @throws IllegalArgumentException if the element is annotated with more than one of the
- * annotations
- */
- public static Optional<ComponentKind> forAnnotatedElement(TypeElement element) {
- ImmutableSet<ComponentKind> kinds = getComponentKinds(element);
- if (kinds.size() > 1) {
- throw new IllegalArgumentException(
- element + " cannot be annotated with more than one of " + annotationsFor(kinds));
- }
- return kinds.stream().findAny();
- }
-
- private final Class<? extends Annotation> annotation;
- private final boolean isRoot;
- private final boolean production;
-
- ComponentKind(
- Class<? extends Annotation> annotation,
- boolean isRoot,
- boolean production) {
- this.annotation = annotation;
- this.isRoot = isRoot;
- this.production = production;
- }
-
- /** Returns the annotation that marks a component of this kind. */
- public Class<? extends Annotation> annotation() {
- return annotation;
- }
-
- /** Returns the kinds of modules that can be used with a component of this kind. */
- public ImmutableSet<ModuleKind> legalModuleKinds() {
- return isProducer()
- ? immutableEnumSet(allOf(ModuleKind.class))
- : immutableEnumSet(ModuleKind.MODULE);
- }
-
- /** Returns the kinds of subcomponents a component of this kind can have. */
- public ImmutableSet<ComponentKind> legalSubcomponentKinds() {
- return isProducer()
- ? immutableEnumSet(PRODUCTION_SUBCOMPONENT)
- : immutableEnumSet(SUBCOMPONENT, PRODUCTION_SUBCOMPONENT);
- }
-
- /**
- * Returns {@code true} if the descriptor is for a root component (not a subcomponent) or is for
- * {@linkplain #isForModuleValidation() module-validation}.
- */
- public boolean isRoot() {
- return isRoot;
- }
-
- /** Returns true if this is a production component. */
- public boolean isProducer() {
- return production;
- }
-
- /** Returns {@code true} if the descriptor is for a module in order to validate its bindings. */
- public boolean isForModuleValidation() {
- switch (this) {
- case MODULE:
- case PRODUCER_MODULE:
- return true;
- default:
- // fall through
- }
- return false;
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ComponentNodeImpl.java b/java/dagger/internal/codegen/binding/ComponentNodeImpl.java
index 0947c252c..5dbf63371 100644
--- a/java/dagger/internal/codegen/binding/ComponentNodeImpl.java
+++ b/java/dagger/internal/codegen/binding/ComponentNodeImpl.java
@@ -20,10 +20,10 @@ import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableSet;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.ComponentPath;
-import dagger.model.DependencyRequest;
-import dagger.model.Scope;
+import dagger.spi.model.BindingGraph.ComponentNode;
+import dagger.spi.model.ComponentPath;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Scope;
/** An implementation of {@link ComponentNode} that also exposes the {@link ComponentDescriptor}. */
@AutoValue
diff --git a/java/dagger/internal/codegen/binding/ComponentRequirement.java b/java/dagger/internal/codegen/binding/ComponentRequirement.java
index 9d54f4dc3..d021eb6da 100644
--- a/java/dagger/internal/codegen/binding/ComponentRequirement.java
+++ b/java/dagger/internal/codegen/binding/ComponentRequirement.java
@@ -16,36 +16,28 @@
package dagger.internal.codegen.binding;
+import static androidx.room.compiler.processing.XElementKt.isConstructor;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static dagger.internal.codegen.binding.SourceFiles.simpleVariableName;
-import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
-import static javax.lang.model.element.ElementKind.CONSTRUCTOR;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
+import static dagger.internal.codegen.xprocessing.XElements.asConstructor;
+import static dagger.internal.codegen.xprocessing.XElements.hasAnyAnnotation;
+import static dagger.internal.codegen.xprocessing.XTypeElements.isNested;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
+import static kotlin.streams.jdk8.StreamsKt.asStream;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
-import com.google.common.base.Equivalence;
-import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
-import dagger.Binds;
-import dagger.BindsOptionalOf;
-import dagger.Provides;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.model.BindingKind;
-import dagger.model.Key;
-import dagger.multibindings.Multibinds;
-import dagger.producers.Produces;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.Key;
import java.util.Optional;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
/** A type that a component needs an instance of. */
@AutoValue
@@ -73,6 +65,8 @@ public abstract class ComponentRequirement {
}
}
+ private XType type;
+
/** The kind of requirement. */
public abstract Kind kind();
@@ -82,20 +76,17 @@ public abstract class ComponentRequirement {
return kind().isBoundInstance();
}
- /**
- * The type of the instance the component must have, wrapped so that requirements can be used as
- * value types.
- */
- public abstract Equivalence.Wrapper<TypeMirror> wrappedType();
+ /** The type of the instance the component must have. */
+ abstract TypeName typeName();
/** The type of the instance the component must have. */
- public TypeMirror type() {
- return wrappedType().get();
+ public XType type() {
+ return type;
}
/** The element associated with the type of this requirement. */
- public TypeElement typeElement() {
- return MoreTypes.asTypeElement(type());
+ public XTypeElement typeElement() {
+ return type.getTypeElement();
}
/** The action a component builder should take if it {@code null} is passed. */
@@ -118,15 +109,15 @@ public abstract class ComponentRequirement {
abstract Optional<NullPolicy> overrideNullPolicy();
/** The requirement's null policy. */
- public NullPolicy nullPolicy(DaggerElements elements, KotlinMetadataUtil metadataUtil) {
+ public NullPolicy nullPolicy() {
if (overrideNullPolicy().isPresent()) {
return overrideNullPolicy().get();
}
switch (kind()) {
case MODULE:
- return componentCanMakeNewInstances(typeElement(), metadataUtil)
+ return componentCanMakeNewInstances(typeElement())
? NullPolicy.NEW
- : requiresAPassedInstance(elements, metadataUtil) ? NullPolicy.THROW : NullPolicy.ALLOW;
+ : requiresAPassedInstance() ? NullPolicy.THROW : NullPolicy.ALLOW;
case DEPENDENCY:
case BOUND_INSTANCE:
return NullPolicy.THROW;
@@ -138,13 +129,12 @@ public abstract class ComponentRequirement {
* Returns true if the passed {@link ComponentRequirement} requires a passed instance in order to
* be used within a component.
*/
- public boolean requiresAPassedInstance(DaggerElements elements, KotlinMetadataUtil metadataUtil) {
+ public boolean requiresAPassedInstance() {
if (!kind().isModule()) {
// Bound instances and dependencies always require the user to provide an instance.
return true;
}
- return requiresModuleInstance(elements, metadataUtil)
- && !componentCanMakeNewInstances(typeElement(), metadataUtil);
+ return requiresModuleInstance() && !componentCanMakeNewInstances(typeElement());
}
/**
@@ -157,33 +147,27 @@ public abstract class ComponentRequirement {
* <p>Alternatively, if the module is a Kotlin Object then the binding methods are considered
* {@code static}, requiring no module instance.
*/
- private boolean requiresModuleInstance(DaggerElements elements, KotlinMetadataUtil metadataUtil) {
- boolean isKotlinObject =
- metadataUtil.isObjectClass(typeElement())
- || metadataUtil.isCompanionObjectClass(typeElement());
- if (isKotlinObject) {
+ private boolean requiresModuleInstance() {
+ if (typeElement().isKotlinObject() || typeElement().isCompanionObject()) {
return false;
}
-
- ImmutableSet<ExecutableElement> methods = elements.getLocalAndInheritedMethods(typeElement());
- return methods.stream()
+ return asStream(typeElement().getAllNonPrivateInstanceMethods())
.filter(this::isBindingMethod)
- .map(ExecutableElement::getModifiers)
- .anyMatch(modifiers -> !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC));
+ .anyMatch(method -> !method.isAbstract() && !method.isStatic());
}
- private boolean isBindingMethod(ExecutableElement method) {
+ private boolean isBindingMethod(XMethodElement method) {
// TODO(cgdecker): At the very least, we should have utility methods to consolidate this stuff
// in one place; listing individual annotations all over the place is brittle.
- return isAnyAnnotationPresent(
+ return hasAnyAnnotation(
method,
- Provides.class,
- Produces.class,
+ TypeNames.PROVIDES,
+ TypeNames.PRODUCES,
// TODO(ronshapiro): it would be cool to have internal meta-annotations that could describe
// these, like @AbstractBindingMethod
- Binds.class,
- Multibinds.class,
- BindsOptionalOf.class);
+ TypeNames.BINDS,
+ TypeNames.MULTIBINDS,
+ TypeNames.BINDS_OPTIONAL_OF);
}
/** The key for this requirement, if one is available. */
@@ -194,42 +178,57 @@ public abstract class ComponentRequirement {
/** Returns a parameter spec for this requirement. */
public ParameterSpec toParameterSpec() {
- return ParameterSpec.builder(TypeName.get(type()), variableName()).build();
+ return ParameterSpec.builder(type().getTypeName(), variableName()).build();
}
- public static ComponentRequirement forDependency(TypeMirror type) {
- return new AutoValue_ComponentRequirement(
- Kind.DEPENDENCY,
- MoreTypes.equivalence().wrap(checkNotNull(type)),
- Optional.empty(),
- Optional.empty(),
- simpleVariableName(MoreTypes.asTypeElement(type)));
+ public static ComponentRequirement forDependency(XType type) {
+ checkArgument(isDeclared(checkNotNull(type)));
+ ComponentRequirement requirement =
+ new AutoValue_ComponentRequirement(
+ Kind.DEPENDENCY,
+ type.getTypeName(),
+ Optional.empty(),
+ Optional.empty(),
+ simpleVariableName(type.getTypeElement().getClassName()));
+ requirement.type = type;
+ return requirement;
}
- public static ComponentRequirement forModule(TypeMirror type) {
- return new AutoValue_ComponentRequirement(
- Kind.MODULE,
- MoreTypes.equivalence().wrap(checkNotNull(type)),
- Optional.empty(),
- Optional.empty(),
- simpleVariableName(MoreTypes.asTypeElement(type)));
+ public static ComponentRequirement forModule(XType type) {
+ checkArgument(isDeclared(checkNotNull(type)));
+ ComponentRequirement requirement =
+ new AutoValue_ComponentRequirement(
+ Kind.MODULE,
+ type.getTypeName(),
+ Optional.empty(),
+ Optional.empty(),
+ simpleVariableName(type.getTypeElement().getClassName()));
+ requirement.type = type;
+ return requirement;
}
- static ComponentRequirement forBoundInstance(Key key, boolean nullable, String variableName) {
- return new AutoValue_ComponentRequirement(
- Kind.BOUND_INSTANCE,
- MoreTypes.equivalence().wrap(key.type()),
- nullable ? Optional.of(NullPolicy.ALLOW) : Optional.empty(),
- Optional.of(key),
- variableName);
+ static ComponentRequirement forBoundInstance(
+ Key key, boolean nullable, XElement elementForVariableName) {
+ ComponentRequirement requirement =
+ new AutoValue_ComponentRequirement(
+ Kind.BOUND_INSTANCE,
+ key.type().xprocessing().getTypeName(),
+ nullable ? Optional.of(NullPolicy.ALLOW) : Optional.empty(),
+ Optional.of(key),
+ toJavac(elementForVariableName).getSimpleName().toString());
+ requirement.type = key.type().xprocessing();
+ return requirement;
}
public static ComponentRequirement forBoundInstance(ContributionBinding binding) {
checkArgument(binding.kind().equals(BindingKind.BOUND_INSTANCE));
- return forBoundInstance(
- binding.key(),
- binding.nullableType().isPresent(),
- binding.bindingElement().get().getSimpleName().toString());
+ ComponentRequirement requirement =
+ forBoundInstance(
+ binding.key(),
+ binding.nullableType().isPresent(),
+ binding.bindingElement().get());
+ requirement.type = binding.key().type().xprocessing();
+ return requirement;
}
/**
@@ -237,9 +236,11 @@ public abstract class ComponentRequirement {
* rather than requiring that they be passed.
*/
// TODO(bcorso): Should this method throw if its called knowing that an instance is not needed?
- public static boolean componentCanMakeNewInstances(
- TypeElement typeElement, KotlinMetadataUtil metadataUtil) {
- switch (typeElement.getKind()) {
+ public static boolean componentCanMakeNewInstances(XTypeElement typeElement) {
+ // TODO(bcorso): Investigate how we should replace this in XProcessing. It's not clear what the
+ // complete set of kinds are in XProcessing and if they're mutually exclusive. For example,
+ // does XTypeElement#isClass() cover XTypeElement#isDataClass(), etc?
+ switch (toJavac(typeElement).getKind()) {
case CLASS:
break;
case ENUM:
@@ -247,10 +248,10 @@ public abstract class ComponentRequirement {
case INTERFACE:
return false;
default:
- throw new AssertionError("TypeElement cannot have kind: " + typeElement.getKind());
+ throw new AssertionError("TypeElement cannot have kind: " + toJavac(typeElement).getKind());
}
- if (typeElement.getModifiers().contains(ABSTRACT)) {
+ if (typeElement.isAbstract()) {
return false;
}
@@ -258,15 +259,10 @@ public abstract class ComponentRequirement {
return false;
}
- if (metadataUtil.isObjectClass(typeElement)
- || metadataUtil.isCompanionObjectClass(typeElement)) {
- return false;
- }
-
- for (Element enclosed : typeElement.getEnclosedElements()) {
- if (enclosed.getKind().equals(CONSTRUCTOR)
- && MoreElements.asExecutable(enclosed).getParameters().isEmpty()
- && !enclosed.getModifiers().contains(PRIVATE)) {
+ for (XElement enclosed : typeElement.getEnclosedElements()) {
+ if (isConstructor(enclosed)
+ && asConstructor(enclosed).getParameters().isEmpty()
+ && !asConstructor(enclosed).isPrivate()) {
return true;
}
}
@@ -276,17 +272,7 @@ public abstract class ComponentRequirement {
return false;
}
- private static boolean requiresEnclosingInstance(TypeElement typeElement) {
- switch (typeElement.getNestingKind()) {
- case TOP_LEVEL:
- return false;
- case MEMBER:
- return !typeElement.getModifiers().contains(STATIC);
- case ANONYMOUS:
- case LOCAL:
- return true;
- }
- throw new AssertionError(
- "TypeElement cannot have nesting kind: " + typeElement.getNestingKind());
+ private static boolean requiresEnclosingInstance(XTypeElement typeElement) {
+ return isNested(typeElement) && !typeElement.isStatic();
}
}
diff --git a/java/dagger/internal/codegen/binding/ConfigurationAnnotations.java b/java/dagger/internal/codegen/binding/ConfigurationAnnotations.java
index 539a66ac6..75ae97e68 100644
--- a/java/dagger/internal/codegen/binding/ConfigurationAnnotations.java
+++ b/java/dagger/internal/codegen/binding/ConfigurationAnnotations.java
@@ -17,37 +17,25 @@
package dagger.internal.codegen.binding;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.consumingIterable;
-import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotation;
-import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
-import static dagger.internal.codegen.base.MoreAnnotationMirrors.getTypeListValue;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.subcomponentCreatorAnnotations;
-import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
-import static javax.lang.model.util.ElementFilter.typesIn;
+import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotations;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.subcomponentCreatorAnnotations;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.xprocessing.XAnnotations.getClassName;
+import static dagger.internal.codegen.xprocessing.XElements.hasAnyAnnotation;
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableList;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
+import com.squareup.javapoet.ClassName;
import dagger.Component;
import dagger.Module;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.lang.annotation.Annotation;
-import java.util.ArrayDeque;
import java.util.List;
import java.util.Optional;
-import java.util.Queue;
-import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
/**
* Utility methods related to dagger configuration annotations (e.g.: {@link Component} and {@link
@@ -55,24 +43,27 @@ import javax.lang.model.type.TypeMirror;
*/
public final class ConfigurationAnnotations {
- public static Optional<TypeElement> getSubcomponentCreator(TypeElement subcomponent) {
- checkArgument(subcomponentAnnotation(subcomponent).isPresent());
- for (TypeElement nestedType : typesIn(subcomponent.getEnclosedElements())) {
- if (isSubcomponentCreator(nestedType)) {
- return Optional.of(nestedType);
- }
- }
- return Optional.empty();
+ public static Optional<XTypeElement> getSubcomponentCreator(XTypeElement subcomponent) {
+ checkArgument(subcomponent.hasAnyAnnotation(subcomponentAnnotations()));
+ return subcomponent.getEnclosedTypeElements().stream()
+ .filter(ConfigurationAnnotations::isSubcomponentCreator)
+ // TODO(bcorso): Consider doing toOptional() instead since there should be at most 1.
+ .findFirst();
}
- static boolean isSubcomponentCreator(Element element) {
- return isAnyAnnotationPresent(element, subcomponentCreatorAnnotations());
+ static boolean isSubcomponentCreator(XElement element) {
+ return hasAnyAnnotation(element, subcomponentCreatorAnnotations());
}
- // Dagger 1 support.
- public static ImmutableList<TypeMirror> getModuleInjects(AnnotationMirror moduleAnnotation) {
- checkNotNull(moduleAnnotation);
- return getTypeListValue(moduleAnnotation, "injects");
+ /** Returns the first type that specifies this' nullability, or empty if none. */
+ public static Optional<XAnnotation> getNullableAnnotation(XElement element) {
+ return element.getAllAnnotations().stream()
+ .filter(annotation -> getClassName(annotation).simpleName().contentEquals("Nullable"))
+ .findFirst();
+ }
+
+ public static Optional<XType> getNullableType(XElement element) {
+ return getNullableAnnotation(element).map(XAnnotation::getType);
}
/** Returns the first type that specifies this' nullability, or empty if none. */
@@ -86,71 +77,12 @@ public final class ConfigurationAnnotations {
return Optional.empty();
}
- /**
- * Returns the full set of modules transitively {@linkplain Module#includes included} from the
- * given seed modules. If a module is malformed and a type listed in {@link Module#includes} is
- * not annotated with {@link Module}, it is ignored.
- *
- * @deprecated Use {@link ComponentDescriptor#modules()}.
- */
- @Deprecated
- public static ImmutableSet<TypeElement> getTransitiveModules(
- DaggerTypes types, DaggerElements elements, Iterable<TypeElement> seedModules) {
- TypeMirror objectType = elements.getTypeElement(Object.class).asType();
- Queue<TypeElement> moduleQueue = new ArrayDeque<>();
- Iterables.addAll(moduleQueue, seedModules);
- Set<TypeElement> moduleElements = Sets.newLinkedHashSet();
- for (TypeElement moduleElement : consumingIterable(moduleQueue)) {
- moduleAnnotation(moduleElement)
- .ifPresent(
- moduleAnnotation -> {
- ImmutableSet.Builder<TypeElement> moduleDependenciesBuilder =
- ImmutableSet.builder();
- moduleDependenciesBuilder.addAll(moduleAnnotation.includes());
- // We don't recur on the parent class because we don't want the parent class as a
- // root that the component depends on, and also because we want the dependencies
- // rooted against this element, not the parent.
- addIncludesFromSuperclasses(
- types, moduleElement, moduleDependenciesBuilder, objectType);
- ImmutableSet<TypeElement> moduleDependencies = moduleDependenciesBuilder.build();
- moduleElements.add(moduleElement);
- for (TypeElement dependencyType : moduleDependencies) {
- if (!moduleElements.contains(dependencyType)) {
- moduleQueue.add(dependencyType);
- }
- }
- });
- }
- return ImmutableSet.copyOf(moduleElements);
- }
-
/** Returns the enclosed types annotated with the given annotation. */
- public static ImmutableList<DeclaredType> enclosedAnnotatedTypes(
- TypeElement typeElement, Class<? extends Annotation> annotation) {
- final ImmutableList.Builder<DeclaredType> builders = ImmutableList.builder();
- for (TypeElement element : typesIn(typeElement.getEnclosedElements())) {
- if (MoreElements.isAnnotationPresent(element, annotation)) {
- builders.add(MoreTypes.asDeclared(element.asType()));
- }
- }
- return builders.build();
- }
-
- /** Traverses includes from superclasses and adds them into the builder. */
- private static void addIncludesFromSuperclasses(
- DaggerTypes types,
- TypeElement element,
- ImmutableSet.Builder<TypeElement> builder,
- TypeMirror objectType) {
- // Also add the superclass to the queue, in case any @Module definitions were on that.
- TypeMirror superclass = element.getSuperclass();
- while (!types.isSameType(objectType, superclass)
- && superclass.getKind().equals(TypeKind.DECLARED)) {
- element = MoreElements.asType(types.asElement(superclass));
- moduleAnnotation(element)
- .ifPresent(moduleAnnotation -> builder.addAll(moduleAnnotation.includes()));
- superclass = element.getSuperclass();
- }
+ public static ImmutableSet<XTypeElement> enclosedAnnotatedTypes(
+ XTypeElement typeElement, ImmutableSet<ClassName> annotations) {
+ return typeElement.getEnclosedTypeElements().stream()
+ .filter(enclosedType -> hasAnyAnnotation(enclosedType, annotations))
+ .collect(toImmutableSet());
}
private ConfigurationAnnotations() {}
diff --git a/java/dagger/internal/codegen/binding/ContributionBinding.java b/java/dagger/internal/codegen/binding/ContributionBinding.java
index 1942e8c1f..2c555600d 100644
--- a/java/dagger/internal/codegen/binding/ContributionBinding.java
+++ b/java/dagger/internal/codegen/binding/ContributionBinding.java
@@ -17,30 +17,26 @@
package dagger.internal.codegen.binding;
import static dagger.internal.codegen.base.MoreAnnotationMirrors.unwrapOptionalEquivalence;
-import static dagger.internal.codegen.binding.ContributionBinding.FactoryCreationStrategy.CLASS_CONSTRUCTOR;
-import static dagger.internal.codegen.binding.ContributionBinding.FactoryCreationStrategy.DELEGATE;
-import static dagger.internal.codegen.binding.ContributionBinding.FactoryCreationStrategy.SINGLETON_INSTANCE;
+import static dagger.internal.codegen.xprocessing.XElements.asMethod;
import static java.util.Arrays.asList;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XElementKt;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.base.Equivalence;
-import com.google.common.base.Preconditions;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.CheckReturnValue;
import dagger.internal.codegen.base.ContributionType;
import dagger.internal.codegen.base.ContributionType.HasContributionType;
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.SetType;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
+import dagger.internal.codegen.xprocessing.XTypes;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
import java.util.Optional;
import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
/**
* An abstract class for a value object representing the mechanism by which a {@link Key} can be
@@ -49,7 +45,7 @@ import javax.lang.model.type.TypeMirror;
public abstract class ContributionBinding extends Binding implements HasContributionType {
/** Returns the type that specifies this' nullability, absent if not nullable. */
- public abstract Optional<DeclaredType> nullableType();
+ public abstract Optional<XType> nullableType();
public abstract Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedMapKeyAnnotation();
@@ -58,16 +54,16 @@ public abstract class ContributionBinding extends Binding implements HasContribu
}
/** If {@link #bindingElement()} is a method that returns a primitive type, returns that type. */
- public final Optional<TypeMirror> contributedPrimitiveType() {
+ public final Optional<XType> contributedPrimitiveType() {
return bindingElement()
- .filter(bindingElement -> bindingElement instanceof ExecutableElement)
- .map(bindingElement -> MoreElements.asExecutable(bindingElement).getReturnType())
- .filter(type -> type.getKind().isPrimitive());
+ .filter(XElementKt::isMethod)
+ .map(bindingElement -> asMethod(bindingElement).getReturnType())
+ .filter(XTypes::isPrimitive);
}
@Override
public boolean requiresModuleInstance() {
- return !isContributingModuleKotlinObject().orElse(false) && super.requiresModuleInstance();
+ return !isContributingModuleKotlinObject() && super.requiresModuleInstance();
}
@Override
@@ -79,51 +75,18 @@ public abstract class ContributionBinding extends Binding implements HasContribu
* Returns {@code true} if the contributing module is a Kotlin object. Note that a companion
* object is also considered a Kotlin object.
*/
- abstract Optional<Boolean> isContributingModuleKotlinObject();
-
- /** The strategy for getting an instance of a factory for a {@link ContributionBinding}. */
- public enum FactoryCreationStrategy {
- /** The factory class is a single instance. */
- SINGLETON_INSTANCE,
- /** The factory must be created by calling the constructor. */
- CLASS_CONSTRUCTOR,
- /** The factory is simply delegated to another. */
- DELEGATE,
+ private boolean isContributingModuleKotlinObject() {
+ return contributingModule().isPresent()
+ && (contributingModule().get().isKotlinObject()
+ || contributingModule().get().isCompanionObject());
}
/**
- * Returns the {@link FactoryCreationStrategy} appropriate for a binding.
- *
- * <p>Delegate bindings use the {@link FactoryCreationStrategy#DELEGATE} strategy.
- *
- * <p>Bindings without dependencies that don't require a module instance use the {@link
- * FactoryCreationStrategy#SINGLETON_INSTANCE} strategy.
- *
- * <p>All other bindings use the {@link FactoryCreationStrategy#CLASS_CONSTRUCTOR} strategy.
+ * The {@link XType type} for the {@code Factory<T>} or {@code Producer<T>} which is created for
+ * this binding. Uses the binding's key, V in the case of {@code Map<K, FrameworkClass<V>>>}, and
+ * E {@code Set<E>} for {@link dagger.multibindings.IntoSet @IntoSet} methods.
*/
- public final FactoryCreationStrategy factoryCreationStrategy() {
- switch (kind()) {
- case DELEGATE:
- return DELEGATE;
- case PROVISION:
- return dependencies().isEmpty() && !requiresModuleInstance()
- ? SINGLETON_INSTANCE
- : CLASS_CONSTRUCTOR;
- case INJECTION:
- case MULTIBOUND_SET:
- case MULTIBOUND_MAP:
- return dependencies().isEmpty() ? SINGLETON_INSTANCE : CLASS_CONSTRUCTOR;
- default:
- return CLASS_CONSTRUCTOR;
- }
- }
-
- /**
- * The {@link TypeMirror type} for the {@code Factory<T>} or {@code Producer<T>} which is created
- * for this binding. Uses the binding's key, V in the case of {@code Map<K, FrameworkClass<V>>>},
- * and E {@code Set<E>} for {@link dagger.multibindings.IntoSet @IntoSet} methods.
- */
- public final TypeMirror contributedType() {
+ public final XType contributedType() {
switch (contributionType()) {
case MAP:
return MapType.from(key()).unwrappedFrameworkValueType();
@@ -131,27 +94,11 @@ public abstract class ContributionBinding extends Binding implements HasContribu
return SetType.from(key()).elementType();
case SET_VALUES:
case UNIQUE:
- return key().type();
+ return key().type().xprocessing();
}
throw new AssertionError();
}
- /**
- * Returns {@link BindingKind#MULTIBOUND_SET} or {@link
- * BindingKind#MULTIBOUND_MAP} if the key is a set or map.
- *
- * @throws IllegalArgumentException if {@code key} is neither a set nor a map
- */
- static BindingKind bindingKindForMultibindingKey(Key key) {
- if (SetType.isSet(key)) {
- return BindingKind.MULTIBOUND_SET;
- } else if (MapType.isMap(key)) {
- return BindingKind.MULTIBOUND_MAP;
- } else {
- throw new IllegalArgumentException(String.format("key is not for a set or map: %s", key));
- }
- }
-
public abstract Builder<?, ?> toBuilder();
/**
@@ -170,21 +117,19 @@ public abstract class ContributionBinding extends Binding implements HasContribu
public abstract B contributionType(ContributionType contributionType);
- public abstract B bindingElement(Element bindingElement);
+ public abstract B bindingElement(XElement bindingElement);
- abstract B bindingElement(Optional<Element> bindingElement);
+ abstract B bindingElement(Optional<XElement> bindingElement);
public final B clearBindingElement() {
return bindingElement(Optional.empty());
};
- abstract B contributingModule(TypeElement contributingModule);
-
- abstract B isContributingModuleKotlinObject(boolean isModuleKotlinObject);
+ abstract B contributingModule(XTypeElement contributingModule);
public abstract B key(Key key);
- public abstract B nullableType(Optional<DeclaredType> nullableType);
+ public abstract B nullableType(Optional<XType> nullableType);
abstract B wrappedMapKeyAnnotation(
Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedMapKeyAnnotation);
@@ -192,16 +137,6 @@ public abstract class ContributionBinding extends Binding implements HasContribu
public abstract B kind(BindingKind kind);
@CheckReturnValue
- abstract C autoBuild();
-
- @CheckReturnValue
- public C build() {
- C binding = autoBuild();
- Preconditions.checkState(
- binding.contributingModule().isPresent()
- == binding.isContributingModuleKotlinObject().isPresent(),
- "The contributionModule and isModuleKotlinObject must both be set together.");
- return binding;
- }
+ abstract C build();
}
}
diff --git a/java/dagger/internal/codegen/binding/DelegateDeclaration.java b/java/dagger/internal/codegen/binding/DelegateDeclaration.java
index b6c3c3830..32ecf67fe 100644
--- a/java/dagger/internal/codegen/binding/DelegateDeclaration.java
+++ b/java/dagger/internal/codegen/binding/DelegateDeclaration.java
@@ -16,12 +16,15 @@
package dagger.internal.codegen.binding;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.base.Preconditions.checkArgument;
import static dagger.internal.codegen.base.MoreAnnotationMirrors.wrapOptionalInEquivalence;
import static dagger.internal.codegen.binding.MapKeys.getMapKey;
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XMethodType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.base.Equivalence;
@@ -29,15 +32,11 @@ import com.google.common.collect.Iterables;
import dagger.Binds;
import dagger.internal.codegen.base.ContributionType;
import dagger.internal.codegen.base.ContributionType.HasContributionType;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.spi.model.DependencyRequest;
import java.util.Optional;
import javax.inject.Inject;
import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.ExecutableType;
/** The declaration for a delegate binding established by a {@link Binds} method. */
@AutoValue
@@ -56,26 +55,20 @@ public abstract class DelegateDeclaration extends BindingDeclaration
/** A {@link DelegateDeclaration} factory. */
public static final class Factory {
- private final DaggerTypes types;
private final KeyFactory keyFactory;
private final DependencyRequestFactory dependencyRequestFactory;
@Inject
Factory(
- DaggerTypes types,
KeyFactory keyFactory,
DependencyRequestFactory dependencyRequestFactory) {
- this.types = types;
this.keyFactory = keyFactory;
this.dependencyRequestFactory = dependencyRequestFactory;
}
- public DelegateDeclaration create(
- ExecutableElement bindsMethod, TypeElement contributingModule) {
- checkArgument(MoreElements.isAnnotationPresent(bindsMethod, Binds.class));
- ExecutableType resolvedMethod =
- MoreTypes.asExecutable(
- types.asMemberOf(MoreTypes.asDeclared(contributingModule.asType()), bindsMethod));
+ public DelegateDeclaration create(XMethodElement bindsMethod, XTypeElement contributingModule) {
+ checkArgument(bindsMethod.hasAnnotation(TypeNames.BINDS));
+ XMethodType resolvedMethod = bindsMethod.asMemberOf(contributingModule.getType());
DependencyRequest delegateRequest =
dependencyRequestFactory.forRequiredResolvedVariable(
Iterables.getOnlyElement(bindsMethod.getParameters()),
@@ -83,10 +76,10 @@ public abstract class DelegateDeclaration extends BindingDeclaration
return new AutoValue_DelegateDeclaration(
ContributionType.fromBindingElement(bindsMethod),
keyFactory.forBindsMethod(bindsMethod, contributingModule),
- Optional.<Element>of(bindsMethod),
+ Optional.<XElement>of(bindsMethod),
Optional.of(contributingModule),
delegateRequest,
- wrapOptionalInEquivalence(getMapKey(bindsMethod)));
+ wrapOptionalInEquivalence(getMapKey(toJavac(bindsMethod))));
}
}
}
diff --git a/java/dagger/internal/codegen/binding/DependencyEdgeImpl.java b/java/dagger/internal/codegen/binding/DependencyEdgeImpl.java
index f11517e6d..11e1dcf03 100644
--- a/java/dagger/internal/codegen/binding/DependencyEdgeImpl.java
+++ b/java/dagger/internal/codegen/binding/DependencyEdgeImpl.java
@@ -17,8 +17,9 @@
package dagger.internal.codegen.binding;
import dagger.internal.codegen.base.ElementFormatter;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.DependencyRequest;
+import dagger.spi.model.BindingGraph.DependencyEdge;
+import dagger.spi.model.DaggerElement;
+import dagger.spi.model.DependencyRequest;
/** An implementation of {@link DependencyEdge}. */
final class DependencyEdgeImpl implements DependencyEdge {
@@ -46,6 +47,7 @@ final class DependencyEdgeImpl implements DependencyEdge {
String string =
dependencyRequest
.requestElement()
+ .map(DaggerElement::java)
.map(ElementFormatter::elementToString)
.orElseGet(
() ->
diff --git a/java/dagger/internal/codegen/binding/DependencyRequestFactory.java b/java/dagger/internal/codegen/binding/DependencyRequestFactory.java
index 707de4ce6..01c3a40d0 100644
--- a/java/dagger/internal/codegen/binding/DependencyRequestFactory.java
+++ b/java/dagger/internal/codegen/binding/DependencyRequestFactory.java
@@ -16,40 +16,51 @@
package dagger.internal.codegen.binding;
-import static com.google.auto.common.MoreTypes.isTypeOf;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static androidx.room.compiler.processing.compat.XConverters.toXProcessing;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.base.RequestKinds.extractKeyType;
-import static dagger.internal.codegen.base.RequestKinds.frameworkClass;
+import static dagger.internal.codegen.base.RequestKinds.frameworkClassName;
import static dagger.internal.codegen.base.RequestKinds.getRequestKind;
+import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedParameter;
import static dagger.internal.codegen.binding.ConfigurationAnnotations.getNullableType;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.langmodel.DaggerTypes.unwrapType;
-import static dagger.model.RequestKind.FUTURE;
-import static dagger.model.RequestKind.INSTANCE;
-import static dagger.model.RequestKind.MEMBERS_INJECTION;
-import static dagger.model.RequestKind.PRODUCER;
-import static dagger.model.RequestKind.PROVIDER;
+import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;
+import static dagger.spi.model.RequestKind.FUTURE;
+import static dagger.spi.model.RequestKind.INSTANCE;
+import static dagger.spi.model.RequestKind.MEMBERS_INJECTION;
+import static dagger.spi.model.RequestKind.PRODUCER;
+import static dagger.spi.model.RequestKind.PROVIDER;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XMethodType;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XVariableElement;
+import androidx.room.compiler.processing.compat.XConverters;
import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.ListenableFuture;
import dagger.Lazy;
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.OptionalType;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.RequestKind;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.spi.model.DaggerElement;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
+import dagger.spi.model.RequestKind;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeMirror;
/**
@@ -59,15 +70,27 @@ import javax.lang.model.type.TypeMirror;
* may mean that the type will be generated in a later round of processing.
*/
public final class DependencyRequestFactory {
+ private final XProcessingEnv processingEnv;
private final KeyFactory keyFactory;
private final InjectionAnnotations injectionAnnotations;
@Inject
- DependencyRequestFactory(KeyFactory keyFactory, InjectionAnnotations injectionAnnotations) {
+ DependencyRequestFactory(
+ XProcessingEnv processingEnv,
+ KeyFactory keyFactory,
+ InjectionAnnotations injectionAnnotations) {
+ this.processingEnv = processingEnv;
this.keyFactory = keyFactory;
this.injectionAnnotations = injectionAnnotations;
}
+ ImmutableSet<DependencyRequest> forRequiredResolvedXVariables(
+ List<? extends XVariableElement> variables, List<XType> resolvedTypes) {
+ return forRequiredResolvedVariables(
+ variables.stream().map(XConverters::toJavac).collect(toImmutableList()),
+ resolvedTypes.stream().map(XConverters::toJavac).collect(toImmutableList()));
+ }
+
ImmutableSet<DependencyRequest> forRequiredResolvedVariables(
List<? extends VariableElement> variables, List<? extends TypeMirror> resolvedTypes) {
checkState(resolvedTypes.size() == variables.size());
@@ -114,7 +137,7 @@ public final class DependencyRequestFactory {
case MAP:
MapType mapType = MapType.from(multibindingKey);
for (RequestKind kind : WRAPPING_MAP_VALUE_FRAMEWORK_TYPES) {
- if (mapType.valuesAreTypeOf(frameworkClass(kind))) {
+ if (mapType.valuesAreTypeOf(frameworkClassName(kind))) {
return kind;
}
}
@@ -130,44 +153,49 @@ public final class DependencyRequestFactory {
}
DependencyRequest forRequiredResolvedVariable(
+ XVariableElement variableElement, XType resolvedType) {
+ return forRequiredResolvedVariable(toJavac(variableElement), toJavac(resolvedType));
+ }
+
+ DependencyRequest forRequiredResolvedVariable(
VariableElement variableElement, TypeMirror resolvedType) {
checkNotNull(variableElement);
checkNotNull(resolvedType);
// Ban @Assisted parameters, they are not considered dependency requests.
- checkArgument(!AssistedInjectionAnnotations.isAssistedParameter(variableElement));
+ checkArgument(!isAssistedParameter(toXProcessing(variableElement, processingEnv)));
Optional<AnnotationMirror> qualifier = injectionAnnotations.getQualifier(variableElement);
return newDependencyRequest(variableElement, resolvedType, qualifier);
}
public DependencyRequest forComponentProvisionMethod(
- ExecutableElement provisionMethod, ExecutableType provisionMethodType) {
+ XMethodElement provisionMethod, XMethodType provisionMethodType) {
checkNotNull(provisionMethod);
checkNotNull(provisionMethodType);
checkArgument(
provisionMethod.getParameters().isEmpty(),
"Component provision methods must be empty: %s",
provisionMethod);
- Optional<AnnotationMirror> qualifier = injectionAnnotations.getQualifier(provisionMethod);
+ Optional<XAnnotation> qualifier = injectionAnnotations.getQualifier(provisionMethod);
return newDependencyRequest(provisionMethod, provisionMethodType.getReturnType(), qualifier);
}
public DependencyRequest forComponentProductionMethod(
- ExecutableElement productionMethod, ExecutableType productionMethodType) {
+ XMethodElement productionMethod, XMethodType productionMethodType) {
checkNotNull(productionMethod);
checkNotNull(productionMethodType);
checkArgument(
productionMethod.getParameters().isEmpty(),
"Component production methods must be empty: %s",
productionMethod);
- TypeMirror type = productionMethodType.getReturnType();
- Optional<AnnotationMirror> qualifier = injectionAnnotations.getQualifier(productionMethod);
+ XType type = productionMethodType.getReturnType();
+ Optional<XAnnotation> qualifier = injectionAnnotations.getQualifier(productionMethod);
// Only a component production method can be a request for a ListenableFuture, so we
// special-case it here.
- if (isTypeOf(ListenableFuture.class, type)) {
+ if (isTypeOf(type, TypeNames.LISTENABLE_FUTURE)) {
return DependencyRequest.builder()
.kind(FUTURE)
.key(keyFactory.forQualifiedType(qualifier, unwrapType(type)))
- .requestElement(productionMethod)
+ .requestElement(DaggerElement.from(productionMethod))
.build();
} else {
return newDependencyRequest(productionMethod, type, qualifier);
@@ -175,17 +203,16 @@ public final class DependencyRequestFactory {
}
DependencyRequest forComponentMembersInjectionMethod(
- ExecutableElement membersInjectionMethod, ExecutableType membersInjectionMethodType) {
+ XMethodElement membersInjectionMethod, XMethodType membersInjectionMethodType) {
checkNotNull(membersInjectionMethod);
checkNotNull(membersInjectionMethodType);
- Optional<AnnotationMirror> qualifier =
- injectionAnnotations.getQualifier(membersInjectionMethod);
+ Optional<XAnnotation> qualifier = injectionAnnotations.getQualifier(membersInjectionMethod);
checkArgument(!qualifier.isPresent());
- TypeMirror membersInjectedType = getOnlyElement(membersInjectionMethodType.getParameterTypes());
+ XType membersInjectedType = getOnlyElement(membersInjectionMethodType.getParameterTypes());
return DependencyRequest.builder()
.kind(MEMBERS_INJECTION)
.key(keyFactory.forMembersInjectedType(membersInjectedType))
- .requestElement(membersInjectionMethod)
+ .requestElement(DaggerElement.from(membersInjectionMethod))
.build();
}
@@ -219,12 +246,18 @@ public final class DependencyRequestFactory {
}
private DependencyRequest newDependencyRequest(
+ XElement requestElement, XType type, Optional<XAnnotation> qualifier) {
+ return newDependencyRequest(
+ toJavac(requestElement), toJavac(type), qualifier.map(XConverters::toJavac));
+ }
+
+ private DependencyRequest newDependencyRequest(
Element requestElement, TypeMirror type, Optional<AnnotationMirror> qualifier) {
RequestKind requestKind = getRequestKind(type);
return DependencyRequest.builder()
.kind(requestKind)
.key(keyFactory.forQualifiedType(qualifier, extractKeyType(type)))
- .requestElement(requestElement)
+ .requestElement(DaggerElement.from(toXProcessing(requestElement, processingEnv)))
.isNullable(allowsNull(requestKind, getNullableType(requestElement)))
.build();
}
diff --git a/java/dagger/internal/codegen/binding/DependencyRequestFormatter.java b/java/dagger/internal/codegen/binding/DependencyRequestFormatter.java
index 888dec2d8..8fe9249c1 100644
--- a/java/dagger/internal/codegen/binding/DependencyRequestFormatter.java
+++ b/java/dagger/internal/codegen/binding/DependencyRequestFormatter.java
@@ -23,11 +23,11 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
import dagger.Provides;
import dagger.internal.codegen.base.Formatter;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
import dagger.producers.Produces;
+import dagger.spi.model.DaggerAnnotation;
+import dagger.spi.model.DependencyRequest;
import java.util.Optional;
import javax.inject.Inject;
-import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementVisitor;
import javax.lang.model.element.ExecutableElement;
@@ -67,7 +67,7 @@ public final class DependencyRequestFormatter extends Formatter<DependencyReques
public String format(DependencyRequest request) {
return request
.requestElement()
- .map(element -> element.accept(formatVisitor, request))
+ .map(element -> element.java().accept(formatVisitor, request))
.orElse("");
}
@@ -101,7 +101,8 @@ public final class DependencyRequestFormatter extends Formatter<DependencyReques
@Override
public String visitVariable(VariableElement variable, DependencyRequest request) {
- TypeMirror requestedType = requestType(request.kind(), request.key().type(), types);
+ TypeMirror requestedType =
+ requestType(request.kind(), request.key().type().java(), types);
return INDENT
+ formatQualifier(request.key().qualifier())
+ requestedType
@@ -122,7 +123,7 @@ public final class DependencyRequestFormatter extends Formatter<DependencyReques
}
};
- private String formatQualifier(Optional<AnnotationMirror> maybeQualifier) {
+ private String formatQualifier(Optional<DaggerAnnotation> maybeQualifier) {
return maybeQualifier.map(qualifier -> qualifier + " ").orElse("");
}
diff --git a/java/dagger/internal/codegen/binding/DependencyVariableNamer.java b/java/dagger/internal/codegen/binding/DependencyVariableNamer.java
index e01d22ef2..45076fe3d 100644
--- a/java/dagger/internal/codegen/binding/DependencyVariableNamer.java
+++ b/java/dagger/internal/codegen/binding/DependencyVariableNamer.java
@@ -22,7 +22,7 @@ import com.google.auto.common.MoreTypes;
import com.google.common.base.Ascii;
import com.google.common.base.CaseFormat;
import dagger.Lazy;
-import dagger.model.DependencyRequest;
+import dagger.spi.model.DependencyRequest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Provider;
@@ -39,10 +39,10 @@ final class DependencyVariableNamer {
static String name(DependencyRequest dependency) {
if (!dependency.requestElement().isPresent()) {
- return simpleVariableName(MoreTypes.asTypeElement(dependency.key().type()));
+ return simpleVariableName(MoreTypes.asTypeElement(dependency.key().type().java()));
}
- String variableName = dependency.requestElement().get().getSimpleName().toString();
+ String variableName = dependency.requestElement().get().java().getSimpleName().toString();
if (Ascii.isUpperCase(variableName.charAt(0))) {
variableName = toLowerCamel(variableName);
}
diff --git a/java/dagger/internal/codegen/binding/ErrorMessages.java b/java/dagger/internal/codegen/binding/ErrorMessages.java
index 8962ade81..0bc43b208 100644
--- a/java/dagger/internal/codegen/binding/ErrorMessages.java
+++ b/java/dagger/internal/codegen/binding/ErrorMessages.java
@@ -16,15 +16,19 @@
package dagger.internal.codegen.binding;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import dagger.internal.codegen.base.ComponentAnnotation;
+import dagger.internal.codegen.base.ComponentCreatorAnnotation;
+import dagger.internal.codegen.base.ComponentKind;
import java.util.Set;
import java.util.function.Function;
import java.util.function.UnaryOperator;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
/** The collection of error messages to be reported back to users. */
public final class ErrorMessages {
@@ -199,18 +203,18 @@ public final class ErrorMessages {
}
public final String factoryMethodReturnsSupertypeWithMissingMethods(
- TypeElement component,
- TypeElement componentBuilder,
- TypeMirror returnType,
- ExecutableElement buildMethod,
- Set<ExecutableElement> additionalMethods) {
+ XTypeElement component,
+ XTypeElement componentBuilder,
+ XType returnType,
+ XMethodElement buildMethod,
+ Set<XMethodElement> additionalMethods) {
return String.format(
"%1$s.%2$s() returns %3$s, but %4$s declares additional component method(s): %5$s. In "
+ "order to provide type-safe access to these methods, override %2$s() to return "
+ "%4$s",
componentBuilder.getQualifiedName(),
- buildMethod.getSimpleName(),
- returnType,
+ getSimpleName(buildMethod),
+ returnType.getTypeName(),
component.getQualifiedName(),
Joiner.on(", ").join(additionalMethods));
}
diff --git a/java/dagger/internal/codegen/binding/FrameworkField.java b/java/dagger/internal/codegen/binding/FrameworkField.java
index 3b0b73fbe..5f72fe2e4 100644
--- a/java/dagger/internal/codegen/binding/FrameworkField.java
+++ b/java/dagger/internal/codegen/binding/FrameworkField.java
@@ -16,8 +16,10 @@
package dagger.internal.codegen.binding;
-import static dagger.model.BindingKind.MEMBERS_INJECTOR;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static dagger.spi.model.BindingKind.MEMBERS_INJECTOR;
+import androidx.room.compiler.processing.XType;
import com.google.auto.value.AutoValue;
import com.google.common.base.CaseFormat;
import com.squareup.javapoet.ClassName;
@@ -29,7 +31,6 @@ import javax.lang.model.element.ElementVisitor;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementKindVisitor8;
/**
@@ -69,24 +70,22 @@ public abstract class FrameworkField {
* one for the binding's type.
*/
public static FrameworkField forBinding(
- ContributionBinding binding, Optional<ClassName> frameworkClass) {
+ ContributionBinding binding, Optional<ClassName> frameworkClassName) {
return create(
- frameworkClass.orElse(
- ClassName.get(
- FrameworkType.forBindingType(binding.bindingType()).frameworkClass())),
- TypeName.get(fieldValueType(binding)),
+ frameworkClassName.orElse(binding.frameworkType().frameworkClassName()),
+ fieldValueType(binding).getTypeName(),
frameworkFieldName(binding));
}
- private static TypeMirror fieldValueType(ContributionBinding binding) {
+ private static XType fieldValueType(ContributionBinding binding) {
return binding.contributionType().isMultibinding()
? binding.contributedType()
- : binding.key().type();
+ : binding.key().type().xprocessing();
}
private static String frameworkFieldName(ContributionBinding binding) {
if (binding.bindingElement().isPresent()) {
- String name = BINDING_ELEMENT_NAME.visit(binding.bindingElement().get(), binding);
+ String name = BINDING_ELEMENT_NAME.visit(toJavac(binding.bindingElement().get()), binding);
return binding.kind().equals(MEMBERS_INJECTOR) ? name + "MembersInjector" : name;
}
return KeyVariableNamer.name(binding.key());
diff --git a/java/dagger/internal/codegen/binding/FrameworkType.java b/java/dagger/internal/codegen/binding/FrameworkType.java
index 6b160b613..0c0868c19 100644
--- a/java/dagger/internal/codegen/binding/FrameworkType.java
+++ b/java/dagger/internal/codegen/binding/FrameworkType.java
@@ -18,66 +18,49 @@ package dagger.internal.codegen.binding;
import static com.google.common.base.CaseFormat.UPPER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
-import static dagger.model.RequestKind.INSTANCE;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
-import dagger.Lazy;
-import dagger.internal.DoubleCheck;
-import dagger.internal.ProviderOfLazy;
import dagger.internal.codegen.base.RequestKinds;
import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import dagger.model.RequestKind;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.producers.internal.Producers;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.RequestKind;
import java.util.Optional;
-import javax.inject.Provider;
import javax.lang.model.type.TypeMirror;
/** One of the core types initialized as fields in a generated component. */
public enum FrameworkType {
- /** A {@link Provider}. */
+ /** A {@link javax.inject.Provider}. */
PROVIDER {
@Override
- public Class<?> frameworkClass() {
- return Provider.class;
- }
-
- @Override
- public Optional<RequestKind> requestKind() {
- return Optional.of(RequestKind.PROVIDER);
- }
-
- @Override
public CodeBlock to(RequestKind requestKind, CodeBlock from) {
switch (requestKind) {
case INSTANCE:
return CodeBlock.of("$L.get()", from);
case LAZY:
- return CodeBlock.of("$T.lazy($L)", DoubleCheck.class, from);
+ return CodeBlock.of("$T.lazy($L)", TypeNames.DOUBLE_CHECK, from);
case PROVIDER:
return from;
case PROVIDER_OF_LAZY:
- return CodeBlock.of("$T.create($L)", ProviderOfLazy.class, from);
+ return CodeBlock.of("$T.create($L)", TypeNames.PROVIDER_OF_LAZY, from);
case PRODUCER:
- return CodeBlock.of("$T.producerFromProvider($L)", Producers.class, from);
+ return CodeBlock.of("$T.producerFromProvider($L)", TypeNames.PRODUCERS, from);
case FUTURE:
- return CodeBlock.of("$T.immediateFuture($L)", Futures.class, to(INSTANCE, from));
+ return CodeBlock.of(
+ "$T.immediateFuture($L)", TypeNames.FUTURES, to(RequestKind.INSTANCE, from));
case PRODUCED:
- return CodeBlock.of("$T.successful($L)", Produced.class, to(INSTANCE, from));
+ return CodeBlock.of(
+ "$T.successful($L)", TypeNames.PRODUCED, to(RequestKind.INSTANCE, from));
default:
throw new IllegalArgumentException(
@@ -96,36 +79,24 @@ public enum FrameworkType {
return from;
case PROVIDER_OF_LAZY:
- TypeMirror lazyType = types.rewrapType(from.type(), Lazy.class);
- return Expression.create(types.wrapType(lazyType, Provider.class), codeBlock);
+ TypeMirror lazyType = types.rewrapType(from.type(), TypeNames.LAZY);
+ return Expression.create(types.wrapType(lazyType, TypeNames.PROVIDER), codeBlock);
case FUTURE:
return Expression.create(
- types.rewrapType(from.type(), ListenableFuture.class), codeBlock);
+ types.rewrapType(from.type(), TypeNames.LISTENABLE_FUTURE), codeBlock);
default:
return Expression.create(
- types.rewrapType(from.type(), RequestKinds.frameworkClass(requestKind)), codeBlock);
+ types.rewrapType(from.type(), RequestKinds.frameworkClassName(requestKind)),
+ codeBlock);
}
}
},
- /** A {@link Producer}. */
+ /** A {@link dagger.producers.Producer}. */
PRODUCER_NODE {
@Override
- public Class<?> frameworkClass() {
- // TODO(cgdecker): Replace this with new class for representing internal producer nodes.
- // Currently the new class is CancellableProducer, but it may be changed to ProducerNode and
- // made to not implement Producer.
- return Producer.class;
- }
-
- @Override
- public Optional<RequestKind> requestKind() {
- return Optional.empty();
- }
-
- @Override
public CodeBlock to(RequestKind requestKind, CodeBlock from) {
switch (requestKind) {
case FUTURE:
@@ -145,7 +116,7 @@ public enum FrameworkType {
switch (requestKind) {
case FUTURE:
return Expression.create(
- types.rewrapType(from.type(), ListenableFuture.class),
+ types.rewrapType(from.type(), TypeNames.LISTENABLE_FUTURE),
to(requestKind, from.codeBlock()));
case PRODUCER:
@@ -156,8 +127,7 @@ public enum FrameworkType {
String.format("Cannot request a %s from a %s", requestKind, this));
}
}
- },
- ;
+ };
/** Returns the framework type appropriate for fields for a given binding type. */
public static FrameworkType forBindingType(BindingType bindingType) {
@@ -182,15 +152,34 @@ public enum FrameworkType {
}
/** The class of fields of this type. */
- public abstract Class<?> frameworkClass();
+ public ClassName frameworkClassName() {
+ switch (this) {
+ case PROVIDER:
+ return TypeNames.PROVIDER;
+ case PRODUCER_NODE:
+ // TODO(cgdecker): Replace this with new class for representing internal producer nodes.
+ // Currently the new class is CancellableProducer, but it may be changed to ProducerNode and
+ // made to not implement Producer.
+ return TypeNames.PRODUCER;
+ }
+ throw new AssertionError("Unknown value: " + this.name());
+ }
- /** Returns the {@link #frameworkClass()} parameterized with a type. */
+ /** Returns the {@link #frameworkClassName()} parameterized with a type. */
public ParameterizedTypeName frameworkClassOf(TypeName valueType) {
- return ParameterizedTypeName.get(ClassName.get(frameworkClass()), valueType);
+ return ParameterizedTypeName.get(frameworkClassName(), valueType);
}
/** The request kind that an instance of this framework type can satisfy directly, if any. */
- public abstract Optional<RequestKind> requestKind();
+ public RequestKind requestKind() {
+ switch (this) {
+ case PROVIDER:
+ return RequestKind.PROVIDER;
+ case PRODUCER_NODE:
+ return RequestKind.PRODUCER;
+ }
+ throw new AssertionError("Unknown value: " + this.name());
+ }
/**
* Returns a {@link CodeBlock} that evaluates to a requested object given an expression that
diff --git a/java/dagger/internal/codegen/binding/FrameworkTypeMapper.java b/java/dagger/internal/codegen/binding/FrameworkTypeMapper.java
index 85463aff8..776fac6b7 100644
--- a/java/dagger/internal/codegen/binding/FrameworkTypeMapper.java
+++ b/java/dagger/internal/codegen/binding/FrameworkTypeMapper.java
@@ -18,8 +18,8 @@ package dagger.internal.codegen.binding;
import static dagger.internal.codegen.binding.BindingType.PRODUCTION;
-import dagger.model.RequestKind;
import dagger.producers.Producer;
+import dagger.spi.model.RequestKind;
import javax.inject.Provider;
/**
diff --git a/java/dagger/internal/codegen/binding/InjectBindingRegistry.java b/java/dagger/internal/codegen/binding/InjectBindingRegistry.java
index 5203130f4..ceb5024b4 100644
--- a/java/dagger/internal/codegen/binding/InjectBindingRegistry.java
+++ b/java/dagger/internal/codegen/binding/InjectBindingRegistry.java
@@ -16,16 +16,17 @@
package dagger.internal.codegen.binding;
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XFieldElement;
+import androidx.room.compiler.processing.XMethodElement;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import dagger.Component;
import dagger.Provides;
import dagger.internal.codegen.base.SourceFileGenerationException;
import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.model.Key;
+import dagger.spi.model.Key;
import java.util.Optional;
import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
/**
* Maintains the collection of provision bindings from {@link Inject} constructors and members
@@ -53,10 +54,13 @@ public interface InjectBindingRegistry {
Optional<ProvisionBinding> getOrFindMembersInjectorProvisionBinding(Key key);
@CanIgnoreReturnValue
- Optional<ProvisionBinding> tryRegisterConstructor(ExecutableElement constructorElement);
+ Optional<ProvisionBinding> tryRegisterInjectConstructor(XConstructorElement constructorElement);
@CanIgnoreReturnValue
- Optional<MembersInjectionBinding> tryRegisterMembersInjectedType(TypeElement typeElement);
+ Optional<MembersInjectionBinding> tryRegisterInjectField(XFieldElement fieldElement);
+
+ @CanIgnoreReturnValue
+ Optional<MembersInjectionBinding> tryRegisterInjectMethod(XMethodElement methodElement);
/**
* This method ensures that sources for all registered {@link Binding bindings} (either explicitly
diff --git a/java/dagger/internal/codegen/binding/InjectionAnnotations.java b/java/dagger/internal/codegen/binding/InjectionAnnotations.java
index 748755e08..250f5ee59 100644
--- a/java/dagger/internal/codegen/binding/InjectionAnnotations.java
+++ b/java/dagger/internal/codegen/binding/InjectionAnnotations.java
@@ -16,33 +16,59 @@
package dagger.internal.codegen.binding;
+import static androidx.room.compiler.processing.XElementKt.isConstructor;
+import static androidx.room.compiler.processing.XElementKt.isField;
+import static androidx.room.compiler.processing.XElementKt.isMethod;
+import static androidx.room.compiler.processing.XElementKt.isMethodParameter;
+import static androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static androidx.room.compiler.processing.compat.XConverters.toXProcessing;
import static com.google.auto.common.MoreElements.asType;
import static com.google.auto.common.MoreElements.asVariable;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.base.MoreAnnotationValues.getStringValue;
+import static dagger.internal.codegen.binding.SourceFiles.factoryNameForElement;
import static dagger.internal.codegen.binding.SourceFiles.memberInjectedFieldSignatureForVariable;
import static dagger.internal.codegen.binding.SourceFiles.membersInjectorNameForType;
+import static dagger.internal.codegen.extension.DaggerCollectors.onlyElement;
+import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
+import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
+import static dagger.internal.codegen.xprocessing.XElements.asMethod;
+import static dagger.internal.codegen.xprocessing.XElements.asMethodParameter;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+import static dagger.internal.codegen.xprocessing.XElements.closestEnclosingTypeElement;
import static javax.lang.model.element.Modifier.STATIC;
import static javax.lang.model.util.ElementFilter.constructorsIn;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.common.AnnotationMirrors;
-import com.google.auto.common.SuperficialValidation;
import com.google.common.base.Equivalence;
import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import dagger.internal.InjectedFieldSignature;
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.base.DaggerSuperficialValidation;
+import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.extension.DaggerCollectors;
import dagger.internal.codegen.extension.DaggerStreams;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.spi.model.DaggerAnnotation;
+import dagger.spi.model.Scope;
import java.util.Optional;
import java.util.stream.Stream;
import javax.inject.Inject;
-import javax.inject.Qualifier;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
@@ -56,21 +82,148 @@ public final class InjectionAnnotations {
private static final Equivalence<AnnotationMirror> EQUIVALENCE = AnnotationMirrors.equivalence();
+ private final XProcessingEnv processingEnv;
private final DaggerElements elements;
private final KotlinMetadataUtil kotlinMetadataUtil;
+ private final DaggerSuperficialValidation superficialValidation;
+ private final CompilerOptions compilerOptions;
@Inject
- InjectionAnnotations(DaggerElements elements, KotlinMetadataUtil kotlinMetadataUtil) {
+ InjectionAnnotations(
+ XProcessingEnv processingEnv,
+ DaggerElements elements,
+ KotlinMetadataUtil kotlinMetadataUtil,
+ DaggerSuperficialValidation superficialValidation,
+ CompilerOptions compilerOptions) {
+ this.processingEnv = processingEnv;
this.elements = elements;
this.kotlinMetadataUtil = kotlinMetadataUtil;
+ this.superficialValidation = superficialValidation;
+ this.compilerOptions = compilerOptions;
}
- public Optional<AnnotationMirror> getQualifier(Element e) {
- if (!SuperficialValidation.validateElement(e)) {
- throw new TypeNotPresentException(e.toString(), null);
+ /**
+ * Returns the scope on the given element if it exists.
+ *
+ * <p>The {@code ScopeMetadata} is used to avoid superficial validation on unnecessary
+ * annotations. If the {@code ScopeMetadata} does not exist, then all annotations must be
+ * superficially validated before we can determine if they are scopes or not.
+ *
+ * @throws IllegalArgumentException if the given element has more than one scope.
+ */
+ public Optional<Scope> getScope(XElement element) {
+ return getScopes(element).stream().collect(toOptional());
+ }
+
+ /**
+ * Returns the scopes on the given element, or an empty set if none exist.
+ *
+ * <p>Note: Use {@link #getScope(XElement)} if the usage of the scope on the given element has
+ * already been validated and known to be unique. This method should typically only be used in the
+ * process of such validation.
+ *
+ * <p>The {@code ScopeMetadata} is used to avoid superficial validation on unnecessary
+ * annotations. If the {@code ScopeMetadata} does not exist, then all annotations must be
+ * superficially validated before we can determine if they are scopes or not.
+ */
+ public ImmutableSet<Scope> getScopes(XElement element) {
+ superficialValidation.validateTypeOf(element);
+ ImmutableSet<Scope> scopes =
+ getScopesFromScopeMetadata(element)
+ .orElseGet(
+ () -> {
+ // Validate the annotation types before we check for @Scope, otherwise the @Scope
+ // annotation may appear to be missing (b/213880825).
+ superficialValidation.validateAnnotationTypesOf(element);
+ return element.getAllAnnotations().stream()
+ .filter(InjectionAnnotations::hasScopeAnnotation)
+ .map(DaggerAnnotation::from)
+ .map(Scope::scope)
+ .collect(toImmutableSet());
+ });
+
+ // Fully validate each scope to ensure its values are also valid.
+ scopes.stream()
+ .map(scope -> scope.scopeAnnotation().xprocessing())
+ .forEach(scope -> superficialValidation.validateAnnotationOf(element, scope));
+ return scopes;
+ }
+
+ private Optional<ImmutableSet<Scope>> getScopesFromScopeMetadata(XElement element) {
+ Optional<XAnnotation> scopeMetadata = getScopeMetadata(element);
+ if (!scopeMetadata.isPresent()) {
+ return Optional.empty();
+ }
+ String scopeName = scopeMetadata.get().getAsString("value");
+ if (scopeName.isEmpty()) {
+ return Optional.of(ImmutableSet.of());
+ }
+ XAnnotation scopeAnnotation =
+ element.getAllAnnotations().stream()
+ .filter(
+ annotation ->
+ scopeName.contentEquals(
+ annotation.getType().getTypeElement().getQualifiedName()))
+ .collect(onlyElement());
+ // Do superficial validation before we convert to a Scope, otherwise the @Scope annotation may
+ // appear to be missing from the annotation if it's no longer on the classpath.
+ superficialValidation.validateAnnotationTypeOf(element, scopeAnnotation);
+
+ // If strictSuperficialValidation is disabled, then we fall back to the old behavior where
+ // we may potentially miss a scope rather than report an exception.
+ if (compilerOptions.strictSuperficialValidation()) {
+ return Optional.of(ImmutableSet.of(Scope.scope(DaggerAnnotation.from(scopeAnnotation))));
+ } else {
+ return Scope.isScope(DaggerAnnotation.from(scopeAnnotation))
+ ? Optional.of(ImmutableSet.of(Scope.scope(DaggerAnnotation.from(scopeAnnotation))))
+ : Optional.empty();
+ }
+ }
+
+ private Optional<XAnnotation> getScopeMetadata(XElement element) {
+ return getGeneratedNameForScopeMetadata(element)
+ .flatMap(factoryName -> Optional.ofNullable(processingEnv.findTypeElement(factoryName)))
+ .flatMap(factory -> Optional.ofNullable(factory.getAnnotation(TypeNames.SCOPE_METADATA)));
+ }
+
+ private Optional<ClassName> getGeneratedNameForScopeMetadata(XElement element) {
+ // Currently, we only support ScopeMetadata for inject-constructor types and provides methods.
+ if (isTypeElement(element)) {
+ return asTypeElement(element).getConstructors().stream()
+ .filter(InjectionAnnotations::hasInjectOrAssistedInjectAnnotation)
+ .findFirst()
+ .map(SourceFiles::factoryNameForElement);
+ } else if (isMethod(element) && element.hasAnnotation(TypeNames.PROVIDES)) {
+ return Optional.of(factoryNameForElement(asMethod(element)));
}
+ return Optional.empty();
+ }
+
+ /*
+ * Returns the qualifier on the given element if it exists.
+ *
+ * <p>The {@code QualifierMetadata} is used to avoid superficial validation on unnecessary
+ * annotations. If the {@code QualifierMetadata} does not exist, then all annotations must be
+ * superficially validated before we can determine if they are qualifiers or not.
+ *
+ * @throws IllegalArgumentException if the given element has more than one qualifier.
+ */
+ public Optional<XAnnotation> getQualifier(XElement element) {
+ return getQualifier(toJavac(element)).map(qualifier -> toXProcessing(qualifier, processingEnv));
+ }
+
+ /*
+ * Returns the qualifier on the given element if it exists.
+ *
+ * <p>The {@code QualifierMetadata} is used to avoid superficial validation on unnecessary
+ * annotations. If the {@code QualifierMetadata} does not exist, then all annotations must be
+ * superficially validated before we can determine if they are qualifiers or not.
+ *
+ * @throws IllegalArgumentException if the given element has more than one qualifier.
+ */
+ public Optional<AnnotationMirror> getQualifier(Element e) {
checkNotNull(e);
- ImmutableCollection<? extends AnnotationMirror> qualifierAnnotations = getQualifiers(e);
+ ImmutableList<? extends AnnotationMirror> qualifierAnnotations = getQualifiers(e);
switch (qualifierAnnotations.size()) {
case 0:
return Optional.empty();
@@ -82,32 +235,187 @@ public final class InjectionAnnotations {
}
}
- public ImmutableCollection<? extends AnnotationMirror> getQualifiers(Element element) {
+ /*
+ * Returns the qualifiers on the given element, or an empty set if none exist.
+ *
+ * <p>The {@code QualifierMetadata} is used to avoid superficial validation on unnecessary
+ * annotations. If the {@code QualifierMetadata} does not exist, then all annotations must be
+ * superficially validated before we can determine if they are qualifiers or not.
+ */
+ public ImmutableSet<XAnnotation> getQualifiers(XElement element) {
+ return getQualifiers(toJavac(element)).stream()
+ .map(qualifier -> toXProcessing(qualifier, processingEnv))
+ .collect(toImmutableSet());
+ }
+
+ /*
+ * Returns the qualifiers on the given element, or an empty set if none exist.
+ *
+ * <p>The {@code QualifierMetadata} is used to avoid superficial validation on unnecessary
+ * annotations. If the {@code QualifierMetadata} does not exist, then all annotations must be
+ * superficially validated before we can determine if they are qualifiers or not.
+ */
+ public ImmutableList<? extends AnnotationMirror> getQualifiers(Element element) {
+ superficialValidation.validateTypeOf(toXProcessing(element, processingEnv));
ImmutableSet<? extends AnnotationMirror> qualifiers =
- AnnotationMirrors.getAnnotatedAnnotations(element, Qualifier.class);
+ getQualifiersFromQualifierMetadata(element)
+ .orElseGet(
+ () -> {
+ // Validate the annotation types before we check for @Qualifier, otherwise the
+ // @Qualifier annotation may appear to be missing (b/213880825).
+ superficialValidation.validateAnnotationTypesOf(element);
+ return element.getAnnotationMirrors().stream()
+ .filter(InjectionAnnotations::hasQualifierAnnotation)
+ .collect(toImmutableSet());
+ });
+
if (element.getKind() == ElementKind.FIELD
// static injected fields are not supported, no need to get qualifier from kotlin metadata
&& !element.getModifiers().contains(STATIC)
- && isAnnotationPresent(element, Inject.class)
+ && hasInjectAnnotation(element)
&& kotlinMetadataUtil.hasMetadata(element)) {
- return Stream.concat(
- qualifiers.stream(), getQualifiersForKotlinProperty(asVariable(element)).stream())
- .map(EQUIVALENCE::wrap) // Wrap in equivalence to deduplicate
- .distinct()
- .map(Wrapper::get)
- .collect(DaggerStreams.toImmutableList());
+ qualifiers =
+ Stream.concat(
+ qualifiers.stream(), getQualifiersForKotlinProperty(asVariable(element)).stream())
+ .map(EQUIVALENCE::wrap) // Wrap in equivalence to deduplicate
+ .distinct()
+ .map(Wrapper::get)
+ .collect(DaggerStreams.toImmutableSet());
+ }
+
+ // Fully validate each qualifier to ensure its values are also valid.
+ qualifiers.forEach(
+ qualifier -> {
+ superficialValidation.validateAnnotationOf(element, qualifier);
+ });
+
+ return qualifiers.asList();
+ }
+
+ private Optional<ImmutableSet<? extends AnnotationMirror>> getQualifiersFromQualifierMetadata(
+ Element javaElement) {
+ XElement element = toXProcessing(javaElement, processingEnv);
+ Optional<XAnnotation> qualifierMetadata = getQualifierMetadata(element);
+ if (!qualifierMetadata.isPresent()) {
+ return Optional.empty();
+ }
+ ImmutableSet<String> qualifierNames =
+ ImmutableSet.copyOf(qualifierMetadata.get().getAsStringList("value"));
+ if (qualifierNames.isEmpty()) {
+ return Optional.of(ImmutableSet.of());
+ }
+ ImmutableSet<XAnnotation> qualifierAnnotations =
+ element.getAllAnnotations().stream()
+ .filter(
+ annotation ->
+ qualifierNames.contains(
+ annotation.getType().getTypeElement().getQualifiedName()))
+ .collect(toImmutableSet());
+ if (qualifierAnnotations.isEmpty()) {
+ return Optional.of(ImmutableSet.of());
+ }
+ // We should be guaranteed that there's exactly one qualifier since the existance of
+ // @QualifierMetadata means that this element has already been processed and multiple
+ // qualifiers would have been caught already.
+ XAnnotation qualifierAnnotation = getOnlyElement(qualifierAnnotations);
+
+ // Ensure the annotation type is superficially valid before we check for @Qualifier, otherwise
+ // the @Qualifier marker may appear to be missing from the annotation (b/213880825).
+ superficialValidation.validateAnnotationTypeOf(element, qualifierAnnotation);
+ if (compilerOptions.strictSuperficialValidation()) {
+ return Optional.of(ImmutableSet.of(toJavac(qualifierAnnotation)));
} else {
- return qualifiers.asList();
+ // If strictSuperficialValidation is disabled, then we fall back to the old behavior where
+ // we may potentially miss a qualifier rather than report an exception.
+ return hasQualifierAnnotation(toJavac(qualifierAnnotation))
+ ? Optional.of(ImmutableSet.of(toJavac(qualifierAnnotation)))
+ : Optional.empty();
}
}
+ /**
+ * Returns {@code QualifierMetadata} annotation.
+ *
+ * <p>Currently, {@code QualifierMetadata} is only associated with inject constructor parameters,
+ * inject fields, inject method parameters, provide methods, and provide method parameters.
+ */
+ private Optional<XAnnotation> getQualifierMetadata(XElement element) {
+ return getGeneratedNameForQualifierMetadata(element)
+ .flatMap(name -> Optional.ofNullable(processingEnv.findTypeElement(name)))
+ .flatMap(type -> Optional.ofNullable(type.getAnnotation(TypeNames.QUALIFIER_METADATA)));
+ }
+
+ private Optional<ClassName> getGeneratedNameForQualifierMetadata(XElement element) {
+ // Currently we only support @QualifierMetadata for @Inject fields, @Inject method parameters,
+ // @Inject constructor parameters, @Provides methods, and @Provides method parameters.
+ if (isField(element) && hasInjectAnnotation(element)) {
+ return Optional.of(membersInjectorNameForType(closestEnclosingTypeElement(element)));
+ } else if (isMethod(element) && element.hasAnnotation(TypeNames.PROVIDES)) {
+ return Optional.of(factoryNameForElement(asMethod(element)));
+ } else if (isMethodParameter(element)) {
+ XExecutableElement executableElement = asMethodParameter(element).getEnclosingMethodElement();
+ if (isConstructor(executableElement)
+ && hasInjectOrAssistedInjectAnnotation(executableElement)) {
+ return Optional.of(factoryNameForElement(executableElement));
+ }
+ if (isMethod(executableElement) && hasInjectAnnotation(executableElement)) {
+ return Optional.of(membersInjectorNameForType(closestEnclosingTypeElement(element)));
+ }
+ if (isMethod(executableElement) && executableElement.hasAnnotation(TypeNames.PROVIDES)) {
+ return Optional.of(factoryNameForElement(executableElement));
+ }
+ }
+ return Optional.empty();
+ }
+
+ /** Returns the constructors in {@code type} that are annotated with {@link Inject}. */
+ public static ImmutableSet<XConstructorElement> injectedConstructors(XTypeElement type) {
+ return type.getConstructors().stream()
+ .filter(InjectionAnnotations::hasInjectAnnotation)
+ .collect(toImmutableSet());
+ }
+
/** Returns the constructors in {@code type} that are annotated with {@link Inject}. */
public static ImmutableSet<ExecutableElement> injectedConstructors(TypeElement type) {
return FluentIterable.from(constructorsIn(type.getEnclosedElements()))
- .filter(constructor -> isAnnotationPresent(constructor, Inject.class))
+ .filter(InjectionAnnotations::hasInjectAnnotation)
.toSet();
}
+ private static boolean hasQualifierAnnotation(AnnotationMirror annotation) {
+ return isAnyAnnotationPresent(
+ annotation.getAnnotationType().asElement(), TypeNames.QUALIFIER, TypeNames.QUALIFIER_JAVAX);
+ }
+
+ private static boolean hasScopeAnnotation(XAnnotation annotation) {
+ return annotation
+ .getType()
+ .getTypeElement()
+ .hasAnyAnnotation(TypeNames.SCOPE, TypeNames.SCOPE_JAVAX);
+ }
+
+ /** Returns true if the given element is annotated with {@link Inject}. */
+ public static boolean hasInjectAnnotation(XElement element) {
+ return element.hasAnyAnnotation(TypeNames.INJECT, TypeNames.INJECT_JAVAX);
+ }
+
+ /** Returns true if the given element is annotated with {@link Inject}. */
+ public static boolean hasInjectAnnotation(Element element) {
+ return isAnyAnnotationPresent(element, TypeNames.INJECT, TypeNames.INJECT_JAVAX);
+ }
+
+ /** Returns true if the given element is annotated with {@link Inject}. */
+ public static boolean hasInjectOrAssistedInjectAnnotation(XElement element) {
+ return element.hasAnyAnnotation(
+ TypeNames.INJECT, TypeNames.INJECT_JAVAX, TypeNames.ASSISTED_INJECT);
+ }
+
+ /** Returns true if the given element is annotated with {@link Inject}. */
+ public static boolean hasInjectOrAssistedInjectAnnotation(Element element) {
+ return isAnyAnnotationPresent(
+ element, TypeNames.INJECT, TypeNames.INJECT_JAVAX, TypeNames.ASSISTED_INJECT);
+ }
+
/**
* Gets the qualifiers annotation of a Kotlin Property. Finding these annotations involve finding
* the synthetic method for annotations as described by the Kotlin metadata or finding the
@@ -131,7 +439,7 @@ public final class InjectionAnnotations {
return ElementFilter.methodsIn(membersInjector.getEnclosedElements()).stream()
.filter(
method ->
- getAnnotationMirror(method, InjectedFieldSignature.class)
+ getAnnotationMirror(method, TypeNames.INJECTED_FIELD_SIGNATURE)
.map(annotation -> getStringValue(annotation, "value"))
.map(memberInjectedFieldSignature::equals)
// If a method is not an @InjectedFieldSignature method then filter it out
@@ -152,7 +460,13 @@ public final class InjectionAnnotations {
"No MembersInjector found for " + fieldElement.getEnclosingElement());
}
} else {
- return kotlinMetadataUtil.getSyntheticPropertyAnnotations(fieldElement, Qualifier.class);
+ return ImmutableSet.<AnnotationMirror>builder()
+ .addAll(
+ kotlinMetadataUtil.getSyntheticPropertyAnnotations(fieldElement, TypeNames.QUALIFIER))
+ .addAll(
+ kotlinMetadataUtil.getSyntheticPropertyAnnotations(
+ fieldElement, TypeNames.QUALIFIER_JAVAX))
+ .build();
}
}
}
diff --git a/java/dagger/internal/codegen/binding/InjectionSiteFactory.java b/java/dagger/internal/codegen/binding/InjectionSiteFactory.java
index 7a6f8d2f5..e620c058a 100644
--- a/java/dagger/internal/codegen/binding/InjectionSiteFactory.java
+++ b/java/dagger/internal/codegen/binding/InjectionSiteFactory.java
@@ -16,11 +16,15 @@
package dagger.internal.codegen.binding;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static com.google.auto.common.MoreTypes.asDeclared;
+import static com.google.common.base.Preconditions.checkArgument;
import static dagger.internal.codegen.langmodel.DaggerElements.DECLARATION_ORDER;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.STATIC;
+import androidx.room.compiler.processing.XType;
import com.google.auto.common.MoreElements;
import com.google.auto.common.MoreTypes;
import com.google.common.collect.ImmutableSortedSet;
@@ -63,6 +67,12 @@ final class InjectionSiteFactory {
}
/** Returns the injection sites for a type. */
+ ImmutableSortedSet<InjectionSite> getInjectionSites(XType type) {
+ checkArgument(isDeclared(type));
+ return getInjectionSites(asDeclared(toJavac(type)));
+ }
+
+ /** Returns the injection sites for a type. */
ImmutableSortedSet<InjectionSite> getInjectionSites(DeclaredType declaredType) {
Set<InjectionSite> injectionSites = new HashSet<>();
List<TypeElement> ancestors = new ArrayList<>();
@@ -138,7 +148,7 @@ final class InjectionSiteFactory {
}
private boolean shouldBeInjected(Element injectionSite) {
- return isAnnotationPresent(injectionSite, Inject.class)
+ return InjectionAnnotations.hasInjectAnnotation(injectionSite)
&& !injectionSite.getModifiers().contains(PRIVATE)
&& !injectionSite.getModifiers().contains(STATIC);
}
diff --git a/java/dagger/internal/codegen/binding/KeyFactory.java b/java/dagger/internal/codegen/binding/KeyFactory.java
index d9236665d..daae7d73b 100644
--- a/java/dagger/internal/codegen/binding/KeyFactory.java
+++ b/java/dagger/internal/codegen/binding/KeyFactory.java
@@ -16,24 +16,35 @@
package dagger.internal.codegen.binding;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.auto.common.MoreTypes.asExecutable;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static androidx.room.compiler.processing.compat.XConverters.toXProcessing;
import static com.google.auto.common.MoreTypes.isType;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.base.ProducerAnnotations.productionImplementationQualifier;
+import static dagger.internal.codegen.base.ProducerAnnotations.productionQualifier;
import static dagger.internal.codegen.base.RequestKinds.extractKeyType;
import static dagger.internal.codegen.binding.MapKeys.getMapKey;
import static dagger.internal.codegen.binding.MapKeys.mapKeyType;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.extension.Optionals.firstPresent;
+import static dagger.internal.codegen.langmodel.DaggerElements.isAnnotationPresent;
import static dagger.internal.codegen.langmodel.DaggerTypes.isFutureType;
import static dagger.internal.codegen.langmodel.DaggerTypes.unwrapType;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
import static java.util.Arrays.asList;
import static javax.lang.model.element.ElementKind.METHOD;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XMethodType;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.common.MoreTypes;
import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
import dagger.Binds;
import dagger.BindsOptionalOf;
import dagger.internal.codegen.base.ContributionType;
@@ -42,25 +53,19 @@ import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.OptionalType;
import dagger.internal.codegen.base.RequestKinds;
import dagger.internal.codegen.base.SetType;
-import dagger.internal.codegen.base.SimpleAnnotationMirror;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
-import dagger.model.Key.MultibindingContributionIdentifier;
-import dagger.model.RequestKind;
import dagger.multibindings.Multibinds;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.producers.Production;
-import dagger.producers.internal.ProductionImplementation;
-import dagger.producers.monitoring.ProductionComponentMonitor;
+import dagger.spi.model.DaggerAnnotation;
+import dagger.spi.model.DaggerType;
+import dagger.spi.model.Key;
+import dagger.spi.model.Key.MultibindingContributionIdentifier;
+import dagger.spi.model.RequestKind;
import java.util.Map;
import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.Executor;
import java.util.stream.Stream;
import javax.inject.Inject;
-import javax.inject.Provider;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
@@ -71,15 +76,20 @@ import javax.lang.model.type.TypeMirror;
/** A factory for {@link Key}s. */
public final class KeyFactory {
+ private final XProcessingEnv processingEnv;
private final DaggerTypes types;
private final DaggerElements elements;
private final InjectionAnnotations injectionAnnotations;
@Inject
KeyFactory(
- DaggerTypes types, DaggerElements elements, InjectionAnnotations injectionAnnotations) {
- this.types = checkNotNull(types);
- this.elements = checkNotNull(elements);
+ XProcessingEnv processingEnv,
+ DaggerTypes types,
+ DaggerElements elements,
+ InjectionAnnotations injectionAnnotations) {
+ this.processingEnv = processingEnv;
+ this.types = types;
+ this.elements = elements;
this.injectionAnnotations = injectionAnnotations;
}
@@ -88,95 +98,124 @@ public final class KeyFactory {
}
private DeclaredType setOf(TypeMirror elementType) {
- return types.getDeclaredType(elements.getTypeElement(Set.class), boxPrimitives(elementType));
+ return types.getDeclaredType(
+ elements.getTypeElement(TypeNames.SET), boxPrimitives(elementType));
+ }
+
+ private DeclaredType mapOf(XType keyType, XType valueType) {
+ return mapOf(toJavac(keyType), toJavac(valueType));
}
private DeclaredType mapOf(TypeMirror keyType, TypeMirror valueType) {
return types.getDeclaredType(
- elements.getTypeElement(Map.class), boxPrimitives(keyType), boxPrimitives(valueType));
+ elements.getTypeElement(TypeNames.MAP), boxPrimitives(keyType), boxPrimitives(valueType));
}
/** Returns {@code Map<KeyType, FrameworkType<ValueType>>}. */
private TypeMirror mapOfFrameworkType(
- TypeMirror keyType, TypeElement frameworkType, TypeMirror valueType) {
- return mapOf(keyType, types.getDeclaredType(frameworkType, boxPrimitives(valueType)));
+ XType keyType, ClassName frameworkClassName, XType valueType) {
+ return mapOfFrameworkType(toJavac(keyType), frameworkClassName, toJavac(valueType));
}
- Key forComponentMethod(ExecutableElement componentMethod) {
- checkArgument(componentMethod.getKind().equals(METHOD));
+ /** Returns {@code Map<KeyType, FrameworkType<ValueType>>}. */
+ private TypeMirror mapOfFrameworkType(
+ TypeMirror keyType, ClassName frameworkClassName, TypeMirror valueType) {
+ return mapOf(
+ keyType,
+ types.getDeclaredType(
+ elements.getTypeElement(frameworkClassName), boxPrimitives(valueType)));
+ }
+
+ Key forComponentMethod(XMethodElement componentMethod) {
return forMethod(componentMethod, componentMethod.getReturnType());
}
- Key forProductionComponentMethod(ExecutableElement componentMethod) {
- checkArgument(componentMethod.getKind().equals(METHOD));
- TypeMirror returnType = componentMethod.getReturnType();
- TypeMirror keyType =
- isFutureType(returnType)
- ? getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments())
- : returnType;
+ Key forProductionComponentMethod(XMethodElement componentMethod) {
+ XType returnType = componentMethod.getReturnType();
+ XType keyType =
+ isFutureType(returnType) ? getOnlyElement(returnType.getTypeArguments()) : returnType;
return forMethod(componentMethod, keyType);
}
Key forSubcomponentCreatorMethod(
- ExecutableElement subcomponentCreatorMethod, DeclaredType declaredContainer) {
- checkArgument(subcomponentCreatorMethod.getKind().equals(METHOD));
- ExecutableType resolvedMethod =
- asExecutable(types.asMemberOf(declaredContainer, subcomponentCreatorMethod));
- return Key.builder(resolvedMethod.getReturnType()).build();
+ XMethodElement subcomponentCreatorMethod, XType declaredContainer) {
+ checkArgument(isDeclared(declaredContainer));
+ XMethodType resolvedMethod = subcomponentCreatorMethod.asMemberOf(declaredContainer);
+ return Key.builder(DaggerType.from(resolvedMethod.getReturnType())).build();
+ }
+
+ public Key forSubcomponentCreator(XType creatorType) {
+ return Key.builder(DaggerType.from(creatorType)).build();
}
- public Key forSubcomponentCreator(TypeMirror creatorType) {
- return Key.builder(creatorType).build();
+ public Key forProvidesMethod(XMethodElement method, XTypeElement contributingModule) {
+ return forProvidesMethod(toJavac(method), toJavac(contributingModule));
}
public Key forProvidesMethod(ExecutableElement method, TypeElement contributingModule) {
- return forBindingMethod(
- method, contributingModule, Optional.of(elements.getTypeElement(Provider.class)));
+ return forBindingMethod(method, contributingModule, Optional.of(TypeNames.PROVIDER));
+ }
+
+ public Key forProducesMethod(XMethodElement method, XTypeElement contributingModule) {
+ return forProducesMethod(toJavac(method), toJavac(contributingModule));
}
public Key forProducesMethod(ExecutableElement method, TypeElement contributingModule) {
- return forBindingMethod(
- method, contributingModule, Optional.of(elements.getTypeElement(Producer.class)));
+ return forBindingMethod(method, contributingModule, Optional.of(TypeNames.PRODUCER));
+ }
+
+ /** Returns the key bound by a {@link Binds} method. */
+ Key forBindsMethod(XMethodElement method, XTypeElement contributingModule) {
+ return forBindsMethod(toJavac(method), toJavac(contributingModule));
}
/** Returns the key bound by a {@link Binds} method. */
Key forBindsMethod(ExecutableElement method, TypeElement contributingModule) {
- checkArgument(isAnnotationPresent(method, Binds.class));
+ checkArgument(isAnnotationPresent(method, TypeNames.BINDS));
return forBindingMethod(method, contributingModule, Optional.empty());
}
/** Returns the base key bound by a {@link BindsOptionalOf} method. */
- Key forBindsOptionalOfMethod(ExecutableElement method, TypeElement contributingModule) {
- checkArgument(isAnnotationPresent(method, BindsOptionalOf.class));
+ Key forBindsOptionalOfMethod(XMethodElement method, XTypeElement contributingModule) {
+ checkArgument(method.hasAnnotation(TypeNames.BINDS_OPTIONAL_OF));
return forBindingMethod(method, contributingModule, Optional.empty());
}
private Key forBindingMethod(
+ XMethodElement method,
+ XTypeElement contributingModule,
+ Optional<ClassName> frameworkClassName) {
+ return forBindingMethod(toJavac(method), toJavac(contributingModule), frameworkClassName);
+ }
+
+ private Key forBindingMethod(
ExecutableElement method,
TypeElement contributingModule,
- Optional<TypeElement> frameworkType) {
+ Optional<ClassName> frameworkClassName) {
checkArgument(method.getKind().equals(METHOD));
ExecutableType methodType =
MoreTypes.asExecutable(
types.asMemberOf(MoreTypes.asDeclared(contributingModule.asType()), method));
ContributionType contributionType = ContributionType.fromBindingElement(method);
TypeMirror returnType = methodType.getReturnType();
- if (frameworkType.isPresent()
- && frameworkType.get().equals(elements.getTypeElement(Producer.class))
+ if (frameworkClassName.isPresent()
+ && frameworkClassName.get().equals(TypeNames.PRODUCER)
&& isType(returnType)) {
if (isFutureType(methodType.getReturnType())) {
returnType = getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments());
} else if (contributionType.equals(ContributionType.SET_VALUES)
&& SetType.isSet(returnType)) {
- SetType setType = SetType.from(returnType);
+ SetType setType = SetType.from(toXProcessing(returnType, processingEnv));
if (isFutureType(setType.elementType())) {
returnType =
types.getDeclaredType(
- elements.getTypeElement(Set.class), unwrapType(setType.elementType()));
+ elements.getTypeElement(TypeNames.SET),
+ toJavac(unwrapType(setType.elementType())));
}
}
}
- TypeMirror keyType = bindingMethodKeyType(returnType, method, contributionType, frameworkType);
+ TypeMirror keyType =
+ bindingMethodKeyType(returnType, method, contributionType, frameworkClassName);
Key key = forMethod(method, keyType);
return contributionType.equals(ContributionType.UNIQUE)
? key
@@ -192,33 +231,48 @@ public final class KeyFactory {
* <p>The key's type is either {@code Set<T>} or {@code Map<K, Provider<V>>}. The latter works
* even for maps used by {@code Producer}s.
*/
- Key forMultibindsMethod(ExecutableType executableType, ExecutableElement method) {
- checkArgument(method.getKind().equals(METHOD), "%s must be a method", method);
- TypeMirror returnType = executableType.getReturnType();
+ Key forMultibindsMethod(XMethodElement method, XMethodType methodType) {
+ XType returnType = method.getReturnType();
TypeMirror keyType =
MapType.isMap(returnType)
? mapOfFrameworkType(
MapType.from(returnType).keyType(),
- elements.getTypeElement(Provider.class),
+ TypeNames.PROVIDER,
MapType.from(returnType).valueType())
- : returnType;
- return forMethod(method, keyType);
+ : toJavac(returnType);
+ return forMethod(toJavac(method), keyType);
}
private TypeMirror bindingMethodKeyType(
TypeMirror returnType,
ExecutableElement method,
ContributionType contributionType,
- Optional<TypeElement> frameworkType) {
+ Optional<ClassName> frameworkClassName) {
switch (contributionType) {
case UNIQUE:
return returnType;
case SET:
return setOf(returnType);
case MAP:
- TypeMirror mapKeyType = mapKeyType(getMapKey(method).get(), types);
- return frameworkType.isPresent()
- ? mapOfFrameworkType(mapKeyType, frameworkType.get(), returnType)
+ Optional<AnnotationMirror> mapKey = getMapKey(method);
+ // TODO(bcorso): We've added a special checkState here since a number of people have run
+ // into this particular case, but technically it shouldn't be necessary if we are properly
+ // doing superficial validation and deferring on unresolvable types. We should revisit
+ // whether this is necessary once we're able to properly defer this case.
+ checkState(
+ mapKey.isPresent(),
+ "Missing map key annotation for method: %s#%s. That method was annotated with: %s. If a"
+ + " map key annotation is included in that list, it means Dagger wasn't able to"
+ + " detect that it was a map key because the dependency is missing from the"
+ + " classpath of the current build. To fix, add a dependency for the map key to the"
+ + " current build. For more details, see"
+ + " https://github.com/google/dagger/issues/3133#issuecomment-1002790894.",
+ method.getEnclosingElement(),
+ method,
+ method.getAnnotationMirrors());
+ TypeMirror mapKeyType = mapKeyType(toXProcessing(mapKey.get(), processingEnv));
+ return frameworkClassName.isPresent()
+ ? mapOfFrameworkType(mapKeyType, frameworkClassName.get(), returnType)
: mapOf(mapKeyType, returnType);
case SET_VALUES:
// TODO(gak): do we want to allow people to use "covariant return" here?
@@ -235,47 +289,69 @@ public final class KeyFactory {
* from {@link DelegateDeclaration#key()} to {@code Map<K, FrameworkType<V>>}. If {@code
* delegateDeclaration} is not a map contribution, its key is returned.
*/
- Key forDelegateBinding(DelegateDeclaration delegateDeclaration, Class<?> frameworkType) {
+ Key forDelegateBinding(DelegateDeclaration delegateDeclaration, ClassName frameworkType) {
return delegateDeclaration.contributionType().equals(ContributionType.MAP)
? wrapMapValue(delegateDeclaration.key(), frameworkType)
: delegateDeclaration.key();
}
+ private Key forMethod(XMethodElement method, XType keyType) {
+ return forMethod(toJavac(method), toJavac(keyType));
+ }
+
private Key forMethod(ExecutableElement method, TypeMirror keyType) {
return forQualifiedType(injectionAnnotations.getQualifier(method), keyType);
}
+ public Key forInjectConstructorWithResolvedType(XType type) {
+ return forInjectConstructorWithResolvedType(toJavac(type));
+ }
+
public Key forInjectConstructorWithResolvedType(TypeMirror type) {
- return Key.builder(type).build();
+ return Key.builder(fromJava(type)).build();
}
// TODO(ronshapiro): Remove these conveniences which are simple wrappers around Key.Builder
- Key forType(TypeMirror type) {
- return Key.builder(type).build();
+ Key forType(XType type) {
+ return Key.builder(DaggerType.from(type)).build();
}
public Key forMembersInjectedType(TypeMirror type) {
- return Key.builder(type).build();
+ return forMembersInjectedType(toXProcessing(type, processingEnv));
+ }
+
+ public Key forMembersInjectedType(XType type) {
+ return Key.builder(DaggerType.from(type)).build();
}
Key forQualifiedType(Optional<AnnotationMirror> qualifier, TypeMirror type) {
- return Key.builder(boxPrimitives(type)).qualifier(qualifier).build();
+ return forQualifiedType(
+ qualifier.map(annotation -> toXProcessing(annotation, processingEnv)),
+ toXProcessing(type, processingEnv));
+ }
+
+ Key forQualifiedType(Optional<XAnnotation> qualifier, XType type) {
+ return Key.builder(DaggerType.from(type.boxed()))
+ .qualifier(qualifier.map(DaggerAnnotation::from))
+ .build();
}
public Key forProductionExecutor() {
- return Key.builder(elements.getTypeElement(Executor.class).asType())
- .qualifier(SimpleAnnotationMirror.of(elements.getTypeElement(Production.class)))
+ return Key.builder(fromJava(elements.getTypeElement(TypeNames.EXECUTOR).asType()))
+ .qualifier(fromJava(toJavac(productionQualifier(processingEnv))))
.build();
}
public Key forProductionImplementationExecutor() {
- return Key.builder(elements.getTypeElement(Executor.class).asType())
- .qualifier(SimpleAnnotationMirror.of(elements.getTypeElement(ProductionImplementation.class)))
+ return Key.builder(fromJava(elements.getTypeElement(TypeNames.EXECUTOR).asType()))
+ .qualifier(fromJava(toJavac(productionImplementationQualifier(processingEnv))))
.build();
}
public Key forProductionComponentMonitor() {
- return Key.builder(elements.getTypeElement(ProductionComponentMonitor.class).asType()).build();
+ return Key.builder(
+ fromJava(elements.getTypeElement(TypeNames.PRODUCTION_COMPONENT_MONITOR).asType()))
+ .build();
}
/**
@@ -298,8 +374,8 @@ public final class KeyFactory {
*/
Optional<Key> implicitMapProviderKeyFrom(Key possibleMapKey) {
return firstPresent(
- rewrapMapKey(possibleMapKey, Produced.class, Provider.class),
- wrapMapKey(possibleMapKey, Provider.class));
+ rewrapMapKey(possibleMapKey, TypeNames.PRODUCED, TypeNames.PROVIDER),
+ wrapMapKey(possibleMapKey, TypeNames.PROVIDER));
}
/**
@@ -310,8 +386,8 @@ public final class KeyFactory {
*/
Optional<Key> implicitMapProducerKeyFrom(Key possibleMapKey) {
return firstPresent(
- rewrapMapKey(possibleMapKey, Produced.class, Producer.class),
- wrapMapKey(possibleMapKey, Producer.class));
+ rewrapMapKey(possibleMapKey, TypeNames.PRODUCED, TypeNames.PRODUCER),
+ wrapMapKey(possibleMapKey, TypeNames.PRODUCER));
}
/**
@@ -325,10 +401,12 @@ public final class KeyFactory {
if (MapType.isMap(key)) {
MapType mapType = MapType.from(key);
if (!mapType.isRawType()) {
- for (Class<?> frameworkClass : asList(Provider.class, Producer.class, Produced.class)) {
+ for (ClassName frameworkClass :
+ asList(TypeNames.PROVIDER, TypeNames.PRODUCER, TypeNames.PRODUCED)) {
if (mapType.valuesAreTypeOf(frameworkClass)) {
return key.toBuilder()
- .type(mapOf(mapType.keyType(), mapType.unwrappedValueType(frameworkClass)))
+ .type(
+ fromJava(mapOf(mapType.keyType(), mapType.unwrappedValueType(frameworkClass))))
.build();
}
}
@@ -337,13 +415,11 @@ public final class KeyFactory {
return key;
}
- /**
- * Converts a {@link Key} of type {@code Map<K, V>} to {@code Map<K, Provider<V>>}.
- */
- private Key wrapMapValue(Key key, Class<?> newWrappingClass) {
+ /** Converts a {@link Key} of type {@code Map<K, V>} to {@code Map<K, Provider<V>>}. */
+ private Key wrapMapValue(Key key, ClassName newWrappingClassName) {
checkArgument(
- FrameworkTypes.isFrameworkType(elements.getTypeElement(newWrappingClass).asType()));
- return wrapMapKey(key, newWrappingClass).get();
+ FrameworkTypes.isFrameworkType(elements.getTypeElement(newWrappingClassName).asType()));
+ return wrapMapKey(key, newWrappingClassName).get();
}
/**
@@ -357,12 +433,12 @@ public final class KeyFactory {
* currentWrappingClass}
*/
public Optional<Key> rewrapMapKey(
- Key possibleMapKey, Class<?> currentWrappingClass, Class<?> newWrappingClass) {
- checkArgument(!currentWrappingClass.equals(newWrappingClass));
+ Key possibleMapKey, ClassName currentWrappingClassName, ClassName newWrappingClassName) {
+ checkArgument(!currentWrappingClassName.equals(newWrappingClassName));
if (MapType.isMap(possibleMapKey)) {
MapType mapType = MapType.from(possibleMapKey);
- if (!mapType.isRawType() && mapType.valuesAreTypeOf(currentWrappingClass)) {
- TypeElement wrappingElement = elements.getTypeElement(newWrappingClass);
+ if (!mapType.isRawType() && mapType.valuesAreTypeOf(currentWrappingClassName)) {
+ TypeElement wrappingElement = elements.getTypeElement(newWrappingClassName);
if (wrappingElement == null) {
// This target might not be compiled with Producers, so wrappingClass might not have an
// associated element.
@@ -370,9 +446,11 @@ public final class KeyFactory {
}
DeclaredType wrappedValueType =
types.getDeclaredType(
- wrappingElement, mapType.unwrappedValueType(currentWrappingClass));
+ wrappingElement, toJavac(mapType.unwrappedValueType(currentWrappingClassName)));
return Optional.of(
- possibleMapKey.toBuilder().type(mapOf(mapType.keyType(), wrappedValueType)).build());
+ possibleMapKey.toBuilder()
+ .type(fromJava(mapOf(toJavac(mapType.keyType()), wrappedValueType)))
+ .build());
}
}
return Optional.empty();
@@ -385,19 +463,22 @@ public final class KeyFactory {
*
* <p>Returns {@link Optional#empty()} if {@code WrappingClass} is not in the classpath.
*/
- private Optional<Key> wrapMapKey(Key possibleMapKey, Class<?> wrappingClass) {
+ private Optional<Key> wrapMapKey(Key possibleMapKey, ClassName wrappingClassName) {
if (MapType.isMap(possibleMapKey)) {
MapType mapType = MapType.from(possibleMapKey);
- if (!mapType.isRawType() && !mapType.valuesAreTypeOf(wrappingClass)) {
- TypeElement wrappingElement = elements.getTypeElement(wrappingClass);
+ if (!mapType.isRawType() && !mapType.valuesAreTypeOf(wrappingClassName)) {
+ TypeElement wrappingElement = elements.getTypeElement(wrappingClassName);
if (wrappingElement == null) {
// This target might not be compiled with Producers, so wrappingClass might not have an
// associated element.
return Optional.empty();
}
- DeclaredType wrappedValueType = types.getDeclaredType(wrappingElement, mapType.valueType());
+ DeclaredType wrappedValueType =
+ types.getDeclaredType(wrappingElement, toJavac(mapType.valueType()));
return Optional.of(
- possibleMapKey.toBuilder().type(mapOf(mapType.keyType(), wrappedValueType)).build());
+ possibleMapKey.toBuilder()
+ .type(fromJava(mapOf(toJavac(mapType.keyType()), wrappedValueType)))
+ .build());
}
}
return Optional.empty();
@@ -407,12 +488,14 @@ public final class KeyFactory {
* If {@code key}'s type is {@code Set<WrappingClass<Bar>>}, returns a key with type {@code Set
* <Bar>} with the same qualifier. Otherwise returns {@link Optional#empty()}.
*/
- Optional<Key> unwrapSetKey(Key key, Class<?> wrappingClass) {
+ Optional<Key> unwrapSetKey(Key key, ClassName wrappingClassName) {
if (SetType.isSet(key)) {
SetType setType = SetType.from(key);
- if (!setType.isRawType() && setType.elementsAreTypeOf(wrappingClass)) {
+ if (!setType.isRawType() && setType.elementsAreTypeOf(wrappingClassName)) {
return Optional.of(
- key.toBuilder().type(setOf(setType.unwrappedElementType(wrappingClass))).build());
+ key.toBuilder()
+ .type(fromJava(setOf(toJavac(setType.unwrappedElementType(wrappingClassName)))))
+ .build());
}
}
return Optional.empty();
@@ -428,7 +511,16 @@ public final class KeyFactory {
return Optional.empty();
}
- TypeMirror optionalValueType = OptionalType.from(key).valueType();
- return Optional.of(key.toBuilder().type(extractKeyType(optionalValueType)).build());
+ XType optionalValueType = OptionalType.from(key).valueType();
+ return Optional.of(
+ key.toBuilder().type(DaggerType.from(extractKeyType(optionalValueType))).build());
+ }
+
+ private DaggerAnnotation fromJava(AnnotationMirror annotation) {
+ return DaggerAnnotation.from(toXProcessing(annotation, processingEnv));
+ }
+
+ private DaggerType fromJava(TypeMirror typeMirror) {
+ return DaggerType.from(toXProcessing(typeMirror, processingEnv));
}
}
diff --git a/java/dagger/internal/codegen/binding/KeyVariableNamer.java b/java/dagger/internal/codegen/binding/KeyVariableNamer.java
index 9ac0efa83..fb42410f5 100644
--- a/java/dagger/internal/codegen/binding/KeyVariableNamer.java
+++ b/java/dagger/internal/codegen/binding/KeyVariableNamer.java
@@ -16,22 +16,21 @@
package dagger.internal.codegen.binding;
+import static androidx.room.compiler.processing.XTypeKt.isArray;
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_CAMEL;
import static dagger.internal.codegen.binding.SourceFiles.protectAgainstKeywords;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
+import static dagger.internal.codegen.xprocessing.XTypes.isPrimitive;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XArrayType;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
import java.util.Iterator;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.PrimitiveType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVisitor;
-import javax.lang.model.util.SimpleTypeVisitor8;
/**
* Suggests a variable name for a type based on a {@link Key}. Prefer {@link
@@ -47,45 +46,6 @@ public final class KeyVariableNamer {
"Subcomponent",
"Injector");
- private static final TypeVisitor<Void, StringBuilder> TYPE_NAMER =
- new SimpleTypeVisitor8<Void, StringBuilder>() {
- @Override
- public Void visitDeclared(DeclaredType declaredType, StringBuilder builder) {
- TypeElement element = MoreTypes.asTypeElement(declaredType);
- if (element.getNestingKind().isNested()
- && VERY_SIMPLE_NAMES.contains(element.getSimpleName().toString())) {
- builder.append(element.getEnclosingElement().getSimpleName());
- }
-
- builder.append(element.getSimpleName());
- Iterator<? extends TypeMirror> argumentIterator =
- declaredType.getTypeArguments().iterator();
- if (argumentIterator.hasNext()) {
- builder.append("Of");
- TypeMirror first = argumentIterator.next();
- first.accept(this, builder);
- while (argumentIterator.hasNext()) {
- builder.append("And");
- argumentIterator.next().accept(this, builder);
- }
- }
- return null;
- }
-
- @Override
- public Void visitPrimitive(PrimitiveType type, StringBuilder builder) {
- builder.append(LOWER_CAMEL.to(UPPER_CAMEL, type.toString()));
- return null;
- }
-
- @Override
- public Void visitArray(ArrayType type, StringBuilder builder) {
- type.getComponentType().accept(this, builder);
- builder.append("Array");
- return null;
- }
- };
-
private KeyVariableNamer() {}
public static String name(Key key) {
@@ -97,11 +57,36 @@ public final class KeyVariableNamer {
if (key.qualifier().isPresent()) {
// TODO(gak): Use a better name for fields with qualifiers with members.
- builder.append(key.qualifier().get().getAnnotationType().asElement().getSimpleName());
+ builder.append(key.qualifier().get().java().getAnnotationType().asElement().getSimpleName());
}
- key.type().accept(TYPE_NAMER, builder);
-
+ typeNamer(key.type().xprocessing(), builder);
return protectAgainstKeywords(UPPER_CAMEL.to(LOWER_CAMEL, builder.toString()));
}
+
+ private static void typeNamer(XType type, StringBuilder builder) {
+ if (isDeclared(type)) {
+ XTypeElement element = type.getTypeElement();
+ if (element.isNested() && VERY_SIMPLE_NAMES.contains(getSimpleName(element))) {
+ builder.append(getSimpleName(element.getEnclosingTypeElement()));
+ }
+
+ builder.append(getSimpleName(element));
+ Iterator<? extends XType> argumentIterator = type.getTypeArguments().iterator();
+ if (argumentIterator.hasNext()) {
+ builder.append("Of");
+ XType first = argumentIterator.next();
+ typeNamer(first, builder);
+ while (argumentIterator.hasNext()) {
+ builder.append("And");
+ typeNamer(argumentIterator.next(), builder);
+ }
+ }
+ } else if (isPrimitive(type)) {
+ builder.append(LOWER_CAMEL.to(UPPER_CAMEL, type.toString()));
+ } else if (isArray(type)) {
+ typeNamer(((XArrayType) type).getComponentType(), builder);
+ builder.append("Array");
+ }
+ }
}
diff --git a/java/dagger/internal/codegen/binding/LegacyBindingGraph.java b/java/dagger/internal/codegen/binding/LegacyBindingGraph.java
index 7c0040167..2f8d39a46 100644
--- a/java/dagger/internal/codegen/binding/LegacyBindingGraph.java
+++ b/java/dagger/internal/codegen/binding/LegacyBindingGraph.java
@@ -16,16 +16,16 @@
package dagger.internal.codegen.binding;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimaps;
-import dagger.model.Key;
-import dagger.model.RequestKind;
+import dagger.spi.model.Key;
+import dagger.spi.model.RequestKind;
import java.util.Collection;
import java.util.Map;
-import javax.lang.model.element.TypeElement;
// TODO(bcorso): Remove the LegacyBindingGraph after we've migrated to the new BindingGraph.
/** The canonical representation of a full-resolved graph. */
@@ -69,7 +69,7 @@ final class LegacyBindingGraph {
private static ImmutableList<LegacyBindingGraph> checkForDuplicates(
ImmutableList<LegacyBindingGraph> graphs) {
- Map<TypeElement, Collection<LegacyBindingGraph>> duplicateGraphs =
+ Map<XTypeElement, Collection<LegacyBindingGraph>> duplicateGraphs =
Maps.filterValues(
Multimaps.index(graphs, graph -> graph.componentDescriptor().typeElement()).asMap(),
overlapping -> overlapping.size() > 1);
diff --git a/java/dagger/internal/codegen/binding/MapKeys.java b/java/dagger/internal/codegen/binding/MapKeys.java
index ec7d79df1..7b2c4daf9 100644
--- a/java/dagger/internal/codegen/binding/MapKeys.java
+++ b/java/dagger/internal/codegen/binding/MapKeys.java
@@ -16,18 +16,29 @@
package dagger.internal.codegen.binding;
+import static androidx.room.compiler.processing.XTypeKt.isArray;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static androidx.room.compiler.processing.compat.XConverters.toXProcessing;
import static com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations;
import static com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults;
+import static com.google.auto.common.MoreElements.asExecutable;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
import static dagger.internal.codegen.base.MapKeyAccessibility.isMapKeyPubliclyAccessible;
import static dagger.internal.codegen.binding.SourceFiles.elementBasedClassName;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
+import static dagger.internal.codegen.xprocessing.XTypes.isPrimitive;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.common.MoreTypes;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
@@ -35,22 +46,18 @@ import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import dagger.MapKey;
+import dagger.internal.codegen.base.DaggerSuperficialValidation;
import dagger.internal.codegen.base.MapKeyAccessibility;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.xprocessing.XElements;
import java.util.NoSuchElementException;
import java.util.Optional;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.SimpleTypeVisitor6;
/** Methods for extracting {@link MapKey} annotations and key code blocks from binding elements. */
public final class MapKeys {
@@ -61,6 +68,16 @@ public final class MapKeys {
* @throws IllegalArgumentException if the element is annotated with more than one {@code MapKey}
* annotation
*/
+ static Optional<AnnotationMirror> getMapKey(XElement bindingElement) {
+ return getMapKey(toJavac(bindingElement));
+ }
+
+ /**
+ * If {@code bindingElement} is annotated with a {@link MapKey} annotation, returns it.
+ *
+ * @throws IllegalArgumentException if the element is annotated with more than one {@code MapKey}
+ * annotation
+ */
static Optional<AnnotationMirror> getMapKey(Element bindingElement) {
ImmutableSet<? extends AnnotationMirror> mapKeys = getMapKeys(bindingElement);
return mapKeys.isEmpty()
@@ -73,6 +90,11 @@ public final class MapKeys {
return getAnnotatedAnnotations(bindingElement, MapKey.class);
}
+ /** Returns all of the {@link MapKey} annotations that annotate {@code bindingElement}. */
+ public static ImmutableSet<XAnnotation> getMapKeys(XElement bindingElement) {
+ return XElements.getAnnotatedAnnotations(bindingElement, TypeNames.MAP_KEY);
+ }
+
/**
* Returns the annotation value if {@code mapKey}'s type is annotated with
* {@link MapKey @MapKey(unwrapValue = true)}.
@@ -89,10 +111,10 @@ public final class MapKeys {
: Optional.empty();
}
- static TypeMirror mapKeyType(AnnotationMirror mapKeyAnnotation, DaggerTypes types) {
- return unwrapValue(mapKeyAnnotation).isPresent()
- ? getUnwrappedMapKeyType(mapKeyAnnotation.getAnnotationType(), types)
- : mapKeyAnnotation.getAnnotationType();
+ static TypeMirror mapKeyType(XAnnotation mapKeyAnnotation) {
+ return unwrapValue(toJavac(mapKeyAnnotation)).isPresent()
+ ? toJavac(getUnwrappedMapKeyType(mapKeyAnnotation.getType()))
+ : toJavac(mapKeyAnnotation.getType());
}
/**
@@ -103,36 +125,24 @@ public final class MapKeys {
* has more than one member, or if its single member is an array
* @throws NoSuchElementException if the annotation has no members
*/
- public static DeclaredType getUnwrappedMapKeyType(
- final DeclaredType mapKeyAnnotationType, final DaggerTypes types) {
+ public static XType getUnwrappedMapKeyType(XType mapKeyAnnotationType) {
checkArgument(
- MoreTypes.asTypeElement(mapKeyAnnotationType).getKind() == ElementKind.ANNOTATION_TYPE,
+ isDeclared(mapKeyAnnotationType)
+ && mapKeyAnnotationType.getTypeElement().isAnnotationClass(),
"%s is not an annotation type",
mapKeyAnnotationType);
- final ExecutableElement onlyElement =
- getOnlyElement(methodsIn(mapKeyAnnotationType.asElement().getEnclosedElements()));
-
- SimpleTypeVisitor6<DeclaredType, Void> keyTypeElementVisitor =
- new SimpleTypeVisitor6<DeclaredType, Void>() {
-
- @Override
- public DeclaredType visitArray(ArrayType t, Void p) {
- throw new IllegalArgumentException(
- mapKeyAnnotationType + "." + onlyElement.getSimpleName() + " cannot be an array");
- }
-
- @Override
- public DeclaredType visitPrimitive(PrimitiveType t, Void p) {
- return MoreTypes.asDeclared(types.boxedClass(t).asType());
- }
-
- @Override
- public DeclaredType visitDeclared(DeclaredType t, Void p) {
- return t;
- }
- };
- return keyTypeElementVisitor.visit(onlyElement.getReturnType());
+ XMethodElement annotationValueMethod =
+ getOnlyElement(mapKeyAnnotationType.getTypeElement().getDeclaredMethods());
+ XType annotationValueType = annotationValueMethod.getReturnType();
+ if (isArray(annotationValueType)) {
+ throw new IllegalArgumentException(
+ mapKeyAnnotationType
+ + "."
+ + getSimpleName(annotationValueMethod)
+ + " cannot be an array");
+ }
+ return isPrimitive(annotationValueType) ? annotationValueType.boxed() : annotationValueType;
}
/**
@@ -145,11 +155,11 @@ public final class MapKeys {
* map} contribution.
*/
public static CodeBlock getMapKeyExpression(
- ContributionBinding binding, ClassName requestingClass, DaggerElements elements) {
+ ContributionBinding binding, ClassName requestingClass, XProcessingEnv processingEnv) {
AnnotationMirror mapKeyAnnotation = binding.mapKeyAnnotation().get();
return MapKeyAccessibility.isMapKeyAccessibleFrom(
mapKeyAnnotation, requestingClass.packageName())
- ? directMapKeyExpression(mapKeyAnnotation, elements)
+ ? directMapKeyExpression(mapKeyAnnotation, processingEnv)
: CodeBlock.of("$T.create()", mapKeyProxyClassName(binding));
}
@@ -166,19 +176,20 @@ public final class MapKeys {
* annotation
*/
private static CodeBlock directMapKeyExpression(
- AnnotationMirror mapKey, DaggerElements elements) {
+ AnnotationMirror mapKey, XProcessingEnv processingEnv) {
Optional<? extends AnnotationValue> unwrappedValue = unwrapValue(mapKey);
AnnotationExpression annotationExpression = new AnnotationExpression(mapKey);
if (MoreTypes.asTypeElement(mapKey.getAnnotationType())
.getQualifiedName()
.contentEquals("dagger.android.AndroidInjectionKey")) {
- TypeElement unwrappedType =
- elements.checkTypePresent((String) unwrappedValue.get().getValue());
+ XTypeElement unwrappedType =
+ DaggerSuperficialValidation.requireTypeElement(
+ processingEnv, (String) unwrappedValue.get().getValue());
return CodeBlock.of(
"$T.of($S)",
ClassName.get("dagger.android.internal", "AndroidInjectionKeys"),
- ClassName.get(unwrappedType).reflectionName());
+ unwrappedType.getClassName().reflectionName());
}
if (unwrappedValue.isPresent()) {
@@ -195,8 +206,7 @@ public final class MapKeys {
* DaggerTypes, DaggerElements)} is generated.
*/
public static ClassName mapKeyProxyClassName(ContributionBinding binding) {
- return elementBasedClassName(
- MoreElements.asExecutable(binding.bindingElement().get()), "MapKey");
+ return elementBasedClassName(asExecutable(toJavac(binding.bindingElement().get())), "MapKey");
}
/**
@@ -205,7 +215,7 @@ public final class MapKeys {
* accessible.
*/
public static Optional<MethodSpec> mapKeyFactoryMethod(
- ContributionBinding binding, DaggerTypes types, DaggerElements elements) {
+ ContributionBinding binding, XProcessingEnv processingEnv) {
return binding
.mapKeyAnnotation()
.filter(mapKey -> !isMapKeyPubliclyAccessible(mapKey))
@@ -213,8 +223,8 @@ public final class MapKeys {
mapKey ->
methodBuilder("create")
.addModifiers(PUBLIC, STATIC)
- .returns(TypeName.get(mapKeyType(mapKey, types)))
- .addStatement("return $L", directMapKeyExpression(mapKey, elements))
+ .returns(TypeName.get(mapKeyType(toXProcessing(mapKey, processingEnv))))
+ .addStatement("return $L", directMapKeyExpression(mapKey, processingEnv))
.build());
}
diff --git a/java/dagger/internal/codegen/binding/MembersInjectionBinding.java b/java/dagger/internal/codegen/binding/MembersInjectionBinding.java
index 3dd101657..695aea6a7 100644
--- a/java/dagger/internal/codegen/binding/MembersInjectionBinding.java
+++ b/java/dagger/internal/codegen/binding/MembersInjectionBinding.java
@@ -16,38 +16,49 @@
package dagger.internal.codegen.binding;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static java.util.stream.Collectors.toList;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
import java.util.Optional;
-import javax.inject.Inject;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
/** Represents the full members injection of a particular type. */
@AutoValue
public abstract class MembersInjectionBinding extends Binding {
+ static MembersInjectionBinding create(
+ Key key,
+ ImmutableSet<DependencyRequest> dependencies,
+ Optional<MembersInjectionBinding> unresolved,
+ ImmutableSortedSet<InjectionSite> injectionSites) {
+ return new AutoValue_MembersInjectionBinding(key, dependencies, unresolved, injectionSites);
+ }
+
@Override
- public final Optional<Element> bindingElement() {
+ public final Optional<XElement> bindingElement() {
return Optional.of(membersInjectedType());
}
- public abstract TypeElement membersInjectedType();
+ public final XTypeElement membersInjectedType() {
+ return key().type().xprocessing().getTypeElement();
+ }
@Override
public abstract Optional<MembersInjectionBinding> unresolved();
@Override
- public Optional<TypeElement> contributingModule() {
+ public Optional<XTypeElement> contributingModule() {
return Optional.empty();
}
@@ -73,11 +84,13 @@ public abstract class MembersInjectionBinding extends Binding {
* Returns {@code true} if any of this binding's injection sites are directly on the bound type.
*/
public boolean hasLocalInjectionSites() {
- return injectionSites()
- .stream()
+ return injectionSites().stream()
.anyMatch(
injectionSite ->
- injectionSite.element().getEnclosingElement().equals(membersInjectedType()));
+ injectionSite
+ .element()
+ .getEnclosingElement()
+ .equals(toJavac(membersInjectedType())));
}
@Override
@@ -119,7 +132,7 @@ public abstract class MembersInjectionBinding extends Binding {
.getEnclosingElement()
.getEnclosedElements()
.stream()
- .filter(element -> isAnnotationPresent(element, Inject.class))
+ .filter(InjectionAnnotations::hasInjectAnnotation)
.filter(element -> !element.getModifiers().contains(Modifier.PRIVATE))
.filter(element -> element.getSimpleName().equals(this.element().getSimpleName()))
.collect(toList())
diff --git a/java/dagger/internal/codegen/binding/MethodSignature.java b/java/dagger/internal/codegen/binding/MethodSignature.java
new file mode 100644
index 000000000..e982ca5a6
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/MethodSignature.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.binding;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+
+import androidx.room.compiler.processing.XMethodType;
+import androidx.room.compiler.processing.XType;
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
+
+/** A class that defines proper {@code equals} and {@code hashcode} for a method signature. */
+@AutoValue
+public abstract class MethodSignature {
+
+ abstract String name();
+
+ abstract ImmutableList<TypeName> parameterTypes();
+
+ abstract ImmutableList<TypeName> thrownTypes();
+
+ public static MethodSignature forComponentMethod(
+ ComponentMethodDescriptor componentMethod, XType componentType) {
+ XMethodType methodType = componentMethod.methodElement().asMemberOf(componentType);
+ return new AutoValue_MethodSignature(
+ getSimpleName(componentMethod.methodElement()),
+ toJavac(methodType).getParameterTypes().stream()
+ .map(TypeName::get)
+ .collect(toImmutableList()),
+ toJavac(methodType).getThrownTypes().stream()
+ .map(TypeName::get)
+ .collect(toImmutableList()));
+ }
+}
diff --git a/java/dagger/internal/codegen/binding/MethodSignatureFormatter.java b/java/dagger/internal/codegen/binding/MethodSignatureFormatter.java
index 97c680f4c..6a1a5a1af 100644
--- a/java/dagger/internal/codegen/binding/MethodSignatureFormatter.java
+++ b/java/dagger/internal/codegen/binding/MethodSignatureFormatter.java
@@ -16,54 +16,55 @@
package dagger.internal.codegen.binding;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static dagger.internal.codegen.base.DiagnosticFormatting.stripCommonTypePrefixes;
+import static dagger.internal.codegen.xprocessing.XElements.closestEnclosingTypeElement;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XExecutableParameterElement;
+import androidx.room.compiler.processing.XExecutableType;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XMethodType;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.XVariableElement;
import dagger.internal.codegen.base.Formatter;
-import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.xprocessing.XAnnotations;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
-/** Formats the signature of an {@link ExecutableElement} suitable for use in error messages. */
-public final class MethodSignatureFormatter extends Formatter<ExecutableElement> {
- private final DaggerTypes types;
+/** Formats the signature of an {@link XExecutableElement} suitable for use in error messages. */
+public final class MethodSignatureFormatter extends Formatter<XExecutableElement> {
private final InjectionAnnotations injectionAnnotations;
@Inject
- public MethodSignatureFormatter(DaggerTypes types, InjectionAnnotations injectionAnnotations) {
- this.types = types;
+ MethodSignatureFormatter(InjectionAnnotations injectionAnnotations) {
this.injectionAnnotations = injectionAnnotations;
}
/**
* A formatter that uses the type where the method is declared for the annotations and name of the
- * method, but the method's resolved type as a member of {@code declaredType} for the key.
+ * method, but the method's resolved type as a member of {@code type} for the key.
*/
- public Formatter<ExecutableElement> typedFormatter(DeclaredType declaredType) {
- return new Formatter<ExecutableElement>() {
+ public Formatter<XMethodElement> typedFormatter(XType type) {
+ checkArgument(isDeclared(type));
+ return new Formatter<XMethodElement>() {
@Override
- public String format(ExecutableElement method) {
+ public String format(XMethodElement method) {
return MethodSignatureFormatter.this.format(
- method,
- MoreTypes.asExecutable(types.asMemberOf(declaredType, method)),
- MoreElements.asType(method.getEnclosingElement()));
+ method, method.asMemberOf(type), closestEnclosingTypeElement(method));
}
};
}
@Override
- public String format(ExecutableElement method) {
+ public String format(XExecutableElement method) {
return format(method, Optional.empty());
}
@@ -71,23 +72,18 @@ public final class MethodSignatureFormatter extends Formatter<ExecutableElement>
* Formats an ExecutableElement as if it were contained within the container, if the container is
* present.
*/
- public String format(ExecutableElement method, Optional<DeclaredType> container) {
- TypeElement type = MoreElements.asType(method.getEnclosingElement());
- ExecutableType executableType = MoreTypes.asExecutable(method.asType());
- if (container.isPresent()) {
- executableType = MoreTypes.asExecutable(types.asMemberOf(container.get(), method));
- type = MoreElements.asType(container.get().asElement());
- }
- return format(method, executableType, type);
+ public String format(XExecutableElement method, Optional<XType> container) {
+ return container.isPresent()
+ ? format(method, method.asMemberOf(container.get()), container.get().getTypeElement())
+ : format(method, method.getExecutableType(), closestEnclosingTypeElement(method));
}
private String format(
- ExecutableElement method, ExecutableType methodType, TypeElement declaringType) {
+ XExecutableElement method, XExecutableType methodType, XTypeElement container) {
StringBuilder builder = new StringBuilder();
- // TODO(user): AnnotationMirror formatter.
- List<? extends AnnotationMirror> annotations = method.getAnnotationMirrors();
+ List<XAnnotation> annotations = method.getAllAnnotations();
if (!annotations.isEmpty()) {
- Iterator<? extends AnnotationMirror> annotationIterator = annotations.iterator();
+ Iterator<XAnnotation> annotationIterator = annotations.iterator();
for (int i = 0; annotationIterator.hasNext(); i++) {
if (i > 0) {
builder.append(' ');
@@ -96,20 +92,20 @@ public final class MethodSignatureFormatter extends Formatter<ExecutableElement>
}
builder.append(' ');
}
- if (method.getSimpleName().contentEquals("<init>")) {
- builder.append(declaringType.getQualifiedName());
+ if (getSimpleName(method).contentEquals("<init>")) {
+ builder.append(container.getQualifiedName());
} else {
builder
- .append(nameOfType(methodType.getReturnType()))
+ .append(nameOfType(((XMethodType) methodType).getReturnType()))
.append(' ')
- .append(declaringType.getQualifiedName())
+ .append(container.getQualifiedName())
.append('.')
- .append(method.getSimpleName());
+ .append(getSimpleName(method));
}
builder.append('(');
checkState(method.getParameters().size() == methodType.getParameterTypes().size());
- Iterator<? extends VariableElement> parameters = method.getParameters().iterator();
- Iterator<? extends TypeMirror> parameterTypes = methodType.getParameterTypes().iterator();
+ Iterator<XExecutableParameterElement> parameters = method.getParameters().iterator();
+ Iterator<XType> parameterTypes = methodType.getParameterTypes().iterator();
for (int i = 0; parameters.hasNext(); i++) {
if (i > 0) {
builder.append(", ");
@@ -120,21 +116,19 @@ public final class MethodSignatureFormatter extends Formatter<ExecutableElement>
return builder.toString();
}
- private void appendParameter(StringBuilder builder, VariableElement parameter, TypeMirror type) {
+ private void appendParameter(
+ StringBuilder builder, XVariableElement parameter, XType parameterType) {
injectionAnnotations
.getQualifier(parameter)
- .ifPresent(
- qualifier -> {
- builder.append(formatAnnotation(qualifier)).append(' ');
- });
- builder.append(nameOfType(type));
+ .ifPresent(qualifier -> builder.append(formatAnnotation(qualifier)).append(' '));
+ builder.append(nameOfType(parameterType));
}
- private static String nameOfType(TypeMirror type) {
+ private static String nameOfType(XType type) {
return stripCommonTypePrefixes(type.toString());
}
- private static String formatAnnotation(AnnotationMirror annotation) {
- return stripCommonTypePrefixes(annotation.toString());
+ private static String formatAnnotation(XAnnotation annotation) {
+ return stripCommonTypePrefixes(XAnnotations.toString(annotation));
}
}
diff --git a/java/dagger/internal/codegen/binding/ModuleDescriptor.java b/java/dagger/internal/codegen/binding/ModuleDescriptor.java
index c471f94b6..c6271f735 100644
--- a/java/dagger/internal/codegen/binding/ModuleDescriptor.java
+++ b/java/dagger/internal/codegen/binding/ModuleDescriptor.java
@@ -16,59 +16,57 @@
package dagger.internal.codegen.binding;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static androidx.room.compiler.processing.compat.XConverters.toXProcessing;
import static com.google.auto.common.MoreElements.asExecutable;
-import static com.google.auto.common.MoreElements.getPackage;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Verify.verify;
-import static com.google.common.collect.Iterables.transform;
+import static com.google.common.collect.Collections2.transform;
import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
import static dagger.internal.codegen.binding.SourceFiles.classFileName;
+import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.langmodel.DaggerElements.getMethodDescriptor;
-import static dagger.internal.codegen.langmodel.DaggerElements.isAnnotationPresent;
-import static javax.lang.model.type.TypeKind.DECLARED;
-import static javax.lang.model.type.TypeKind.NONE;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
import static javax.lang.model.util.ElementFilter.methodsIn;
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XElementKt;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableSet;
import com.google.common.graph.Traverser;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.TypeName;
import dagger.Binds;
import dagger.BindsOptionalOf;
import dagger.Module;
-import dagger.Provides;
import dagger.internal.codegen.base.ClearableCache;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
+import dagger.internal.codegen.base.DaggerSuperficialValidation;
+import dagger.internal.codegen.base.ModuleKind;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.model.Key;
-import dagger.multibindings.Multibinds;
-import dagger.producers.Produces;
+import dagger.internal.codegen.xprocessing.XElements;
+import dagger.spi.model.Key;
+import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
/** Contains metadata that describes a module. */
@AutoValue
public abstract class ModuleDescriptor {
- public abstract TypeElement moduleElement();
-
- abstract ImmutableSet<TypeElement> includedModules();
+ public abstract XTypeElement moduleElement();
public abstract ImmutableSet<ContributionBinding> bindings();
@@ -107,38 +105,41 @@ public abstract class ModuleDescriptor {
/** A {@link ModuleDescriptor} factory. */
@Singleton
public static final class Factory implements ClearableCache {
+ private final XProcessingEnv processingEnv;
private final DaggerElements elements;
- private final KotlinMetadataUtil metadataUtil;
private final BindingFactory bindingFactory;
private final MultibindingDeclaration.Factory multibindingDeclarationFactory;
private final DelegateDeclaration.Factory bindingDelegateDeclarationFactory;
private final SubcomponentDeclaration.Factory subcomponentDeclarationFactory;
private final OptionalBindingDeclaration.Factory optionalBindingDeclarationFactory;
- private final Map<TypeElement, ModuleDescriptor> cache = new HashMap<>();
+ private final DaggerSuperficialValidation superficialValidation;
+ private final Map<XTypeElement, ModuleDescriptor> cache = new HashMap<>();
@Inject
Factory(
+ XProcessingEnv processingEnv,
DaggerElements elements,
- KotlinMetadataUtil metadataUtil,
BindingFactory bindingFactory,
MultibindingDeclaration.Factory multibindingDeclarationFactory,
DelegateDeclaration.Factory bindingDelegateDeclarationFactory,
SubcomponentDeclaration.Factory subcomponentDeclarationFactory,
- OptionalBindingDeclaration.Factory optionalBindingDeclarationFactory) {
+ OptionalBindingDeclaration.Factory optionalBindingDeclarationFactory,
+ DaggerSuperficialValidation superficialValidation) {
+ this.processingEnv = processingEnv;
this.elements = elements;
- this.metadataUtil = metadataUtil;
this.bindingFactory = bindingFactory;
this.multibindingDeclarationFactory = multibindingDeclarationFactory;
this.bindingDelegateDeclarationFactory = bindingDelegateDeclarationFactory;
this.subcomponentDeclarationFactory = subcomponentDeclarationFactory;
this.optionalBindingDeclarationFactory = optionalBindingDeclarationFactory;
+ this.superficialValidation = superficialValidation;
}
- public ModuleDescriptor create(TypeElement moduleElement) {
+ public ModuleDescriptor create(XTypeElement moduleElement) {
return reentrantComputeIfAbsent(cache, moduleElement, this::createUncached);
}
- public ModuleDescriptor createUncached(TypeElement moduleElement) {
+ public ModuleDescriptor createUncached(XTypeElement moduleElement) {
ImmutableSet.Builder<ContributionBinding> bindings = ImmutableSet.builder();
ImmutableSet.Builder<DelegateDeclaration> delegates = ImmutableSet.builder();
ImmutableSet.Builder<MultibindingDeclaration> multibindingDeclarations =
@@ -146,33 +147,40 @@ public abstract class ModuleDescriptor {
ImmutableSet.Builder<OptionalBindingDeclaration> optionalDeclarations =
ImmutableSet.builder();
- for (ExecutableElement moduleMethod : methodsIn(elements.getAllMembers(moduleElement))) {
- if (isAnnotationPresent(moduleMethod, Provides.class)) {
- bindings.add(bindingFactory.providesMethodBinding(moduleMethod, moduleElement));
- }
- if (isAnnotationPresent(moduleMethod, Produces.class)) {
- bindings.add(bindingFactory.producesMethodBinding(moduleMethod, moduleElement));
- }
- if (isAnnotationPresent(moduleMethod, Binds.class)) {
- delegates.add(bindingDelegateDeclarationFactory.create(moduleMethod, moduleElement));
- }
- if (isAnnotationPresent(moduleMethod, Multibinds.class)) {
- multibindingDeclarations.add(
- multibindingDeclarationFactory.forMultibindsMethod(moduleMethod, moduleElement));
- }
- if (isAnnotationPresent(moduleMethod, BindsOptionalOf.class)) {
- optionalDeclarations.add(
- optionalBindingDeclarationFactory.forMethod(moduleMethod, moduleElement));
- }
- }
+ methodsIn(elements.getAllMembers(toJavac(moduleElement))).stream()
+ .map(method -> toXProcessing(method, processingEnv))
+ .filter(XElementKt::isMethod)
+ .map(XElements::asMethod)
+ .forEach(
+ moduleMethod -> {
+ if (moduleMethod.hasAnnotation(TypeNames.PROVIDES)) {
+ bindings.add(bindingFactory.providesMethodBinding(moduleMethod, moduleElement));
+ }
+ if (moduleMethod.hasAnnotation(TypeNames.PRODUCES)) {
+ bindings.add(bindingFactory.producesMethodBinding(moduleMethod, moduleElement));
+ }
+ if (moduleMethod.hasAnnotation(TypeNames.BINDS)) {
+ delegates.add(
+ bindingDelegateDeclarationFactory.create(moduleMethod, moduleElement));
+ }
+ if (moduleMethod.hasAnnotation(TypeNames.MULTIBINDS)) {
+ multibindingDeclarations.add(
+ multibindingDeclarationFactory.forMultibindsMethod(
+ moduleMethod, moduleElement));
+ }
+ if (moduleMethod.hasAnnotation(TypeNames.BINDS_OPTIONAL_OF)) {
+ optionalDeclarations.add(
+ optionalBindingDeclarationFactory.forMethod(moduleMethod, moduleElement));
+ }
+ });
- if (metadataUtil.hasEnclosedCompanionObject(moduleElement)) {
- collectCompanionModuleBindings(moduleElement, bindings);
- }
+ moduleElement.getEnclosedTypeElements().stream()
+ .filter(XTypeElement::isCompanionObject)
+ .collect(toOptional())
+ .ifPresent(companionModule -> collectCompanionModuleBindings(companionModule, bindings));
return new AutoValue_ModuleDescriptor(
moduleElement,
- ImmutableSet.copyOf(collectIncludedModules(new LinkedHashSet<>(), moduleElement)),
bindings.build(),
multibindingDeclarations.build(),
subcomponentDeclarationFactory.forModule(moduleElement),
@@ -182,17 +190,21 @@ public abstract class ModuleDescriptor {
}
private void collectCompanionModuleBindings(
- TypeElement moduleElement, ImmutableSet.Builder<ContributionBinding> bindings) {
- checkArgument(metadataUtil.hasEnclosedCompanionObject(moduleElement));
- TypeElement companionModule = metadataUtil.getEnclosedCompanionObject(moduleElement);
+ XTypeElement companionModule, ImmutableSet.Builder<ContributionBinding> bindings) {
ImmutableSet<String> bindingElementDescriptors =
bindings.build().stream()
- .map(binding -> getMethodDescriptor(asExecutable(binding.bindingElement().get())))
+ .map(
+ binding ->
+ getMethodDescriptor(asExecutable(toJavac(binding.bindingElement().get()))))
.collect(toImmutableSet());
- methodsIn(elements.getAllMembers(companionModule)).stream()
+
+ methodsIn(elements.getAllMembers(toJavac(companionModule))).stream()
+ .map(method -> toXProcessing(method, processingEnv))
+ .filter(XElementKt::isMethod)
+ .map(XElements::asMethod)
// Binding methods in companion objects with @JvmStatic are mirrored in the enclosing
// class, therefore we should ignore it or else it'll be a duplicate binding.
- .filter(method -> !KotlinMetadataUtil.isJvmStaticPresent(method))
+ .filter(method -> !method.hasAnnotation(TypeNames.JVM_STATIC))
// Fallback strategy for de-duping contributing bindings in the companion module with
// @JvmStatic by comparing descriptors. Contributing bindings are the only valid bindings
// a companion module can declare. See: https://youtrack.jetbrains.com/issue/KT-35104
@@ -200,35 +212,39 @@ public abstract class ModuleDescriptor {
.filter(method -> !bindingElementDescriptors.contains(getMethodDescriptor(method)))
.forEach(
method -> {
- if (isAnnotationPresent(method, Provides.class)) {
+ if (method.hasAnnotation(TypeNames.PROVIDES)) {
bindings.add(bindingFactory.providesMethodBinding(method, companionModule));
}
- if (isAnnotationPresent(method, Produces.class)) {
+ if (method.hasAnnotation(TypeNames.PRODUCES)) {
bindings.add(bindingFactory.producesMethodBinding(method, companionModule));
}
});
}
/** Returns all the modules transitively included by given modules, including the arguments. */
- ImmutableSet<ModuleDescriptor> transitiveModules(Iterable<TypeElement> modules) {
+ ImmutableSet<ModuleDescriptor> transitiveModules(Collection<XTypeElement> modules) {
+ // Traverse as a graph to automatically handle modules with cyclic includes.
return ImmutableSet.copyOf(
Traverser.forGraph(
- (ModuleDescriptor module) -> transform(module.includedModules(), this::create))
+ (ModuleDescriptor module) -> transform(includedModules(module), this::create))
.depthFirstPreOrder(transform(modules, this::create)));
}
- @CanIgnoreReturnValue
- private Set<TypeElement> collectIncludedModules(
- Set<TypeElement> includedModules, TypeElement moduleElement) {
- TypeMirror superclass = moduleElement.getSuperclass();
- if (!superclass.getKind().equals(NONE)) {
- verify(superclass.getKind().equals(DECLARED));
- TypeElement superclassElement = MoreTypes.asTypeElement(superclass);
- if (!superclassElement.getQualifiedName().contentEquals(Object.class.getCanonicalName())) {
- collectIncludedModules(includedModules, superclassElement);
+ private ImmutableSet<XTypeElement> includedModules(ModuleDescriptor moduleDescriptor) {
+ return ImmutableSet.copyOf(
+ collectIncludedModules(new LinkedHashSet<>(), moduleDescriptor.moduleElement()));
+ }
+
+ private Set<XTypeElement> collectIncludedModules(
+ Set<XTypeElement> includedModules, XTypeElement moduleElement) {
+ XType superclass = moduleElement.getSuperType();
+ if (superclass != null) {
+ verify(isDeclared(superclass));
+ if (!TypeName.OBJECT.equals(superclass.getTypeName())) {
+ collectIncludedModules(includedModules, superclass.getTypeElement());
}
}
- moduleAnnotation(moduleElement)
+ moduleAnnotation(moduleElement, superficialValidation)
.ifPresent(
moduleAnnotation -> {
includedModules.addAll(moduleAnnotation.includes());
@@ -237,26 +253,31 @@ public abstract class ModuleDescriptor {
return includedModules;
}
+ private static final ClassName CONTRIBUTES_ANDROID_INJECTOR =
+ ClassName.get("dagger.android", "ContributesAndroidInjector");
+
// @ContributesAndroidInjector generates a module that is implicitly included in the enclosing
// module
- private ImmutableSet<TypeElement> implicitlyIncludedModules(TypeElement moduleElement) {
- TypeElement contributesAndroidInjector =
- elements.getTypeElement("dagger.android.ContributesAndroidInjector");
- if (contributesAndroidInjector == null) {
+ private ImmutableSet<XTypeElement> implicitlyIncludedModules(XTypeElement module) {
+ if (processingEnv.findTypeElement(CONTRIBUTES_ANDROID_INJECTOR) == null) {
return ImmutableSet.of();
}
- return methodsIn(moduleElement.getEnclosedElements()).stream()
- .filter(method -> isAnnotationPresent(method, contributesAndroidInjector.asType()))
- .map(method -> elements.checkTypePresent(implicitlyIncludedModuleName(method)))
+ return module.getDeclaredMethods().stream()
+ .filter(method -> method.hasAnnotation(CONTRIBUTES_ANDROID_INJECTOR))
+ .map(
+ method ->
+ DaggerSuperficialValidation.requireTypeElement(
+ processingEnv, implicitlyIncludedModuleName(module, method)))
.collect(toImmutableSet());
}
- private String implicitlyIncludedModuleName(ExecutableElement method) {
- return getPackage(method).getQualifiedName()
- + "."
- + classFileName(ClassName.get(MoreElements.asType(method.getEnclosingElement())))
- + "_"
- + LOWER_CAMEL.to(UPPER_CAMEL, method.getSimpleName().toString());
+ private ClassName implicitlyIncludedModuleName(XTypeElement module, XMethodElement method) {
+ return ClassName.get(
+ module.getPackageName(),
+ String.format(
+ "%s_%s",
+ classFileName(module.getClassName()),
+ LOWER_CAMEL.to(UPPER_CAMEL, getSimpleName(method))));
}
@Override
diff --git a/java/dagger/internal/codegen/binding/MultibindingDeclaration.java b/java/dagger/internal/codegen/binding/MultibindingDeclaration.java
index f1d3f8d75..746feaf5c 100644
--- a/java/dagger/internal/codegen/binding/MultibindingDeclaration.java
+++ b/java/dagger/internal/codegen/binding/MultibindingDeclaration.java
@@ -16,28 +16,25 @@
package dagger.internal.codegen.binding;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
import static com.google.common.base.Preconditions.checkArgument;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XMethodType;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import dagger.internal.codegen.base.ContributionType;
import dagger.internal.codegen.base.ContributionType.HasContributionType;
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.SetType;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.multibindings.Multibinds;
+import dagger.spi.model.Key;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
/**
* A declaration that a multibinding with a certain key is available to be injected in a component
@@ -71,43 +68,36 @@ public abstract class MultibindingDeclaration extends BindingDeclaration
/** A factory for {@link MultibindingDeclaration}s. */
public static final class Factory {
- private final DaggerTypes types;
private final KeyFactory keyFactory;
@Inject
- Factory(DaggerTypes types, KeyFactory keyFactory) {
- this.types = types;
+ Factory(KeyFactory keyFactory) {
this.keyFactory = keyFactory;
}
/** A multibinding declaration for a {@link Multibinds @Multibinds} method. */
MultibindingDeclaration forMultibindsMethod(
- ExecutableElement moduleMethod, TypeElement moduleElement) {
- checkArgument(isAnnotationPresent(moduleMethod, Multibinds.class));
+ XMethodElement moduleMethod, XTypeElement moduleElement) {
+ checkArgument(moduleMethod.hasAnnotation(TypeNames.MULTIBINDS));
return forDeclaredMethod(
- moduleMethod,
- MoreTypes.asExecutable(
- types.asMemberOf(MoreTypes.asDeclared(moduleElement.asType()), moduleMethod)),
- moduleElement);
+ moduleMethod, moduleMethod.asMemberOf(moduleElement.getType()), moduleElement);
}
private MultibindingDeclaration forDeclaredMethod(
- ExecutableElement method,
- ExecutableType methodType,
- TypeElement contributingType) {
- TypeMirror returnType = methodType.getReturnType();
+ XMethodElement method, XMethodType methodType, XTypeElement contributingType) {
+ XType returnType = methodType.getReturnType();
checkArgument(
SetType.isSet(returnType) || MapType.isMap(returnType),
"%s must return a set or map",
method);
return new AutoValue_MultibindingDeclaration(
- Optional.<Element>of(method),
+ Optional.of(method),
Optional.of(contributingType),
- keyFactory.forMultibindsMethod(methodType, method),
+ keyFactory.forMultibindsMethod(method, methodType),
contributionType(returnType));
}
- private ContributionType contributionType(TypeMirror returnType) {
+ private ContributionType contributionType(XType returnType) {
if (MapType.isMap(returnType)) {
return ContributionType.MAP;
} else if (SetType.isSet(returnType)) {
diff --git a/java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java b/java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java
index d7ba7bcfc..d708c0ac2 100644
--- a/java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java
+++ b/java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java
@@ -16,18 +16,17 @@
package dagger.internal.codegen.binding;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
import static com.google.common.base.Preconditions.checkArgument;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import dagger.BindsOptionalOf;
-import dagger.model.Key;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.spi.model.Key;
import java.util.Optional;
import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
/** A {@link BindsOptionalOf} declaration. */
@AutoValue
@@ -57,10 +56,10 @@ abstract class OptionalBindingDeclaration extends BindingDeclaration {
this.keyFactory = keyFactory;
}
- OptionalBindingDeclaration forMethod(ExecutableElement method, TypeElement contributingModule) {
- checkArgument(isAnnotationPresent(method, BindsOptionalOf.class));
+ OptionalBindingDeclaration forMethod(XMethodElement method, XTypeElement contributingModule) {
+ checkArgument(method.hasAnnotation(TypeNames.BINDS_OPTIONAL_OF));
return new AutoValue_OptionalBindingDeclaration(
- Optional.<Element>of(method),
+ Optional.of(method),
Optional.of(contributingModule),
keyFactory.forBindsOptionalOfMethod(method, contributingModule));
}
diff --git a/java/dagger/internal/codegen/binding/ProductionBinding.java b/java/dagger/internal/codegen/binding/ProductionBinding.java
index ad85a68d0..b803089e8 100644
--- a/java/dagger/internal/codegen/binding/ProductionBinding.java
+++ b/java/dagger/internal/codegen/binding/ProductionBinding.java
@@ -19,6 +19,8 @@ package dagger.internal.codegen.binding;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.langmodel.DaggerTypes.isFutureType;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableList;
@@ -26,12 +28,10 @@ import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import dagger.internal.codegen.base.ContributionType;
import dagger.internal.codegen.base.SetType;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
import java.util.Optional;
import java.util.stream.Stream;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.TypeMirror;
/** A value object representing the mechanism by which a {@link Key} can be produced. */
@AutoValue
@@ -63,7 +63,7 @@ public abstract class ProductionBinding extends ContributionBinding {
SET_OF_FUTURE;
/** Returns the kind of object a {@code @Produces}-annotated method returns. */
- public static ProductionKind fromProducesMethod(ExecutableElement producesMethod) {
+ public static ProductionKind fromProducesMethod(XMethodElement producesMethod) {
if (isFutureType(producesMethod.getReturnType())) {
return FUTURE;
} else if (ContributionType.fromBindingElement(producesMethod)
@@ -84,7 +84,7 @@ public abstract class ProductionBinding extends ContributionBinding {
public abstract Optional<ProductionKind> productionKind();
/** Returns the list of types in the throws clause of the method. */
- public abstract ImmutableList<? extends TypeMirror> thrownTypes();
+ public abstract ImmutableList<XType> thrownTypes();
/**
* If this production requires an executor, this will be the corresponding request. All
@@ -110,7 +110,7 @@ public abstract class ProductionBinding extends ContributionBinding {
public static Builder builder() {
return new AutoValue_ProductionBinding.Builder()
.explicitDependencies(ImmutableList.<DependencyRequest>of())
- .thrownTypes(ImmutableList.<TypeMirror>of());
+ .thrownTypes(ImmutableList.<XType>of());
}
@Override
@@ -142,7 +142,7 @@ public abstract class ProductionBinding extends ContributionBinding {
@Override
public abstract Builder unresolved(ProductionBinding unresolved);
- abstract Builder thrownTypes(Iterable<? extends TypeMirror> thrownTypes);
+ abstract Builder thrownTypes(Iterable<XType> thrownTypes);
abstract Builder executorRequest(DependencyRequest executorRequest);
diff --git a/java/dagger/internal/codegen/binding/ProvisionBinding.java b/java/dagger/internal/codegen/binding/ProvisionBinding.java
index c917dd6b5..2447e30de 100644
--- a/java/dagger/internal/codegen/binding/ProvisionBinding.java
+++ b/java/dagger/internal/codegen/binding/ProvisionBinding.java
@@ -17,8 +17,8 @@
package dagger.internal.codegen.binding;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.model.BindingKind.COMPONENT_PROVISION;
-import static dagger.model.BindingKind.PROVISION;
+import static dagger.spi.model.BindingKind.COMPONENT_PROVISION;
+import static dagger.spi.model.BindingKind.PROVISION;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
@@ -27,10 +27,10 @@ import com.google.common.collect.ImmutableSortedSet;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.Scope;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
+import dagger.spi.model.Scope;
import java.util.Optional;
/** A value object representing the mechanism by which a {@link Key} can be provided. */
diff --git a/java/dagger/internal/codegen/binding/ResolvedBindings.java b/java/dagger/internal/codegen/binding/ResolvedBindings.java
index 74301feda..2ef9bd63f 100644
--- a/java/dagger/internal/codegen/binding/ResolvedBindings.java
+++ b/java/dagger/internal/codegen/binding/ResolvedBindings.java
@@ -16,6 +16,7 @@
package dagger.internal.codegen.binding;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Iterables.getOnlyElement;
@@ -26,7 +27,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap;
-import dagger.model.Key;
+import dagger.spi.model.Key;
import javax.lang.model.element.TypeElement;
/**
@@ -99,7 +100,7 @@ abstract class ResolvedBindings {
/** All bindings for {@link #key()} that are owned by a component. */
ImmutableSet<? extends Binding> bindingsOwnedBy(ComponentDescriptor component) {
- return allBindings().get(component.typeElement());
+ return allBindings().get(toJavac(component.typeElement()));
}
/**
@@ -151,7 +152,7 @@ abstract class ResolvedBindings {
return new AutoValue_ResolvedBindings(
key,
ImmutableSetMultimap.of(),
- ImmutableMap.of(owningComponent.typeElement(), ownedMembersInjectionBinding),
+ ImmutableMap.of(toJavac(owningComponent.typeElement()), ownedMembersInjectionBinding),
ImmutableSet.of(),
ImmutableSet.of(),
ImmutableSet.of());
diff --git a/java/dagger/internal/codegen/binding/SourceFiles.java b/java/dagger/internal/codegen/binding/SourceFiles.java
index 3b6d9d9d1..84bdd2ba5 100644
--- a/java/dagger/internal/codegen/binding/SourceFiles.java
+++ b/java/dagger/internal/codegen/binding/SourceFiles.java
@@ -16,6 +16,8 @@
package dagger.internal.codegen.binding;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static com.google.auto.common.MoreElements.asType;
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_CAMEL;
import static com.google.common.base.Preconditions.checkArgument;
@@ -28,16 +30,21 @@ import static dagger.internal.codegen.javapoet.TypeNames.MAP_OF_PRODUCED_PRODUCE
import static dagger.internal.codegen.javapoet.TypeNames.MAP_OF_PRODUCER_PRODUCER;
import static dagger.internal.codegen.javapoet.TypeNames.MAP_PRODUCER;
import static dagger.internal.codegen.javapoet.TypeNames.MAP_PROVIDER_FACTORY;
+import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER;
+import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER;
import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER_OF_LAZY;
import static dagger.internal.codegen.javapoet.TypeNames.SET_FACTORY;
import static dagger.internal.codegen.javapoet.TypeNames.SET_OF_PRODUCED_PRODUCER;
import static dagger.internal.codegen.javapoet.TypeNames.SET_PRODUCER;
-import static dagger.model.BindingKind.ASSISTED_INJECTION;
-import static dagger.model.BindingKind.INJECTION;
-import static dagger.model.BindingKind.MULTIBOUND_MAP;
-import static dagger.model.BindingKind.MULTIBOUND_SET;
+import static dagger.internal.codegen.xprocessing.XElements.asExecutable;
+import static dagger.spi.model.BindingKind.ASSISTED_INJECTION;
+import static dagger.spi.model.BindingKind.INJECTION;
+import static dagger.spi.model.BindingKind.MULTIBOUND_MAP;
+import static dagger.spi.model.BindingKind.MULTIBOUND_SET;
import static javax.lang.model.SourceVersion.isName;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.common.MoreElements;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
@@ -51,17 +58,12 @@ import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeVariableName;
-import dagger.internal.SetFactory;
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.SetType;
-import dagger.model.DependencyRequest;
-import dagger.model.RequestKind;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.producers.internal.SetOfProducedProducer;
-import dagger.producers.internal.SetProducer;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.RequestKind;
import java.util.List;
-import javax.inject.Provider;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
@@ -97,9 +99,8 @@ public class SourceFiles {
binding.dependencies(),
dependency ->
FrameworkField.create(
- ClassName.get(
- frameworkTypeMapper.getFrameworkType(dependency.kind()).frameworkClass()),
- TypeName.get(dependency.key().type()),
+ frameworkTypeMapper.getFrameworkType(dependency.kind()).frameworkClassName(),
+ TypeName.get(dependency.key().type().java()),
DependencyVariableNamer.name(dependency)));
}
@@ -144,11 +145,10 @@ public class SourceFiles {
case INJECTION:
case PROVISION:
case PRODUCTION:
- return elementBasedClassName(
- MoreElements.asExecutable(binding.bindingElement().get()), "Factory");
+ return factoryNameForElement(asExecutable(binding.bindingElement().get()));
case ASSISTED_FACTORY:
- return siblingClassName(MoreElements.asType(binding.bindingElement().get()), "_Impl");
+ return siblingClassName(asType(toJavac(binding.bindingElement().get())), "_Impl");
default:
throw new AssertionError();
@@ -162,6 +162,18 @@ public class SourceFiles {
}
/**
+ * Returns the generated factory name for the given element.
+ *
+ * <p>This method is useful during validation before a {@link Binding} can be created. If a
+ * binding already exists for the given element, prefer to call {@link
+ * #generatedClassNameForBinding(Binding)} instead since this method does not validate that the
+ * given element is actually a binding element or not.
+ */
+ public static ClassName factoryNameForElement(XExecutableElement element) {
+ return elementBasedClassName(toJavac(element), "Factory");
+ }
+
+ /**
* Calculates an appropriate {@link ClassName} for a generated class that is based on {@code
* element}, appending {@code suffix} at the end.
*
@@ -188,8 +200,12 @@ public class SourceFiles {
: ParameterizedTypeName.get(className, Iterables.toArray(typeParameters, TypeName.class));
}
+ public static ClassName membersInjectorNameForType(XTypeElement typeElement) {
+ return membersInjectorNameForType(toJavac(typeElement));
+ }
+
public static ClassName membersInjectorNameForType(TypeElement typeElement) {
- return siblingClassName(typeElement, "_MembersInjector");
+ return siblingClassName(typeElement, "_MembersInjector");
}
public static String memberInjectedFieldSignatureForVariable(VariableElement variableElement) {
@@ -202,8 +218,8 @@ public class SourceFiles {
return CLASS_FILE_NAME_JOINER.join(className.simpleNames());
}
- public static ClassName generatedMonitoringModuleName(TypeElement componentElement) {
- return siblingClassName(componentElement, "_MonitoringModule");
+ public static ClassName generatedMonitoringModuleName(XTypeElement componentElement) {
+ return siblingClassName(toJavac(componentElement), "_MonitoringModule");
}
// TODO(ronshapiro): when JavaPoet migration is complete, replace the duplicated code
@@ -217,9 +233,10 @@ public class SourceFiles {
* The {@link java.util.Set} factory class name appropriate for set bindings.
*
* <ul>
- * <li>{@link SetFactory} for provision bindings.
- * <li>{@link SetProducer} for production bindings for {@code Set<T>}.
- * <li>{@link SetOfProducedProducer} for production bindings for {@code Set<Produced<T>>}.
+ * <li>{@link dagger.producers.internal.SetFactory} for provision bindings.
+ * <li>{@link dagger.producers.internal.SetProducer} for production bindings for {@code Set<T>}.
+ * <li>{@link dagger.producers.internal.SetOfProducedProducer} for production bindings for
+ * {@code Set<Produced<T>>}.
* </ul>
*/
public static ClassName setFactoryClassName(ContributionBinding binding) {
@@ -228,7 +245,9 @@ public class SourceFiles {
return SET_FACTORY;
} else {
SetType setType = SetType.from(binding.key());
- return setType.elementsAreTypeOf(Produced.class) ? SET_OF_PRODUCED_PRODUCER : SET_PRODUCER;
+ return setType.elementsAreTypeOf(TypeNames.PRODUCED)
+ ? SET_OF_PRODUCED_PRODUCER
+ : SET_PRODUCER;
}
}
@@ -238,10 +257,10 @@ public class SourceFiles {
MapType mapType = MapType.from(binding.key());
switch (binding.bindingType()) {
case PROVISION:
- return mapType.valuesAreTypeOf(Provider.class) ? MAP_PROVIDER_FACTORY : MAP_FACTORY;
+ return mapType.valuesAreTypeOf(PROVIDER) ? MAP_PROVIDER_FACTORY : MAP_FACTORY;
case PRODUCTION:
return mapType.valuesAreFrameworkType()
- ? mapType.valuesAreTypeOf(Producer.class)
+ ? mapType.valuesAreTypeOf(PRODUCER)
? MAP_OF_PRODUCER_PRODUCER
: MAP_OF_PRODUCED_PRODUCER
: MAP_PRODUCER;
@@ -261,7 +280,7 @@ public class SourceFiles {
}
}
List<? extends TypeParameterElement> typeParameters =
- binding.bindingTypeElement().get().getTypeParameters();
+ toJavac(binding.bindingTypeElement().get()).getTypeParameters();
return typeParameters.stream().map(TypeVariableName::get).collect(toImmutableList());
}
@@ -272,7 +291,16 @@ public class SourceFiles {
*/
// TODO(gak): maybe this should be a function of TypeMirrors instead of Elements?
public static String simpleVariableName(TypeElement typeElement) {
- String candidateName = UPPER_CAMEL.to(LOWER_CAMEL, typeElement.getSimpleName().toString());
+ return simpleVariableName(ClassName.get(typeElement));
+ }
+
+ /**
+ * Returns a name to be used for variables of the given {@linkplain ClassName}. Prefer
+ * semantically meaningful variable names, but if none can be derived, this will produce something
+ * readable.
+ */
+ public static String simpleVariableName(ClassName className) {
+ String candidateName = UPPER_CAMEL.to(LOWER_CAMEL, className.simpleName());
String variableName = protectAgainstKeywords(candidateName);
verify(isName(variableName), "'%s' was expected to be a valid variable name");
return variableName;
diff --git a/java/dagger/internal/codegen/binding/SubcomponentCreatorBindingEdgeImpl.java b/java/dagger/internal/codegen/binding/SubcomponentCreatorBindingEdgeImpl.java
index 93e79b5b9..5998b98e8 100644
--- a/java/dagger/internal/codegen/binding/SubcomponentCreatorBindingEdgeImpl.java
+++ b/java/dagger/internal/codegen/binding/SubcomponentCreatorBindingEdgeImpl.java
@@ -22,12 +22,12 @@ import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static java.util.stream.Collectors.joining;
import com.google.common.collect.ImmutableSet;
-import dagger.model.BindingGraph.SubcomponentCreatorBindingEdge;
-import javax.lang.model.element.TypeElement;
+import com.squareup.javapoet.ClassName;
+import dagger.spi.model.BindingGraph.SubcomponentCreatorBindingEdge;
+import dagger.spi.model.DaggerTypeElement;
/** An implementation of {@link SubcomponentCreatorBindingEdge}. */
public final class SubcomponentCreatorBindingEdgeImpl implements SubcomponentCreatorBindingEdge {
-
private final ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations;
SubcomponentCreatorBindingEdgeImpl(
@@ -36,10 +36,11 @@ public final class SubcomponentCreatorBindingEdgeImpl implements SubcomponentCre
}
@Override
- public ImmutableSet<TypeElement> declaringModules() {
+ public ImmutableSet<DaggerTypeElement> declaringModules() {
return subcomponentDeclarations.stream()
.map(SubcomponentDeclaration::contributingModule)
.flatMap(presentValues())
+ .map(DaggerTypeElement::from)
.collect(toImmutableSet());
}
@@ -47,9 +48,10 @@ public final class SubcomponentCreatorBindingEdgeImpl implements SubcomponentCre
public String toString() {
return "subcomponent declared by "
+ (subcomponentDeclarations.size() == 1
- ? getOnlyElement(declaringModules()).getQualifiedName()
+ ? getOnlyElement(declaringModules()).className().canonicalName()
: declaringModules().stream()
- .map(TypeElement::getQualifiedName)
+ .map(DaggerTypeElement::className)
+ .map(ClassName::canonicalName)
.collect(joining(", ", "{", "}")));
}
}
diff --git a/java/dagger/internal/codegen/binding/SubcomponentDeclaration.java b/java/dagger/internal/codegen/binding/SubcomponentDeclaration.java
index 4f1f3efd2..dfc290587 100644
--- a/java/dagger/internal/codegen/binding/SubcomponentDeclaration.java
+++ b/java/dagger/internal/codegen/binding/SubcomponentDeclaration.java
@@ -16,18 +16,20 @@
package dagger.internal.codegen.binding;
-import static com.google.auto.common.AnnotationMirrors.getAnnotationElementAndValue;
import static dagger.internal.codegen.binding.ConfigurationAnnotations.getSubcomponentCreator;
+import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableSet;
+import dagger.internal.codegen.base.DaggerSuperficialValidation;
import dagger.internal.codegen.base.ModuleAnnotation;
-import dagger.model.Key;
+import dagger.spi.model.Key;
import java.util.Optional;
import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
/**
* A declaration for a subcomponent that is included in a module via {@link
@@ -46,7 +48,7 @@ public abstract class SubcomponentDeclaration extends BindingDeclaration {
* The type element that defines the {@link dagger.Subcomponent} or {@link
* dagger.producers.ProductionSubcomponent} for this declaration.
*/
- abstract TypeElement subcomponentType();
+ abstract XTypeElement subcomponentType();
/** The module annotation. */
public abstract ModuleAnnotation moduleAnnotation();
@@ -61,24 +63,31 @@ public abstract class SubcomponentDeclaration extends BindingDeclaration {
/** A {@link SubcomponentDeclaration} factory. */
public static class Factory {
private final KeyFactory keyFactory;
+ private final DaggerSuperficialValidation superficialValidation;
@Inject
- Factory(KeyFactory keyFactory) {
+ Factory(KeyFactory keyFactory, DaggerSuperficialValidation superficialValidation) {
this.keyFactory = keyFactory;
+ this.superficialValidation = superficialValidation;
}
- ImmutableSet<SubcomponentDeclaration> forModule(TypeElement module) {
+ ImmutableSet<SubcomponentDeclaration> forModule(XTypeElement module) {
+ ModuleAnnotation moduleAnnotation =
+ ModuleAnnotation.moduleAnnotation(module, superficialValidation).get();
+ XElement subcomponentAttribute =
+ moduleAnnotation.annotation().getType().getTypeElement().getDeclaredMethods().stream()
+ .filter(method -> getSimpleName(method).contentEquals("subcomponents"))
+ .collect(toOptional())
+ .get();
+
ImmutableSet.Builder<SubcomponentDeclaration> declarations = ImmutableSet.builder();
- ModuleAnnotation moduleAnnotation = ModuleAnnotation.moduleAnnotation(module).get();
- Element subcomponentAttribute =
- getAnnotationElementAndValue(moduleAnnotation.annotation(), "subcomponents").getKey();
- for (TypeElement subcomponent : moduleAnnotation.subcomponents()) {
+ for (XTypeElement subcomponent : moduleAnnotation.subcomponents()) {
declarations.add(
new AutoValue_SubcomponentDeclaration(
Optional.of(subcomponentAttribute),
Optional.of(module),
keyFactory.forSubcomponentCreator(
- getSubcomponentCreator(subcomponent).get().asType()),
+ getSubcomponentCreator(subcomponent).get().getType()),
subcomponent,
moduleAnnotation));
}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/BUILD b/java/dagger/internal/codegen/bindinggraphvalidation/BUILD
index da35b516a..cb7db877c 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/BUILD
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/BUILD
@@ -30,16 +30,18 @@ java_library(
"//java/dagger/internal/codegen/binding",
"//java/dagger/internal/codegen/compileroption",
"//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/kotlin",
"//java/dagger/internal/codegen/langmodel",
"//java/dagger/internal/codegen/validation",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:graph",
- "//java/dagger/producers",
+ "//java/dagger/internal/codegen/xprocessing",
"//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/graph",
+ "//third_party/java/javapoet",
+ "//third_party/java/jsr330_inject",
],
)
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java b/java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java
index a1f1848cf..f689427ac 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java
@@ -22,7 +22,7 @@ import dagger.Provides;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.validation.CompositeBindingGraphPlugin;
import dagger.internal.codegen.validation.Validation;
-import dagger.spi.BindingGraphPlugin;
+import dagger.spi.model.BindingGraphPlugin;
/** Binds the set of {@link BindingGraphPlugin}s used to implement Dagger validation. */
@Module
@@ -42,7 +42,8 @@ public interface BindingGraphValidationModule {
MissingBindingValidator validation7,
NullableBindingValidator validation8,
ProvisionDependencyOnProducerBindingValidator validation9,
- SubcomponentFactoryMethodValidator validation10) {
+ SetMultibindingValidator validation10,
+ SubcomponentFactoryMethodValidator validation11) {
ImmutableSet<BindingGraphPlugin> plugins = ImmutableSet.of(
validation1,
validation2,
@@ -53,7 +54,8 @@ public interface BindingGraphValidationModule {
validation7,
validation8,
validation9,
- validation10);
+ validation10,
+ validation11);
if (compilerOptions.experimentalDaggerErrorMessages()) {
return ImmutableSet.of(factory.create(plugins, "Dagger/Validation"));
} else {
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java
index bc89ebbb2..f2cb90b75 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java
@@ -29,6 +29,7 @@ import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static javax.tools.Diagnostic.Kind.ERROR;
+import androidx.room.compiler.processing.XType;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -38,25 +39,26 @@ import com.google.common.graph.Graphs;
import com.google.common.graph.ImmutableNetwork;
import com.google.common.graph.MutableNetwork;
import com.google.common.graph.NetworkBuilder;
+import dagger.internal.codegen.base.Formatter;
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.OptionalType;
import dagger.internal.codegen.binding.DependencyRequestFormatter;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.Node;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
-import dagger.model.RequestKind;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.spi.model.Binding;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraph.ComponentNode;
+import dagger.spi.model.BindingGraph.DependencyEdge;
+import dagger.spi.model.BindingGraph.Node;
+import dagger.spi.model.BindingGraphPlugin;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.DiagnosticReporter;
+import dagger.spi.model.RequestKind;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.lang.model.type.TypeMirror;
/** Reports errors for dependency cycles. */
final class DependencyCycleValidator implements BindingGraphPlugin {
@@ -143,7 +145,11 @@ final class DependencyCycleValidator implements BindingGraphPlugin {
DependencyEdge dependencyToReport =
chooseDependencyEdgeConnecting(previousNode, cycleStartNode, bindingGraph);
diagnosticReporter.reportDependency(
- ERROR, dependencyToReport, errorMessage(cycle.shift(cycleStartNode), bindingGraph));
+ ERROR,
+ dependencyToReport,
+ errorMessage(cycle.shift(cycleStartNode), bindingGraph)
+ // The actual dependency trace is included from the reportDependency call.
+ + "\n\nThe cycle is requested via:");
}
private ImmutableList<Node> shortestPathToCycleFromAnEntryPoint(
@@ -182,6 +188,10 @@ final class DependencyCycleValidator implements BindingGraphPlugin {
.collect(toImmutableList())
.reverse();
dependencyRequestFormatter.formatIndentedList(message, cycleRequests, 0);
+ message.append("\n")
+ .append(dependencyRequestFormatter.format(cycleRequests.get(0)))
+ .append("\n")
+ .append(Formatter.INDENT).append("...");
return message.toString();
}
@@ -203,22 +213,22 @@ final class DependencyCycleValidator implements BindingGraphPlugin {
if (edge.dependencyRequest().key().multibindingContributionIdentifier().isPresent()) {
return false;
}
- if (breaksCycle(edge.dependencyRequest().key().type(), edge.dependencyRequest().kind())) {
+ if (breaksCycle(
+ edge.dependencyRequest().key().type().xprocessing(), edge.dependencyRequest().kind())) {
return true;
}
Node target = graph.network().incidentNodes(edge).target();
- if (target instanceof dagger.model.Binding
- && ((dagger.model.Binding) target).kind().equals(BindingKind.OPTIONAL)) {
+ if (target instanceof Binding && ((Binding) target).kind().equals(BindingKind.OPTIONAL)) {
/* For @BindsOptionalOf bindings, unwrap the type inside the Optional. If the unwrapped type
* breaks the cycle, so does the optional binding. */
- TypeMirror optionalValueType = OptionalType.from(edge.dependencyRequest().key()).valueType();
+ XType optionalValueType = OptionalType.from(edge.dependencyRequest().key()).valueType();
RequestKind requestKind = getRequestKind(optionalValueType);
return breaksCycle(extractKeyType(optionalValueType), requestKind);
}
return false;
}
- private boolean breaksCycle(TypeMirror requestedType, RequestKind requestKind) {
+ private boolean breaksCycle(XType requestedType, RequestKind requestKind) {
switch (requestKind) {
case PROVIDER:
case LAZY:
@@ -227,8 +237,7 @@ final class DependencyCycleValidator implements BindingGraphPlugin {
case INSTANCE:
if (MapType.isMap(requestedType)) {
- MapType mapType = MapType.from(requestedType);
- return !mapType.isRawType() && mapType.valuesAreTypeOf(Provider.class);
+ return MapType.from(requestedType).valuesAreTypeOf(TypeNames.PROVIDER);
}
// fall through
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java
index 08e2c3e65..1d44133ce 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java
@@ -21,11 +21,12 @@ import static javax.tools.Diagnostic.Kind.ERROR;
import dagger.internal.codegen.binding.KeyFactory;
import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.MaybeBinding;
-import dagger.model.Key;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
+import dagger.spi.model.Binding;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraph.MaybeBinding;
+import dagger.spi.model.BindingGraphPlugin;
+import dagger.spi.model.DiagnosticReporter;
+import dagger.spi.model.Key;
import javax.inject.Inject;
/**
@@ -64,7 +65,7 @@ final class DependsOnProductionExecutorValidator implements BindingGraphPlugin {
.forEach(binding -> reportError(diagnosticReporter, binding));
}
- private void reportError(DiagnosticReporter diagnosticReporter, dagger.model.Binding binding) {
+ private void reportError(DiagnosticReporter diagnosticReporter, Binding binding) {
diagnosticReporter.reportBinding(
ERROR, binding, "%s may not depend on the production executor", binding.key());
}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java
index 5c4da51b5..db8d38238 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java
@@ -21,8 +21,8 @@ import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.base.Formatter.INDENT;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSetMultimap;
-import static dagger.model.BindingKind.INJECTION;
-import static dagger.model.BindingKind.MEMBERS_INJECTION;
+import static dagger.spi.model.BindingKind.INJECTION;
+import static dagger.spi.model.BindingKind.MEMBERS_INJECTION;
import static java.util.Comparator.comparing;
import static javax.tools.Diagnostic.Kind.ERROR;
@@ -42,14 +42,16 @@ import dagger.internal.codegen.binding.BindingDeclarationFormatter;
import dagger.internal.codegen.binding.BindingNode;
import dagger.internal.codegen.binding.MultibindingDeclaration;
import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.model.Binding;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.BindingKind;
-import dagger.model.ComponentPath;
-import dagger.model.Key;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
+import dagger.spi.model.Binding;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraph.ComponentNode;
+import dagger.spi.model.BindingGraphPlugin;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.ComponentPath;
+import dagger.spi.model.DaggerElement;
+import dagger.spi.model.DaggerTypeElement;
+import dagger.spi.model.DiagnosticReporter;
+import dagger.spi.model.Key;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Optional;
@@ -238,7 +240,7 @@ final class DuplicateBindingsValidator implements BindingGraphPlugin {
private String incompatibleBindingsMessage(
Binding oneBinding, ImmutableSet<Binding> duplicateBindings, BindingGraph graph) {
Key key = oneBinding.key();
- ImmutableSet<dagger.model.Binding> multibindings =
+ ImmutableSet<dagger.spi.model.Binding> multibindings =
duplicateBindings.stream()
.filter(binding -> binding.kind().isMultibinding())
.collect(toImmutableSet());
@@ -248,11 +250,11 @@ final class DuplicateBindingsValidator implements BindingGraphPlugin {
java.util.Formatter messageFormatter = new java.util.Formatter(message);
messageFormatter.format("%s has incompatible bindings or declarations:\n", key);
message.append(INDENT);
- dagger.model.Binding multibinding = getOnlyElement(multibindings);
+ dagger.spi.model.Binding multibinding = getOnlyElement(multibindings);
messageFormatter.format("%s bindings and declarations:", multibindingTypeString(multibinding));
formatDeclarations(message, 2, declarations(graph, multibindings));
- Set<dagger.model.Binding> uniqueBindings =
+ Set<dagger.spi.model.Binding> uniqueBindings =
Sets.filter(duplicateBindings, binding -> !binding.equals(multibinding));
message.append('\n').append(INDENT).append("Unique bindings and declarations:");
formatDeclarations(
@@ -276,7 +278,7 @@ final class DuplicateBindingsValidator implements BindingGraphPlugin {
}
private ImmutableSet<BindingDeclaration> declarations(
- BindingGraph graph, Set<dagger.model.Binding> bindings) {
+ BindingGraph graph, Set<dagger.spi.model.Binding> bindings) {
return bindings.stream()
.flatMap(binding -> declarations(graph, binding).stream())
.distinct()
@@ -285,7 +287,7 @@ final class DuplicateBindingsValidator implements BindingGraphPlugin {
}
private ImmutableSet<BindingDeclaration> declarations(
- BindingGraph graph, dagger.model.Binding binding) {
+ BindingGraph graph, dagger.spi.model.Binding binding) {
ImmutableSet.Builder<BindingDeclaration> declarations = ImmutableSet.builder();
BindingNode bindingNode = (BindingNode) binding;
bindingNode.associatedDeclarations().forEach(declarations::add);
@@ -299,7 +301,7 @@ final class DuplicateBindingsValidator implements BindingGraphPlugin {
return declarations.build();
}
- private String multibindingTypeString(dagger.model.Binding multibinding) {
+ private String multibindingTypeString(dagger.spi.model.Binding multibinding) {
switch (multibinding.kind()) {
case MULTIBOUND_MAP:
return "Map";
@@ -339,7 +341,9 @@ final class DuplicateBindingsValidator implements BindingGraphPlugin {
private static BindingElement forBinding(Binding binding) {
return new AutoValue_DuplicateBindingsValidator_BindingElement(
- binding.kind(), binding.bindingElement(), binding.contributingModule());
+ binding.kind(),
+ binding.bindingElement().map(DaggerElement::java),
+ binding.contributingModule().map(DaggerTypeElement::java));
}
}
}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java
index a01dbaf62..b9cf89c33 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java
@@ -18,22 +18,23 @@ package dagger.internal.codegen.bindinggraphvalidation;
import static dagger.internal.codegen.base.Formatter.INDENT;
import static dagger.internal.codegen.base.Scopes.getReadableSource;
-import static dagger.internal.codegen.langmodel.DaggerElements.closestEnclosingTypeElement;
-import static dagger.model.BindingKind.INJECTION;
+import static dagger.internal.codegen.xprocessing.XElements.asExecutable;
+import static dagger.internal.codegen.xprocessing.XElements.closestEnclosingTypeElement;
+import static dagger.spi.model.BindingKind.INJECTION;
import static java.util.stream.Collectors.joining;
import static javax.tools.Diagnostic.Kind.ERROR;
-import com.google.auto.common.MoreElements;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimaps;
import dagger.internal.codegen.base.Scopes;
import dagger.internal.codegen.binding.MethodSignatureFormatter;
import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.model.Binding;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
+import dagger.internal.codegen.validation.DiagnosticMessageGenerator;
+import dagger.spi.model.Binding;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraph.ComponentNode;
+import dagger.spi.model.BindingGraphPlugin;
+import dagger.spi.model.DiagnosticReporter;
import java.util.Optional;
import java.util.Set;
import javax.inject.Inject;
@@ -47,12 +48,16 @@ final class IncompatiblyScopedBindingsValidator implements BindingGraphPlugin {
private final MethodSignatureFormatter methodSignatureFormatter;
private final CompilerOptions compilerOptions;
+ private final DiagnosticMessageGenerator.Factory diagnosticMessageGeneratorFactory;
@Inject
IncompatiblyScopedBindingsValidator(
- MethodSignatureFormatter methodSignatureFormatter, CompilerOptions compilerOptions) {
+ MethodSignatureFormatter methodSignatureFormatter,
+ CompilerOptions compilerOptions,
+ DiagnosticMessageGenerator.Factory diagnosticMessageGeneratorFactory) {
this.methodSignatureFormatter = methodSignatureFormatter;
this.compilerOptions = compilerOptions;
+ this.diagnosticMessageGeneratorFactory = diagnosticMessageGeneratorFactory;
}
@Override
@@ -62,9 +67,11 @@ final class IncompatiblyScopedBindingsValidator implements BindingGraphPlugin {
@Override
public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- ImmutableSetMultimap.Builder<ComponentNode, dagger.model.Binding> incompatibleBindings =
+ DiagnosticMessageGenerator diagnosticMessageGenerator =
+ diagnosticMessageGeneratorFactory.create(bindingGraph);
+ ImmutableSetMultimap.Builder<ComponentNode, dagger.spi.model.Binding> incompatibleBindings =
ImmutableSetMultimap.builder();
- for (dagger.model.Binding binding : bindingGraph.bindings()) {
+ for (dagger.spi.model.Binding binding : bindingGraph.bindings()) {
binding
.scope()
.filter(scope -> !scope.isReusable())
@@ -85,16 +92,19 @@ final class IncompatiblyScopedBindingsValidator implements BindingGraphPlugin {
});
}
Multimaps.asMap(incompatibleBindings.build())
- .forEach((componentNode, bindings) -> report(componentNode, bindings, diagnosticReporter));
+ .forEach((componentNode, bindings) ->
+ report(componentNode, bindings, diagnosticReporter, diagnosticMessageGenerator));
}
private void report(
ComponentNode componentNode,
Set<Binding> bindings,
- DiagnosticReporter diagnosticReporter) {
+ DiagnosticReporter diagnosticReporter,
+ DiagnosticMessageGenerator diagnosticMessageGenerator) {
Diagnostic.Kind diagnosticKind = ERROR;
StringBuilder message =
- new StringBuilder(componentNode.componentPath().currentComponent().getQualifiedName());
+ new StringBuilder(
+ componentNode.componentPath().currentComponent().className().canonicalName());
if (!componentNode.isRealComponent()) {
// If the "component" is really a module, it will have no scopes attached. We want to report
@@ -125,7 +135,7 @@ final class IncompatiblyScopedBindingsValidator implements BindingGraphPlugin {
case PROVISION:
message.append(
methodSignatureFormatter.format(
- MoreElements.asExecutable(binding.bindingElement().get())));
+ asExecutable(binding.bindingElement().get().xprocessing())));
break;
case INJECTION:
@@ -133,12 +143,17 @@ final class IncompatiblyScopedBindingsValidator implements BindingGraphPlugin {
.append(getReadableSource(binding.scope().get()))
.append(" class ")
.append(
- closestEnclosingTypeElement(binding.bindingElement().get()).getQualifiedName());
+ closestEnclosingTypeElement(binding.bindingElement().get().xprocessing())
+ .getQualifiedName())
+ .append(diagnosticMessageGenerator.getMessage(binding));
+
break;
default:
throw new AssertionError(binding);
}
+
+ message.append('\n');
}
diagnosticReporter.reportComponent(diagnosticKind, componentNode, message.toString());
}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java
index fe1c3e044..a250612b0 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java
@@ -16,25 +16,29 @@
package dagger.internal.codegen.bindinggraphvalidation;
-import static dagger.model.BindingKind.INJECTION;
+import static androidx.room.compiler.processing.compat.XConverters.toXProcessing;
+import static com.google.auto.common.MoreTypes.asTypeElement;
+import static dagger.spi.model.BindingKind.INJECTION;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XProcessingEnv;
import dagger.internal.codegen.validation.InjectValidator;
import dagger.internal.codegen.validation.ValidationReport;
import dagger.internal.codegen.validation.ValidationReport.Item;
-import dagger.model.BindingGraph;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
+import dagger.spi.model.Binding;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraphPlugin;
+import dagger.spi.model.DiagnosticReporter;
import javax.inject.Inject;
-import javax.lang.model.element.TypeElement;
/** Validates bindings from {@code @Inject}-annotated constructors. */
final class InjectBindingValidator implements BindingGraphPlugin {
+ private final XProcessingEnv processingEnv;
private final InjectValidator injectValidator;
@Inject
- InjectBindingValidator(InjectValidator injectValidator) {
+ InjectBindingValidator(XProcessingEnv processingEnv, InjectValidator injectValidator) {
+ this.processingEnv = processingEnv;
this.injectValidator = injectValidator.whenGeneratingCode();
}
@@ -50,10 +54,10 @@ final class InjectBindingValidator implements BindingGraphPlugin {
.forEach(binding -> validateInjectionBinding(binding, diagnosticReporter));
}
- private void validateInjectionBinding(
- dagger.model.Binding node, DiagnosticReporter diagnosticReporter) {
- ValidationReport<TypeElement> typeReport =
- injectValidator.validateType(MoreTypes.asTypeElement(node.key().type()));
+ private void validateInjectionBinding(Binding node, DiagnosticReporter diagnosticReporter) {
+ ValidationReport typeReport =
+ injectValidator.validate(
+ toXProcessing(asTypeElement(node.key().type().java()), processingEnv));
for (Item item : typeReport.allItems()) {
diagnosticReporter.reportBinding(item.kind(), node, item.message());
}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java
index 481c6d82b..feaf88b2c 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java
@@ -21,31 +21,29 @@ import static com.google.common.collect.Multimaps.filterKeys;
import static dagger.internal.codegen.base.Formatter.INDENT;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSetMultimap;
-import static dagger.model.BindingKind.MULTIBOUND_MAP;
+import static dagger.spi.model.BindingKind.MULTIBOUND_MAP;
import static javax.tools.Diagnostic.Kind.ERROR;
-import com.google.auto.common.MoreTypes;
-import com.google.common.base.Equivalence;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
+import com.squareup.javapoet.TypeName;
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.binding.BindingDeclaration;
import dagger.internal.codegen.binding.BindingDeclarationFormatter;
import dagger.internal.codegen.binding.BindingNode;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.binding.KeyFactory;
-import dagger.model.BindingGraph;
-import dagger.model.Key;
-import dagger.producers.Producer;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.spi.model.Binding;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraphPlugin;
+import dagger.spi.model.DiagnosticReporter;
+import dagger.spi.model.Key;
import java.util.Set;
import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.lang.model.type.DeclaredType;
/**
* Reports an error for any map binding with either more than one contribution with the same map key
@@ -91,36 +89,38 @@ final class MapMultibindingValidator implements BindingGraphPlugin {
* <li>{@code Map<K, Producer<V>>}
* </ol>
*/
- private ImmutableSet<dagger.model.Binding> mapMultibindings(BindingGraph bindingGraph) {
- ImmutableSetMultimap<Key, dagger.model.Binding> mapMultibindings =
+ private ImmutableSet<Binding> mapMultibindings(BindingGraph bindingGraph) {
+ ImmutableSetMultimap<Key, Binding> mapMultibindings =
bindingGraph.bindings().stream()
.filter(node -> node.kind().equals(MULTIBOUND_MAP))
- .collect(toImmutableSetMultimap(dagger.model.Binding::key, node -> node));
+ .collect(toImmutableSetMultimap(Binding::key, node -> node));
// Mutlbindings for Map<K, V>
- SetMultimap<Key, dagger.model.Binding> plainValueMapMultibindings =
+ SetMultimap<Key, Binding> plainValueMapMultibindings =
filterKeys(mapMultibindings, key -> !MapType.from(key).valuesAreFrameworkType());
// Multibindings for Map<K, Provider<V>> where Map<K, V> isn't in plainValueMapMultibindings
- SetMultimap<Key, dagger.model.Binding> providerValueMapMultibindings =
+ SetMultimap<Key, Binding> providerValueMapMultibindings =
filterKeys(
mapMultibindings,
key ->
- MapType.from(key).valuesAreTypeOf(Provider.class)
+ MapType.from(key).valuesAreTypeOf(TypeNames.PROVIDER)
&& !plainValueMapMultibindings.containsKey(keyFactory.unwrapMapValueType(key)));
// Multibindings for Map<K, Producer<V>> where Map<K, V> isn't in plainValueMapMultibindings and
// Map<K, Provider<V>> isn't in providerValueMapMultibindings
- SetMultimap<Key, dagger.model.Binding> producerValueMapMultibindings =
+ SetMultimap<Key, Binding> producerValueMapMultibindings =
filterKeys(
mapMultibindings,
key ->
- MapType.from(key).valuesAreTypeOf(Producer.class)
+ MapType.from(key).valuesAreTypeOf(TypeNames.PRODUCER)
&& !plainValueMapMultibindings.containsKey(keyFactory.unwrapMapValueType(key))
&& !providerValueMapMultibindings.containsKey(
- keyFactory.rewrapMapKey(key, Producer.class, Provider.class).get()));
+ keyFactory
+ .rewrapMapKey(key, TypeNames.PRODUCER, TypeNames.PROVIDER)
+ .get()));
- return new ImmutableSet.Builder<dagger.model.Binding>()
+ return new ImmutableSet.Builder<Binding>()
.addAll(plainValueMapMultibindings.values())
.addAll(providerValueMapMultibindings.values())
.addAll(producerValueMapMultibindings.values())
@@ -128,7 +128,7 @@ final class MapMultibindingValidator implements BindingGraphPlugin {
}
private ImmutableSet<ContributionBinding> mapBindingContributions(
- dagger.model.Binding binding, BindingGraph bindingGraph) {
+ Binding binding, BindingGraph bindingGraph) {
checkArgument(binding.kind().equals(MULTIBOUND_MAP));
return bindingGraph.requestedBindings(binding).stream()
.map(b -> (BindingNode) b)
@@ -137,7 +137,7 @@ final class MapMultibindingValidator implements BindingGraphPlugin {
}
private void checkForDuplicateMapKeys(
- dagger.model.Binding multiboundMapBinding,
+ Binding multiboundMapBinding,
ImmutableSet<ContributionBinding> contributions,
DiagnosticReporter diagnosticReporter) {
ImmutableSetMultimap<?, ContributionBinding> contributionsByMapKey =
@@ -156,11 +156,11 @@ final class MapMultibindingValidator implements BindingGraphPlugin {
}
private void checkForInconsistentMapKeyAnnotationTypes(
- dagger.model.Binding multiboundMapBinding,
+ Binding multiboundMapBinding,
ImmutableSet<ContributionBinding> contributions,
DiagnosticReporter diagnosticReporter) {
- ImmutableSetMultimap<Equivalence.Wrapper<DeclaredType>, ContributionBinding>
- contributionsByMapKeyAnnotationType = indexByMapKeyAnnotationType(contributions);
+ ImmutableSetMultimap<TypeName, ContributionBinding> contributionsByMapKeyAnnotationType =
+ indexByMapKeyAnnotationType(contributions);
if (contributionsByMapKeyAnnotationType.keySet().size() > 1) {
diagnosticReporter.reportBinding(
@@ -171,19 +171,16 @@ final class MapMultibindingValidator implements BindingGraphPlugin {
}
}
- private static ImmutableSetMultimap<Equivalence.Wrapper<DeclaredType>, ContributionBinding>
- indexByMapKeyAnnotationType(ImmutableSet<ContributionBinding> contributions) {
+ private static ImmutableSetMultimap<TypeName, ContributionBinding> indexByMapKeyAnnotationType(
+ ImmutableSet<ContributionBinding> contributions) {
return ImmutableSetMultimap.copyOf(
Multimaps.index(
contributions,
- mapBinding ->
- MoreTypes.equivalence()
- .wrap(mapBinding.mapKeyAnnotation().get().getAnnotationType())));
+ mapBinding -> TypeName.get(mapBinding.mapKeyAnnotation().get().getAnnotationType())));
}
private String inconsistentMapKeyAnnotationTypesErrorMessage(
- ImmutableSetMultimap<Equivalence.Wrapper<DeclaredType>, ContributionBinding>
- contributionsByMapKeyAnnotationType,
+ ImmutableSetMultimap<TypeName, ContributionBinding> contributionsByMapKeyAnnotationType,
Key mapBindingKey) {
StringBuilder message =
new StringBuilder(mapBindingKey.toString())
@@ -191,7 +188,7 @@ final class MapMultibindingValidator implements BindingGraphPlugin {
Multimaps.asMap(contributionsByMapKeyAnnotationType)
.forEach(
(annotationType, contributions) -> {
- message.append('\n').append(INDENT).append(annotationType.get()).append(':');
+ message.append('\n').append(INDENT).append(annotationType).append(':');
bindingDeclarationFormatter.formatIndentedList(message, contributions, 2);
});
return message.toString();
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java
index 7334cd9c8..fdcccf968 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java
@@ -17,36 +17,50 @@
package dagger.internal.codegen.bindinggraphvalidation;
import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.Iterables.getLast;
import static dagger.internal.codegen.base.Keys.isValidImplicitProvisionKey;
import static dagger.internal.codegen.base.Keys.isValidMembersInjectionKey;
import static dagger.internal.codegen.base.RequestKinds.canBeSatisfiedByProductionBinding;
+import static dagger.internal.codegen.binding.DependencyRequestFormatter.DOUBLE_INDENT;
import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
+import static dagger.internal.codegen.xprocessing.XTypes.isWildcard;
import static javax.tools.Diagnostic.Kind.ERROR;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import dagger.internal.codegen.binding.DependencyRequestFormatter;
import dagger.internal.codegen.binding.InjectBindingRegistry;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.MissingBinding;
-import dagger.model.BindingGraph.Node;
-import dagger.model.Key;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
+import dagger.internal.codegen.validation.DiagnosticMessageGenerator;
+import dagger.spi.model.Binding;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraph.ComponentNode;
+import dagger.spi.model.BindingGraph.DependencyEdge;
+import dagger.spi.model.BindingGraph.Edge;
+import dagger.spi.model.BindingGraph.MissingBinding;
+import dagger.spi.model.BindingGraph.Node;
+import dagger.spi.model.BindingGraphPlugin;
+import dagger.spi.model.ComponentPath;
+import dagger.spi.model.DiagnosticReporter;
+import dagger.spi.model.Key;
+import java.util.List;
+import java.util.stream.Collectors;
import javax.inject.Inject;
-import javax.lang.model.type.TypeKind;
/** Reports errors for missing bindings. */
final class MissingBindingValidator implements BindingGraphPlugin {
- private final DaggerTypes types;
private final InjectBindingRegistry injectBindingRegistry;
+ private final DependencyRequestFormatter dependencyRequestFormatter;
+ private final DiagnosticMessageGenerator.Factory diagnosticMessageGeneratorFactory;
@Inject
MissingBindingValidator(
- DaggerTypes types, InjectBindingRegistry injectBindingRegistry) {
- this.types = types;
+ InjectBindingRegistry injectBindingRegistry,
+ DependencyRequestFormatter dependencyRequestFormatter,
+ DiagnosticMessageGenerator.Factory diagnosticMessageGeneratorFactory) {
this.injectBindingRegistry = injectBindingRegistry;
+ this.dependencyRequestFormatter = dependencyRequestFormatter;
+ this.diagnosticMessageGeneratorFactory = diagnosticMessageGeneratorFactory;
}
@Override
@@ -68,18 +82,33 @@ final class MissingBindingValidator implements BindingGraphPlugin {
private void reportMissingBinding(
MissingBinding missingBinding, BindingGraph graph, DiagnosticReporter diagnosticReporter) {
- diagnosticReporter.reportBinding(
- ERROR, missingBinding, missingBindingErrorMessage(missingBinding, graph));
+ List<ComponentPath> alternativeComponents =
+ graph.bindings(missingBinding.key()).stream()
+ .map(Binding::componentPath)
+ .distinct()
+ .collect(Collectors.toList());
+ // Print component name for each binding along the dependency path if the missing binding
+ // exists in a different component than expected
+ if (alternativeComponents.isEmpty()) {
+ diagnosticReporter.reportBinding(
+ ERROR, missingBinding, missingBindingErrorMessage(missingBinding, graph));
+ } else {
+ diagnosticReporter.reportComponent(
+ ERROR,
+ graph.componentNode(missingBinding.componentPath()).get(),
+ missingBindingErrorMessage(missingBinding, graph)
+ + wrongComponentErrorMessage(missingBinding, alternativeComponents, graph));
+ }
}
private String missingBindingErrorMessage(MissingBinding missingBinding, BindingGraph graph) {
Key key = missingBinding.key();
StringBuilder errorMessage = new StringBuilder();
// Wildcards should have already been checked by DependencyRequestValidator.
- verify(!key.type().getKind().equals(TypeKind.WILDCARD), "unexpected wildcard request: %s", key);
+ verify(!isWildcard(key.type().xprocessing()), "unexpected wildcard request: %s", key);
// TODO(ronshapiro): replace "provided" with "satisfied"?
errorMessage.append(key).append(" cannot be provided without ");
- if (isValidImplicitProvisionKey(key, types)) {
+ if (isValidImplicitProvisionKey(key)) {
errorMessage.append("an @Inject constructor or ");
}
errorMessage.append("an @Provides-"); // TODO(dpb): s/an/a
@@ -91,17 +120,64 @@ final class MissingBindingValidator implements BindingGraphPlugin {
errorMessage.append(
" This type supports members injection but cannot be implicitly provided.");
}
- graph.bindings(key).stream()
- .map(binding -> binding.componentPath().currentComponent())
- .distinct()
- .forEach(
- component ->
- errorMessage
- .append("\nA binding with matching key exists in component: ")
- .append(component.getQualifiedName()));
return errorMessage.toString();
}
+ private String wrongComponentErrorMessage(
+ MissingBinding missingBinding,
+ List<ComponentPath> alternativeComponentPath,
+ BindingGraph graph) {
+ ImmutableSet<DependencyEdge> entryPoints =
+ graph.entryPointEdgesDependingOnBinding(missingBinding);
+ DiagnosticMessageGenerator generator = diagnosticMessageGeneratorFactory.create(graph);
+ ImmutableList<DependencyEdge> dependencyTrace =
+ generator.dependencyTrace(missingBinding, entryPoints);
+ StringBuilder message =
+ graph.isFullBindingGraph()
+ ? new StringBuilder()
+ : new StringBuilder(dependencyTrace.size() * 100 /* a guess heuristic */);
+ // Check in which component the missing binding is requested. This can be different from the
+ // component the missing binding is in because we'll try to search up the parent components for
+ // a binding which makes missing bindings end up at the root component. This is different from
+ // the place we are logically requesting the binding from. Note that this is related to the
+ // particular dependency trace being shown and so is not necessarily stable.
+ String missingComponentName =
+ getComponentFromDependencyEdge(dependencyTrace.get(0), graph, false);
+ boolean hasSameComponentName = false;
+ for (ComponentPath component : alternativeComponentPath) {
+ message.append("\nA binding for ").append(missingBinding.key()).append(" exists in ");
+ String currentComponentName = component.currentComponent().className().canonicalName();
+ if (currentComponentName.contentEquals(missingComponentName)) {
+ hasSameComponentName = true;
+ message.append("[").append(component).append("]");
+ } else {
+ message.append(currentComponentName);
+ }
+ message.append(":");
+ }
+ for (DependencyEdge edge : dependencyTrace) {
+ String line = dependencyRequestFormatter.format(edge.dependencyRequest());
+ if (line.isEmpty()) {
+ continue;
+ }
+ // If we ran into a rare case where the component names collide and we need to show the full
+ // path, only show the full path for the first dependency request. This is guaranteed to be
+ // the component in question since the logic for checking for a collision uses the first
+ // edge in the trace. Do not expand subsequent component paths to reduce spam.
+ String componentName =
+ String.format("[%s] ", getComponentFromDependencyEdge(edge, graph, hasSameComponentName));
+ hasSameComponentName = false;
+ message.append("\n").append(line.replace(DOUBLE_INDENT, DOUBLE_INDENT + componentName));
+ }
+ if (!dependencyTrace.isEmpty()) {
+ generator.appendComponentPathUnlessAtRoot(message, source(getLast(dependencyTrace), graph));
+ }
+ message.append(
+ generator.getRequestsNotInTrace(
+ dependencyTrace, generator.requests(missingBinding), entryPoints));
+ return message.toString();
+ }
+
private boolean allIncomingDependenciesCanUseProduction(
MissingBinding missingBinding, BindingGraph graph) {
return graph.network().inEdges(missingBinding).stream()
@@ -116,11 +192,11 @@ final class MissingBindingValidator implements BindingGraphPlugin {
if (source instanceof ComponentNode) {
return canBeSatisfiedByProductionBinding(edge.dependencyRequest().kind());
}
- if (source instanceof dagger.model.Binding) {
- return ((dagger.model.Binding) source).isProduction();
+ if (source instanceof dagger.spi.model.Binding) {
+ return ((dagger.spi.model.Binding) source).isProduction();
}
throw new IllegalArgumentException(
- "expected a dagger.model.Binding or ComponentNode: " + source);
+ "expected a dagger.spi.model.Binding or ComponentNode: " + source);
}
private boolean typeHasInjectionSites(Key key) {
@@ -129,4 +205,16 @@ final class MissingBindingValidator implements BindingGraphPlugin {
.map(binding -> !binding.injectionSites().isEmpty())
.orElse(false);
}
+
+ private static String getComponentFromDependencyEdge(
+ DependencyEdge edge, BindingGraph graph, boolean completePath) {
+ ComponentPath componentPath = graph.network().incidentNodes(edge).source().componentPath();
+ return completePath
+ ? componentPath.toString()
+ : componentPath.currentComponent().className().canonicalName();
+ }
+
+ private Node source(Edge edge, BindingGraph graph) {
+ return graph.network().incidentNodes(edge).source();
+ }
}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/NullableBindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/NullableBindingValidator.java
index 9800b15f2..4130fe97e 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/NullableBindingValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/NullableBindingValidator.java
@@ -24,10 +24,11 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
+import dagger.spi.model.Binding;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraph.DependencyEdge;
+import dagger.spi.model.BindingGraphPlugin;
+import dagger.spi.model.DiagnosticReporter;
import javax.inject.Inject;
/**
@@ -45,7 +46,7 @@ final class NullableBindingValidator implements BindingGraphPlugin {
@Override
public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- for (dagger.model.Binding binding : nullableBindings(bindingGraph)) {
+ for (Binding binding : nullableBindings(bindingGraph)) {
for (DependencyEdge dependencyEdge : nonNullableDependencies(bindingGraph, binding)) {
diagnosticReporter.reportDependency(
compilerOptions.nullableValidationKind(),
@@ -62,14 +63,14 @@ final class NullableBindingValidator implements BindingGraphPlugin {
return "Dagger/Nullable";
}
- private ImmutableList<dagger.model.Binding> nullableBindings(BindingGraph bindingGraph) {
+ private ImmutableList<Binding> nullableBindings(BindingGraph bindingGraph) {
return bindingGraph.bindings().stream()
.filter(binding -> binding.isNullable())
.collect(toImmutableList());
}
private ImmutableSet<DependencyEdge> nonNullableDependencies(
- BindingGraph bindingGraph, dagger.model.Binding binding) {
+ BindingGraph bindingGraph, Binding binding) {
return bindingGraph.network().inEdges(binding).stream()
.flatMap(instancesOf(DependencyEdge.class))
.filter(edge -> !edge.dependencyRequest().isNullable())
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java
index 7d742f96f..53904a780 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java
@@ -22,11 +22,12 @@ import static dagger.internal.codegen.base.RequestKinds.canBeSatisfiedByProducti
import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
import static javax.tools.Diagnostic.Kind.ERROR;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.Node;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
+import dagger.spi.model.Binding;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraph.DependencyEdge;
+import dagger.spi.model.BindingGraph.Node;
+import dagger.spi.model.BindingGraphPlugin;
+import dagger.spi.model.DiagnosticReporter;
import java.util.stream.Stream;
import javax.inject.Inject;
@@ -68,8 +69,7 @@ final class ProvisionDependencyOnProducerBindingValidator implements BindingGrap
/** Returns the dependencies on {@code binding}. */
// TODO(dpb): Move to BindingGraph.
- private Stream<DependencyEdge> incomingDependencies(
- dagger.model.Binding binding, BindingGraph bindingGraph) {
+ private Stream<DependencyEdge> incomingDependencies(Binding binding, BindingGraph bindingGraph) {
return bindingGraph.network().inEdges(binding).stream()
.flatMap(instancesOf(DependencyEdge.class));
}
@@ -88,16 +88,16 @@ final class ProvisionDependencyOnProducerBindingValidator implements BindingGrap
* DependencyEdge#isEntryPoint() entry point}.
*/
// TODO(dpb): Move to BindingGraph.
- private dagger.model.Binding bindingRequestingDependency(
+ private Binding bindingRequestingDependency(
DependencyEdge dependency, BindingGraph bindingGraph) {
checkArgument(!dependency.isEntryPoint());
Node source = bindingGraph.network().incidentNodes(dependency).source();
verify(
- source instanceof dagger.model.Binding,
+ source instanceof Binding,
"expected source of %s to be a binding, but was: %s",
dependency,
source);
- return (dagger.model.Binding) source;
+ return (Binding) source;
}
private String entryPointErrorMessage(DependencyEdge entryPoint) {
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/SetMultibindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/SetMultibindingValidator.java
new file mode 100644
index 000000000..1f79f872e
--- /dev/null
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/SetMultibindingValidator.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.bindinggraphvalidation;
+
+import static dagger.spi.model.BindingKind.DELEGATE;
+import static dagger.spi.model.BindingKind.MULTIBOUND_SET;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+import dagger.spi.model.Binding;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraphPlugin;
+import dagger.spi.model.DiagnosticReporter;
+import dagger.spi.model.Key;
+import javax.inject.Inject;
+
+/** Validates that there are not multiple set binding contributions to the same binding. */
+final class SetMultibindingValidator implements BindingGraphPlugin {
+
+ @Inject
+ SetMultibindingValidator() {
+ }
+
+ @Override
+ public String pluginName() {
+ return "Dagger/SetMultibinding";
+ }
+
+ @Override
+ public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
+ bindingGraph.bindings().stream()
+ .filter(binding -> binding.kind().equals(MULTIBOUND_SET))
+ .forEach(
+ binding ->
+ checkForDuplicateSetContributions(binding, bindingGraph, diagnosticReporter));
+ }
+
+ private void checkForDuplicateSetContributions(
+ Binding binding, BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
+ // Map of delegate target key to the original contribution binding
+ Multimap<Key, Binding> dereferencedBindsTargets = HashMultimap.create();
+ for (Binding dep : bindingGraph.requestedBindings(binding)) {
+ if (dep.kind().equals(DELEGATE)) {
+ dereferencedBindsTargets.put(dereferenceDelegateBinding(dep, bindingGraph), dep);
+ }
+ }
+
+ dereferencedBindsTargets
+ .asMap()
+ .forEach(
+ (targetKey, contributions) -> {
+ if (contributions.size() > 1) {
+ diagnosticReporter.reportComponent(
+ ERROR,
+ bindingGraph.componentNode(binding.componentPath()).get(),
+ "Multiple set contributions into %s for the same contribution key: %s.\n\n"
+ + " %s\n",
+ binding.key(),
+ targetKey,
+ Joiner.on("\n ").join(contributions));
+ }
+ });
+ }
+
+ /** Returns the delegate target of a delegate binding (going through other delegates as well). */
+ private Key dereferenceDelegateBinding(Binding binding, BindingGraph bindingGraph) {
+ ImmutableSet<Binding> delegateSet = bindingGraph.requestedBindings(binding);
+ if (delegateSet.isEmpty()) {
+ // There may not be a delegate if the delegate is missing. In this case, we just take the
+ // requested key and return that.
+ return Iterables.getOnlyElement(binding.dependencies()).key();
+ }
+ // If there is a binding, first we check if that is a delegate binding so we can dereference
+ // that binding if needed.
+ Binding delegate = Iterables.getOnlyElement(delegateSet);
+ if (delegate.kind().equals(DELEGATE)) {
+ return dereferenceDelegateBinding(delegate, bindingGraph);
+ }
+ return delegate.key();
+ }
+}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/SubcomponentFactoryMethodValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/SubcomponentFactoryMethodValidator.java
index bf83a69f9..6650c4368 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/SubcomponentFactoryMethodValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/SubcomponentFactoryMethodValidator.java
@@ -16,49 +16,39 @@
package dagger.internal.codegen.bindinggraphvalidation;
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.auto.common.MoreTypes.asExecutable;
-import static com.google.auto.common.MoreTypes.asTypeElements;
import static com.google.common.collect.Sets.union;
import static dagger.internal.codegen.binding.ComponentRequirement.componentCanMakeNewInstances;
import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static javax.tools.Diagnostic.Kind.ERROR;
+import androidx.room.compiler.processing.XExecutableType;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;
import dagger.internal.codegen.base.Util;
import dagger.internal.codegen.binding.ComponentNodeImpl;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ChildFactoryMethodEdge;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.spi.model.BindingGraph.ComponentNode;
+import dagger.spi.model.BindingGraphPlugin;
+import dagger.spi.model.DiagnosticReporter;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import javax.inject.Inject;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
/** Reports an error if a subcomponent factory method is missing required modules. */
final class SubcomponentFactoryMethodValidator implements BindingGraphPlugin {
- private final DaggerTypes types;
- private final KotlinMetadataUtil metadataUtil;
- private final Map<ComponentNode, Set<TypeElement>> inheritedModulesCache = new HashMap<>();
+ private final Map<ComponentNode, Set<XTypeElement>> inheritedModulesCache = new HashMap<>();
@Inject
- SubcomponentFactoryMethodValidator(DaggerTypes types, KotlinMetadataUtil metadataUtil) {
- this.types = types;
- this.metadataUtil = metadataUtil;
- }
+ SubcomponentFactoryMethodValidator() {}
@Override
public String pluginName() {
@@ -77,7 +67,7 @@ final class SubcomponentFactoryMethodValidator implements BindingGraphPlugin {
.flatMap(instancesOf(ChildFactoryMethodEdge.class))
.forEach(
edge -> {
- ImmutableSet<TypeElement> missingModules = findMissingModules(edge, bindingGraph);
+ ImmutableSet<XTypeElement> missingModules = findMissingModules(edge, bindingGraph);
if (!missingModules.isEmpty()) {
reportMissingModuleParameters(
edge, missingModules, bindingGraph, diagnosticReporter);
@@ -85,49 +75,50 @@ final class SubcomponentFactoryMethodValidator implements BindingGraphPlugin {
});
}
- private ImmutableSet<TypeElement> findMissingModules(
+ private ImmutableSet<XTypeElement> findMissingModules(
ChildFactoryMethodEdge edge, BindingGraph graph) {
- ImmutableSet<TypeElement> factoryMethodParameters =
+ ImmutableSet<XTypeElement> factoryMethodParameters =
subgraphFactoryMethodParameters(edge, graph);
ComponentNode child = (ComponentNode) graph.network().incidentNodes(edge).target();
- SetView<TypeElement> modulesOwnedByChild = ownedModules(child, graph);
+ SetView<XTypeElement> modulesOwnedByChild = ownedModules(child, graph);
return graph.bindings().stream()
// bindings owned by child
.filter(binding -> binding.componentPath().equals(child.componentPath()))
// that require a module instance
.filter(binding -> binding.requiresModuleInstance())
- .map(binding -> binding.contributingModule().get())
+ .map(binding -> binding.contributingModule().get().xprocessing())
.distinct()
// module owned by child
.filter(module -> modulesOwnedByChild.contains(module))
// module not in the method parameters
.filter(module -> !factoryMethodParameters.contains(module))
// module doesn't have an accessible no-arg constructor
- .filter(moduleType -> !componentCanMakeNewInstances(moduleType, metadataUtil))
+ .filter(moduleType -> !componentCanMakeNewInstances(moduleType))
.collect(toImmutableSet());
}
- private ImmutableSet<TypeElement> subgraphFactoryMethodParameters(
+ private ImmutableSet<XTypeElement> subgraphFactoryMethodParameters(
ChildFactoryMethodEdge edge, BindingGraph bindingGraph) {
ComponentNode parent = (ComponentNode) bindingGraph.network().incidentNodes(edge).source();
- DeclaredType parentType = asDeclared(parent.componentPath().currentComponent().asType());
- ExecutableType factoryMethodType =
- asExecutable(types.asMemberOf(parentType, edge.factoryMethod()));
- return asTypeElements(factoryMethodType.getParameterTypes());
+ XType parentType = parent.componentPath().currentComponent().xprocessing().getType();
+ XExecutableType factoryMethodType = edge.factoryMethod().xprocessing().asMemberOf(parentType);
+ return factoryMethodType.getParameterTypes().stream()
+ .map(XType::getTypeElement)
+ .collect(toImmutableSet());
}
- private SetView<TypeElement> ownedModules(ComponentNode component, BindingGraph graph) {
+ private SetView<XTypeElement> ownedModules(ComponentNode component, BindingGraph graph) {
return Sets.difference(
((ComponentNodeImpl) component).componentDescriptor().moduleTypes(),
inheritedModules(component, graph));
}
- private Set<TypeElement> inheritedModules(ComponentNode component, BindingGraph graph) {
+ private Set<XTypeElement> inheritedModules(ComponentNode component, BindingGraph graph) {
return Util.reentrantComputeIfAbsent(
inheritedModulesCache, component, uncachedInheritedModules(graph));
}
- private Function<ComponentNode, Set<TypeElement>> uncachedInheritedModules(BindingGraph graph) {
+ private Function<ComponentNode, Set<XTypeElement>> uncachedInheritedModules(BindingGraph graph) {
return componentNode ->
componentNode.componentPath().atRoot()
? ImmutableSet.of()
@@ -139,7 +130,7 @@ final class SubcomponentFactoryMethodValidator implements BindingGraphPlugin {
private void reportMissingModuleParameters(
ChildFactoryMethodEdge edge,
- ImmutableSet<TypeElement> missingModules,
+ ImmutableSet<XTypeElement> missingModules,
BindingGraph graph,
DiagnosticReporter diagnosticReporter) {
diagnosticReporter.reportSubcomponentFactoryMethod(
@@ -153,7 +144,8 @@ final class SubcomponentFactoryMethodValidator implements BindingGraphPlugin {
.target()
.componentPath()
.currentComponent()
- .getQualifiedName(),
+ .className()
+ .canonicalName(),
Joiner.on(", ").join(missingModules));
}
}
diff --git a/java/dagger/internal/codegen/bootstrap/bootstrap_compiler_deploy.jar b/java/dagger/internal/codegen/bootstrap/bootstrap_compiler_deploy.jar
index b69dc65d5..69e859d4c 100644
--- a/java/dagger/internal/codegen/bootstrap/bootstrap_compiler_deploy.jar
+++ b/java/dagger/internal/codegen/bootstrap/bootstrap_compiler_deploy.jar
Binary files differ
diff --git a/java/dagger/internal/codegen/compileroption/BUILD b/java/dagger/internal/codegen/compileroption/BUILD
index ef39b34b4..6af5401d5 100644
--- a/java/dagger/internal/codegen/compileroption/BUILD
+++ b/java/dagger/internal/codegen/compileroption/BUILD
@@ -27,12 +27,12 @@ java_library(
deps = [
"//java/dagger:core",
"//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/producers",
- "@google_bazel_common//third_party/java/google_java_format",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
+ "//java/dagger/internal/codegen/xprocessing",
+ "//third_party/java/auto:common",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/jsr330_inject",
],
)
diff --git a/java/dagger/internal/codegen/compileroption/CompilerOptions.java b/java/dagger/internal/codegen/compileroption/CompilerOptions.java
index a0d1cda34..bd65d4309 100644
--- a/java/dagger/internal/codegen/compileroption/CompilerOptions.java
+++ b/java/dagger/internal/codegen/compileroption/CompilerOptions.java
@@ -16,7 +16,7 @@
package dagger.internal.codegen.compileroption;
-import javax.lang.model.element.TypeElement;
+import androidx.room.compiler.processing.XTypeElement;
import javax.tools.Diagnostic;
/** A collection of options that dictate how the compiler will run. */
@@ -24,6 +24,16 @@ public abstract class CompilerOptions {
public abstract boolean usesProducers();
/**
+ * Returns true if the experimental Android mode is enabled.
+ *
+ * <p><b>Warning: Do Not use! This flag is for internal, experimental use only!</b>
+ *
+ * <p>Issues related to this flag will not be supported. This flag could break your build, cause
+ * memory leaks in your app, or cause other unknown issues at runtime.
+ */
+ public abstract boolean experimentalMergedMode(XTypeElement element);
+
+ /**
* Returns true if the fast initialization flag, {@code fastInit}, is enabled.
*
* <p>If enabled, the generated code will attempt to optimize for fast component initialization.
@@ -31,7 +41,7 @@ public abstract class CompilerOptions {
* number of eagerly initialized fields at the cost of potential memory leaks and higher
* per-provision instantiation time.
*/
- public abstract boolean fastInit(TypeElement element);
+ public abstract boolean fastInit(XTypeElement element);
public abstract boolean formatGeneratedSource();
@@ -48,6 +58,15 @@ public abstract class CompilerOptions {
public abstract Diagnostic.Kind staticMemberValidationKind();
/**
+ * Returns {@code true} if the stacktrace should be included in the deferred error message.
+ *
+ * <p>The default for this option is {@code false}. The stacktrace is mostly useful for special
+ * debugging purposes to gather more information about where the exception was thrown from within
+ * Dagger's own processors.
+ */
+ public abstract boolean includeStacktraceWithDeferredErrorMessages();
+
+ /**
* If {@code true}, Dagger will generate factories and components even if some members-injected
* types have {@code private} or {@code static} {@code @Inject}-annotated members.
*
@@ -83,7 +102,7 @@ public abstract class CompilerOptions {
*
* @throws IllegalArgumentException if {@code element} is not a module or (sub)component
*/
- public abstract boolean pluginsVisitFullBindingGraphs(TypeElement element);
+ public abstract boolean pluginsVisitFullBindingGraphs(XTypeElement element);
public abstract Diagnostic.Kind moduleHasDifferentScopesDiagnosticKind();
@@ -91,8 +110,27 @@ public abstract class CompilerOptions {
public abstract boolean experimentalDaggerErrorMessages();
+ /**
+ * Returns {@code true} if strict superficial validation is enabled.
+ *
+ * <p>This option is enabled by default and allows Dagger to detect and fail if an element that
+ * supports being annotated with a scope or qualifier annotation is annotated with any
+ * unresolvable annotation types. This option is considered "strict" because in most cases we must
+ * fail for any unresolvable annotation types, not just scopes and qualifiers. In particular, if
+ * an annotation type is not resolvable, we don't have enough information to tell if it's a scope
+ * or qualifier, so we must fail for all unresolvable annotations.
+ *
+ * <p>This option can be disabled to allow easier migration from the legacy behavior of Dagger
+ * (i.e. versions less than or equal to 2.40.5). However, we will remove this option in a future
+ * version of Dagger.
+ *
+ * <p>Warning:Disabling this option means that Dagger may miss a scope or qualifier on a binding,
+ * leading to a (wrong) unscoped binding or a (wrong) unqualified binding, respectively.
+ */
+ public abstract boolean strictSuperficialValidation();
+
/** Returns the number of bindings allowed per shard. */
- public int keysPerComponentShard(TypeElement component) {
+ public int keysPerComponentShard(XTypeElement component) {
return 3500;
}
diff --git a/java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java b/java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java
index 06d15a236..3135d5cd7 100644
--- a/java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java
+++ b/java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java
@@ -19,6 +19,7 @@ package dagger.internal.codegen.compileroption;
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Sets.immutableEnumSet;
import static dagger.internal.codegen.compileroption.FeatureStatus.DISABLED;
import static dagger.internal.codegen.compileroption.FeatureStatus.ENABLED;
@@ -29,8 +30,10 @@ import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompil
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.FLOATING_BINDS_METHODS;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.FORMAT_GENERATED_SOURCE;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT;
+import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.INCLUDE_STACKTRACE_WITH_DEFERRED_ERROR_MESSAGES;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.PLUGINS_VISIT_FULL_BINDING_GRAPHS;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.STRICT_MULTIBINDING_VALIDATION;
+import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.STRICT_SUPERFICIAL_VALIDATION;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.VALIDATE_TRANSITIVE_COMPONENT_DEPENDENCIES;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.WARN_IF_INJECTION_FACTORY_NOT_GENERATED_UPSTREAM;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.WRITE_PRODUCER_NAME_IN_TOKEN;
@@ -50,13 +53,14 @@ import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Stream.concat;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.base.Ascii;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.producers.Produces;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
@@ -64,34 +68,33 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
-import javax.annotation.processing.ProcessingEnvironment;
import javax.inject.Inject;
-import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
-/** {@link CompilerOptions} for the given {@link ProcessingEnvironment}. */
+/** {@link CompilerOptions} for the given processor. */
public final class ProcessingEnvironmentCompilerOptions extends CompilerOptions {
// EnumOption<T> doesn't support integer inputs so just doing this as a 1-off for now.
private static final String KEYS_PER_COMPONENT_SHARD = "dagger.keysPerComponentShard";
- private final ProcessingEnvironment processingEnvironment;
- private final DaggerElements daggerElements;
+ private final XMessager messager;
+ private final Map<String, String> options;
+ private final DaggerElements elements;
private final Map<EnumOption<?>, Object> enumOptions = new HashMap<>();
private final Map<EnumOption<?>, ImmutableMap<String, ? extends Enum<?>>> allCommandLineOptions =
new HashMap<>();
@Inject
ProcessingEnvironmentCompilerOptions(
- ProcessingEnvironment processingEnvironment, DaggerElements daggerElements) {
- this.processingEnvironment = processingEnvironment;
- this.daggerElements = daggerElements;
+ XMessager messager, @ProcessingOptions Map<String, String> options, DaggerElements elements) {
+ this.messager = messager;
+ this.options = options;
+ this.elements = elements;
checkValid();
}
@Override
public boolean usesProducers() {
- return processingEnvironment.getElementUtils().getTypeElement(Produces.class.getCanonicalName())
- != null;
+ return elements.getTypeElement(TypeNames.PRODUCES) != null;
}
@Override
@@ -100,10 +103,37 @@ public final class ProcessingEnvironmentCompilerOptions extends CompilerOptions
}
@Override
- public boolean fastInit(TypeElement component) {
+ public boolean experimentalMergedMode(XTypeElement component) {
+ boolean isExperimental = experimentalMergedModeInternal();
+ if (isExperimental) {
+ checkState(
+ !fastInitInternal(component),
+ "Both fast init and experimental merged mode were turned on, please specify exactly one"
+ + " compilation mode.");
+ }
+ return isExperimental;
+ }
+
+ @Override
+ public boolean fastInit(XTypeElement component) {
+ boolean isFastInit = fastInitInternal(component);
+ if (isFastInit) {
+ checkState(
+ !experimentalMergedModeInternal(),
+ "Both fast init and experimental merged mode were turned on, please specify exactly one"
+ + " compilation mode.");
+ }
+ return isFastInit;
+ }
+
+ private boolean fastInitInternal(XTypeElement component) {
return isEnabled(FAST_INIT);
}
+ private boolean experimentalMergedModeInternal() {
+ return false;
+ }
+
@Override
public boolean formatGeneratedSource() {
return isEnabled(FORMAT_GENERATED_SOURCE);
@@ -130,6 +160,11 @@ public final class ProcessingEnvironmentCompilerOptions extends CompilerOptions
}
@Override
+ public boolean includeStacktraceWithDeferredErrorMessages() {
+ return isEnabled(INCLUDE_STACKTRACE_WITH_DEFERRED_ERROR_MESSAGES);
+ }
+
+ @Override
public boolean ignorePrivateAndStaticInjectionForComponent() {
return isEnabled(IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT);
}
@@ -155,7 +190,7 @@ public final class ProcessingEnvironmentCompilerOptions extends CompilerOptions
}
@Override
- public boolean pluginsVisitFullBindingGraphs(TypeElement component) {
+ public boolean pluginsVisitFullBindingGraphs(XTypeElement component) {
return isEnabled(PLUGINS_VISIT_FULL_BINDING_GRAPHS);
}
@@ -180,20 +215,23 @@ public final class ProcessingEnvironmentCompilerOptions extends CompilerOptions
}
@Override
- public int keysPerComponentShard(TypeElement component) {
- if (processingEnvironment.getOptions().containsKey(KEYS_PER_COMPONENT_SHARD)) {
+ public boolean strictSuperficialValidation() {
+ return isEnabled(STRICT_SUPERFICIAL_VALIDATION);
+ }
+
+ @Override
+ public int keysPerComponentShard(XTypeElement component) {
+ if (options.containsKey(KEYS_PER_COMPONENT_SHARD)) {
checkArgument(
- "dagger.internal.codegen".contentEquals(
- MoreElements.getPackage(component).getQualifiedName()),
+ component.getClassName().packageName().startsWith("dagger."),
"Cannot set %s. It is only meant for internal testing.", KEYS_PER_COMPONENT_SHARD);
- return Integer.parseInt(
- processingEnvironment.getOptions().get(KEYS_PER_COMPONENT_SHARD));
+ return Integer.parseInt(options.get(KEYS_PER_COMPONENT_SHARD));
}
return super.keysPerComponentShard(component);
}
private boolean isEnabled(KeyOnlyOption keyOnlyOption) {
- return processingEnvironment.getOptions().containsKey(keyOnlyOption.toString());
+ return options.containsKey(keyOnlyOption.toString());
}
private boolean isEnabled(Feature feature) {
@@ -206,9 +244,6 @@ public final class ProcessingEnvironmentCompilerOptions extends CompilerOptions
@SuppressWarnings("CheckReturnValue")
private ProcessingEnvironmentCompilerOptions checkValid() {
- for (KeyOnlyOption keyOnlyOption : KeyOnlyOption.values()) {
- isEnabled(keyOnlyOption);
- }
for (Feature feature : Feature.values()) {
parseOption(feature);
}
@@ -223,11 +258,9 @@ public final class ProcessingEnvironmentCompilerOptions extends CompilerOptions
}
private void noLongerRecognized(CommandLineOption commandLineOption) {
- if (processingEnvironment.getOptions().containsKey(commandLineOption.toString())) {
- processingEnvironment
- .getMessager()
- .printMessage(
- Diagnostic.Kind.WARNING, commandLineOption + " is no longer recognized by Dagger");
+ if (options.containsKey(commandLineOption.toString())) {
+ messager.printMessage(
+ Diagnostic.Kind.WARNING, commandLineOption + " is no longer recognized by Dagger");
}
}
@@ -290,6 +323,8 @@ public final class ProcessingEnvironmentCompilerOptions extends CompilerOptions
WARN_IF_INJECTION_FACTORY_NOT_GENERATED_UPSTREAM,
+ INCLUDE_STACKTRACE_WITH_DEFERRED_ERROR_MESSAGES,
+
IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT,
EXPERIMENTAL_AHEAD_OF_TIME_SUBCOMPONENTS,
@@ -306,6 +341,8 @@ public final class ProcessingEnvironmentCompilerOptions extends CompilerOptions
STRICT_MULTIBINDING_VALIDATION,
+ STRICT_SUPERFICIAL_VALIDATION(ENABLED),
+
VALIDATE_TRANSITIVE_COMPONENT_DEPENDENCIES(ENABLED)
;
@@ -458,13 +495,11 @@ public final class ProcessingEnvironmentCompilerOptions extends CompilerOptions
private void reportUseOfDifferentNamesForOption(
Diagnostic.Kind diagnosticKind, EnumOption<?> option, ImmutableSet<String> usedNames) {
- processingEnvironment
- .getMessager()
- .printMessage(
- diagnosticKind,
- String.format(
- "Only one of the equivalent options (%s) should be used; prefer -A%s",
- usedNames.stream().map(name -> "-A" + name).collect(joining(", ")), option));
+ messager.printMessage(
+ diagnosticKind,
+ String.format(
+ "Only one of the equivalent options (%s) should be used; prefer -A%s",
+ usedNames.stream().map(name -> "-A" + name).collect(joining(", ")), option));
}
private <T extends Enum<T>> ImmutableMap<String, T> parseOptionWithAllNames(
@@ -486,12 +521,10 @@ public final class ProcessingEnvironmentCompilerOptions extends CompilerOptions
}
private <T extends Enum<T>> Optional<T> parseOptionWithName(EnumOption<T> option, String key) {
- checkArgument(processingEnvironment.getOptions().containsKey(key), "key %s not found", key);
- String stringValue = processingEnvironment.getOptions().get(key);
+ checkArgument(options.containsKey(key), "key %s not found", key);
+ String stringValue = options.get(key);
if (stringValue == null) {
- processingEnvironment
- .getMessager()
- .printMessage(Diagnostic.Kind.ERROR, "Processor option -A" + key + " needs a value");
+ messager.printMessage(Diagnostic.Kind.ERROR, "Processor option -A" + key + " needs a value");
} else {
try {
T value =
@@ -502,19 +535,16 @@ public final class ProcessingEnvironmentCompilerOptions extends CompilerOptions
} catch (IllegalArgumentException e) {
// handled below
}
- processingEnvironment
- .getMessager()
- .printMessage(
- Diagnostic.Kind.ERROR,
- String.format(
- "Processor option -A%s may only have the values %s "
- + "(case insensitive), found: %s",
- key, option.validValues(), stringValue));
+ messager.printMessage(
+ Diagnostic.Kind.ERROR,
+ String.format(
+ "Processor option -A%s may only have the values %s (case insensitive), found: %s",
+ key, option.validValues(), stringValue));
}
return Optional.empty();
}
private Stream<String> getUsedNames(CommandLineOption option) {
- return option.allNames().filter(name -> processingEnvironment.getOptions().containsKey(name));
+ return option.allNames().filter(options::containsKey);
}
}
diff --git a/java/dagger/internal/codegen/componentgenerator/BUILD b/java/dagger/internal/codegen/componentgenerator/BUILD
index d898d4d91..859bc0d0b 100644
--- a/java/dagger/internal/codegen/componentgenerator/BUILD
+++ b/java/dagger/internal/codegen/componentgenerator/BUILD
@@ -25,19 +25,15 @@ java_library(
"//java/dagger:core",
"//java/dagger/internal/codegen/base",
"//java/dagger/internal/codegen/binding",
- "//java/dagger/internal/codegen/compileroption",
- "//java/dagger/internal/codegen/extension",
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/kotlin",
"//java/dagger/internal/codegen/langmodel",
"//java/dagger/internal/codegen/writing",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/producers",
- "//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
+ "//java/dagger/internal/codegen/xprocessing",
+ "//third_party/java/auto:common",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
+ "//third_party/java/jsr330_inject",
],
)
diff --git a/java/dagger/internal/codegen/componentgenerator/ComponentGenerator.java b/java/dagger/internal/codegen/componentgenerator/ComponentGenerator.java
index 098da81e6..5442b6481 100644
--- a/java/dagger/internal/codegen/componentgenerator/ComponentGenerator.java
+++ b/java/dagger/internal/codegen/componentgenerator/ComponentGenerator.java
@@ -17,52 +17,56 @@
package dagger.internal.codegen.componentgenerator;
import static com.google.common.base.Verify.verify;
-import static dagger.internal.codegen.binding.SourceFiles.classFileName;
+import static dagger.internal.codegen.writing.ComponentNames.getRootComponentClassName;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler;
import com.google.common.collect.ImmutableList;
-import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeSpec;
import dagger.Component;
import dagger.internal.codegen.base.SourceFileGenerator;
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.writing.ComponentImplementation;
-import javax.annotation.processing.Filer;
+import java.util.Optional;
import javax.inject.Inject;
import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
/** Generates the implementation of the abstract types annotated with {@link Component}. */
final class ComponentGenerator extends SourceFileGenerator<BindingGraph> {
- private final ComponentImplementationFactory componentImplementationFactory;
+ private final TopLevelImplementationComponent.Factory topLevelImplementationComponentFactory;
@Inject
ComponentGenerator(
- Filer filer,
+ XFiler filer,
DaggerElements elements,
SourceVersion sourceVersion,
- ComponentImplementationFactory componentImplementationFactory) {
+ TopLevelImplementationComponent.Factory topLevelImplementationComponentFactory) {
super(filer, elements, sourceVersion);
- this.componentImplementationFactory = componentImplementationFactory;
- }
-
- static ClassName componentName(TypeElement componentDefinitionType) {
- ClassName componentName = ClassName.get(componentDefinitionType);
- return ClassName.get(componentName.packageName(), "Dagger" + classFileName(componentName));
+ this.topLevelImplementationComponentFactory = topLevelImplementationComponentFactory;
}
@Override
- public Element originatingElement(BindingGraph input) {
+ public XElement originatingElement(BindingGraph input) {
return input.componentTypeElement();
}
@Override
public ImmutableList<TypeSpec.Builder> topLevelTypes(BindingGraph bindingGraph) {
ComponentImplementation componentImplementation =
- componentImplementationFactory.createComponentImplementation(bindingGraph);
+ topLevelImplementationComponentFactory
+ .create(bindingGraph)
+ .currentImplementationSubcomponentBuilder()
+ .bindingGraph(bindingGraph)
+ .parentImplementation(Optional.empty())
+ .parentRequestRepresentations(Optional.empty())
+ .parentRequirementExpressions(Optional.empty())
+ .build()
+ .componentImplementation();
verify(
- componentImplementation.name().equals(componentName(bindingGraph.componentTypeElement())));
- return ImmutableList.of(componentImplementation.generate());
+ componentImplementation
+ .name()
+ .equals(getRootComponentClassName(bindingGraph.componentDescriptor())));
+ return ImmutableList.of(componentImplementation.generate().toBuilder());
}
}
diff --git a/java/dagger/internal/codegen/componentgenerator/ComponentHjarGenerator.java b/java/dagger/internal/codegen/componentgenerator/ComponentHjarGenerator.java
index c8b8c97c3..7bd9ddcaa 100644
--- a/java/dagger/internal/codegen/componentgenerator/ComponentHjarGenerator.java
+++ b/java/dagger/internal/codegen/componentgenerator/ComponentHjarGenerator.java
@@ -16,22 +16,27 @@
package dagger.internal.codegen.componentgenerator;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_CAMEL;
import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Iterables.getOnlyElement;
import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.BUILDER;
-import static dagger.internal.codegen.componentgenerator.ComponentGenerator.componentName;
+import static dagger.internal.codegen.base.ComponentCreatorKind.BUILDER;
import static dagger.internal.codegen.javapoet.TypeSpecs.addSupertype;
import static dagger.internal.codegen.langmodel.Accessibility.isElementAccessibleFrom;
-import static javax.lang.model.element.Modifier.ABSTRACT;
+import static dagger.internal.codegen.writing.ComponentNames.getRootComponentClassName;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static dagger.internal.codegen.xprocessing.XTypeElements.getAllUnimplementedMethods;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.base.Ascii;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
@@ -39,25 +44,19 @@ import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
-import dagger.BindsInstance;
+import dagger.internal.codegen.base.ComponentCreatorKind;
import dagger.internal.codegen.base.SourceFileGenerator;
import dagger.internal.codegen.binding.ComponentCreatorDescriptor;
-import dagger.internal.codegen.binding.ComponentCreatorKind;
import dagger.internal.codegen.binding.ComponentDescriptor;
import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
+import dagger.internal.codegen.binding.MethodSignature;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.producers.internal.CancellationListener;
+import dagger.internal.codegen.xprocessing.MethodSpecs;
import java.util.Set;
import java.util.stream.Stream;
-import javax.annotation.processing.Filer;
import javax.inject.Inject;
import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
/**
* A component generator that emits only API, without any actual implementation.
@@ -73,40 +72,28 @@ import javax.lang.model.type.DeclaredType;
* normal step. Method bodies are omitted as Turbine ignores them entirely.
*/
final class ComponentHjarGenerator extends SourceFileGenerator<ComponentDescriptor> {
- private final DaggerElements elements;
- private final DaggerTypes types;
- private final KotlinMetadataUtil metadataUtil;
-
@Inject
- ComponentHjarGenerator(
- Filer filer,
- DaggerElements elements,
- DaggerTypes types,
- SourceVersion sourceVersion,
- KotlinMetadataUtil metadataUtil) {
+ ComponentHjarGenerator(XFiler filer, DaggerElements elements, SourceVersion sourceVersion) {
super(filer, elements, sourceVersion);
- this.elements = elements;
- this.types = types;
- this.metadataUtil = metadataUtil;
}
@Override
- public Element originatingElement(ComponentDescriptor input) {
+ public XElement originatingElement(ComponentDescriptor input) {
return input.typeElement();
}
@Override
public ImmutableList<TypeSpec.Builder> topLevelTypes(ComponentDescriptor componentDescriptor) {
- ClassName generatedTypeName = componentName(componentDescriptor.typeElement());
+ ClassName generatedTypeName = getRootComponentClassName(componentDescriptor);
TypeSpec.Builder generatedComponent =
TypeSpec.classBuilder(generatedTypeName)
.addModifiers(FINAL)
.addMethod(privateConstructor());
- if (componentDescriptor.typeElement().getModifiers().contains(PUBLIC)) {
+ if (componentDescriptor.typeElement().isPublic()) {
generatedComponent.addModifiers(PUBLIC);
}
- TypeElement componentElement = componentDescriptor.typeElement();
+ XTypeElement componentElement = componentDescriptor.typeElement();
addSupertype(generatedComponent, componentElement);
TypeName builderMethodReturnType;
@@ -114,7 +101,7 @@ final class ComponentHjarGenerator extends SourceFileGenerator<ComponentDescript
boolean noArgFactoryMethod;
if (componentDescriptor.creatorDescriptor().isPresent()) {
ComponentCreatorDescriptor creatorDescriptor = componentDescriptor.creatorDescriptor().get();
- builderMethodReturnType = ClassName.get(creatorDescriptor.typeElement());
+ builderMethodReturnType = creatorDescriptor.typeElement().getClassName();
creatorKind = creatorDescriptor.kind();
noArgFactoryMethod = creatorDescriptor.factoryParameters().isEmpty();
} else {
@@ -122,7 +109,7 @@ final class ComponentHjarGenerator extends SourceFileGenerator<ComponentDescript
TypeSpec.classBuilder("Builder")
.addModifiers(STATIC, FINAL)
.addMethod(privateConstructor());
- if (componentDescriptor.typeElement().getModifiers().contains(PUBLIC)) {
+ if (componentDescriptor.typeElement().isPublic()) {
builder.addModifiers(PUBLIC);
}
@@ -142,21 +129,18 @@ final class ComponentHjarGenerator extends SourceFileGenerator<ComponentDescript
if (noArgFactoryMethod
&& !hasBindsInstanceMethods(componentDescriptor)
&& componentRequirements(componentDescriptor)
- .noneMatch(
- requirement -> requirement.requiresAPassedInstance(elements, metadataUtil))) {
+ .noneMatch(ComponentRequirement::requiresAPassedInstance)) {
generatedComponent.addMethod(createMethod(componentDescriptor));
}
- DeclaredType componentType = MoreTypes.asDeclared(componentElement.asType());
+ XType componentType = componentElement.getType();
// TODO(ronshapiro): unify with ComponentImplementationBuilder
Set<MethodSignature> methodSignatures =
Sets.newHashSetWithExpectedSize(componentDescriptor.componentMethods().size());
componentDescriptor.componentMethods().stream()
.filter(
- method -> {
- return methodSignatures.add(
- MethodSignature.forComponentMethod(method, componentType, types));
- })
+ method ->
+ methodSignatures.add(MethodSignature.forComponentMethod(method, componentType)))
.forEach(
method ->
generatedComponent.addMethod(
@@ -164,16 +148,15 @@ final class ComponentHjarGenerator extends SourceFileGenerator<ComponentDescript
if (componentDescriptor.isProduction()) {
generatedComponent
- .addSuperinterface(ClassName.get(CancellationListener.class))
+ .addSuperinterface(TypeNames.CANCELLATION_LISTENER)
.addMethod(onProducerFutureCancelledMethod());
}
return ImmutableList.of(generatedComponent);
}
- private MethodSpec emptyComponentMethod(TypeElement typeElement, ExecutableElement baseMethod) {
- return MethodSpec.overriding(baseMethod, MoreTypes.asDeclared(typeElement.asType()), types)
- .build();
+ private MethodSpec emptyComponentMethod(XTypeElement typeElement, XMethodElement baseMethod) {
+ return MethodSpecs.overriding(baseMethod, typeElement.getType()).build();
}
private static MethodSpec privateConstructor() {
@@ -194,40 +177,32 @@ final class ComponentHjarGenerator extends SourceFileGenerator<ComponentDescript
component.modules().stream()
.filter(
module ->
- !module.moduleElement().getModifiers().contains(ABSTRACT)
+ !module.moduleElement().isAbstract()
&& isElementAccessibleFrom(
module.moduleElement(),
- ClassName.get(component.typeElement()).packageName()))
- .map(module -> ComponentRequirement.forModule(module.moduleElement().asType())));
+ component.typeElement().getClassName().packageName()))
+ .map(module -> ComponentRequirement.forModule(module.moduleElement().getType())));
}
private boolean hasBindsInstanceMethods(ComponentDescriptor componentDescriptor) {
return componentDescriptor.creatorDescriptor().isPresent()
- && elements
- .getUnimplementedMethods(componentDescriptor.creatorDescriptor().get().typeElement())
+ && getAllUnimplementedMethods(componentDescriptor.creatorDescriptor().get().typeElement())
.stream()
.anyMatch(method -> isBindsInstance(method));
}
- private static boolean isBindsInstance(ExecutableElement method) {
- if (isAnnotationPresent(method, BindsInstance.class)) {
- return true;
- }
-
- if (method.getParameters().size() == 1) {
- return isAnnotationPresent(method.getParameters().get(0), BindsInstance.class);
- }
-
- return false;
+ private static boolean isBindsInstance(XMethodElement method) {
+ return method.hasAnnotation(TypeNames.BINDS_INSTANCE)
+ || (method.getParameters().size() == 1
+ && getOnlyElement(method.getParameters()).hasAnnotation(TypeNames.BINDS_INSTANCE));
}
private static MethodSpec builderSetterMethod(
- TypeElement componentRequirement, ClassName builderClass) {
- String simpleName =
- UPPER_CAMEL.to(LOWER_CAMEL, componentRequirement.getSimpleName().toString());
+ XTypeElement componentRequirement, ClassName builderClass) {
+ String simpleName = UPPER_CAMEL.to(LOWER_CAMEL, getSimpleName(componentRequirement));
return MethodSpec.methodBuilder(simpleName)
.addModifiers(PUBLIC)
- .addParameter(ClassName.get(componentRequirement), simpleName)
+ .addParameter(componentRequirement.getClassName(), simpleName)
.returns(builderClass)
.build();
}
@@ -235,7 +210,7 @@ final class ComponentHjarGenerator extends SourceFileGenerator<ComponentDescript
private static MethodSpec builderBuildMethod(ComponentDescriptor component) {
return MethodSpec.methodBuilder("build")
.addModifiers(PUBLIC)
- .returns(ClassName.get(component.typeElement()))
+ .returns(component.typeElement().getClassName())
.build();
}
@@ -250,7 +225,7 @@ final class ComponentHjarGenerator extends SourceFileGenerator<ComponentDescript
private static MethodSpec createMethod(ComponentDescriptor componentDescriptor) {
return MethodSpec.methodBuilder("create")
.addModifiers(PUBLIC, STATIC)
- .returns(ClassName.get(componentDescriptor.typeElement()))
+ .returns(componentDescriptor.typeElement().getClassName())
.build();
}
diff --git a/java/dagger/internal/codegen/componentgenerator/ComponentImplementationBuilder.java b/java/dagger/internal/codegen/componentgenerator/ComponentImplementationBuilder.java
deleted file mode 100644
index 2be7d3861..000000000
--- a/java/dagger/internal/codegen/componentgenerator/ComponentImplementationBuilder.java
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.componentgenerator;
-
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.common.base.Preconditions.checkState;
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.BUILDER;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
-import static dagger.internal.codegen.javapoet.CodeBlocks.parameterNames;
-import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.BUILDER_METHOD;
-import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.CANCELLATION_LISTENER_METHOD;
-import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.COMPONENT_METHOD;
-import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.CONSTRUCTOR;
-import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.INITIALIZE_METHOD;
-import static dagger.internal.codegen.writing.ComponentImplementation.TypeSpecKind.COMPONENT_CREATOR;
-import static dagger.internal.codegen.writing.ComponentImplementation.TypeSpecKind.SUBCOMPONENT;
-import static dagger.producers.CancellationPolicy.Propagation.PROPAGATE;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimaps;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.Preconditions;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ComponentCreatorDescriptor;
-import dagger.internal.codegen.binding.ComponentCreatorKind;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.javapoet.AnnotationSpecs;
-import dagger.internal.codegen.javapoet.CodeBlocks;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.internal.codegen.writing.ComponentBindingExpressions;
-import dagger.internal.codegen.writing.ComponentCreatorImplementation;
-import dagger.internal.codegen.writing.ComponentImplementation;
-import dagger.internal.codegen.writing.ComponentRequirementExpressions;
-import dagger.internal.codegen.writing.ParentComponent;
-import dagger.model.Key;
-import dagger.producers.internal.CancellationListener;
-import dagger.producers.internal.Producers;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.function.Function;
-import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.DeclaredType;
-
-/** A builder of {@link ComponentImplementation}s. */
-// This only needs to be public because it's referenced in an entry point.
-public final class ComponentImplementationBuilder {
- private static final String MAY_INTERRUPT_IF_RUNNING = "mayInterruptIfRunning";
-
- /**
- * How many statements per {@code initialize()} or {@code onProducerFutureCancelled()} method
- * before they get partitioned.
- */
- private static final int STATEMENTS_PER_METHOD = 100;
-
- private static final String CANCELLATION_LISTENER_METHOD_NAME = "onProducerFutureCancelled";
-
- private final Optional<ComponentImplementationBuilder> parent;
- private final BindingGraph graph;
- private final ComponentBindingExpressions bindingExpressions;
- private final ComponentRequirementExpressions componentRequirementExpressions;
- private final ComponentImplementation componentImplementation;
- private final ComponentCreatorImplementationFactory componentCreatorImplementationFactory;
- private final TopLevelImplementationComponent topLevelImplementationComponent;
- private final DaggerTypes types;
- private final DaggerElements elements;
- private final KotlinMetadataUtil metadataUtil;
- private boolean done;
-
- @Inject
- ComponentImplementationBuilder(
- @ParentComponent Optional<ComponentImplementationBuilder> parent,
- BindingGraph graph,
- ComponentBindingExpressions bindingExpressions,
- ComponentRequirementExpressions componentRequirementExpressions,
- ComponentImplementation componentImplementation,
- ComponentCreatorImplementationFactory componentCreatorImplementationFactory,
- TopLevelImplementationComponent topLevelImplementationComponent,
- DaggerTypes types,
- DaggerElements elements,
- KotlinMetadataUtil metadataUtil) {
- this.parent = parent;
- this.graph = graph;
- this.bindingExpressions = bindingExpressions;
- this.componentRequirementExpressions = componentRequirementExpressions;
- this.componentImplementation = componentImplementation;
- this.componentCreatorImplementationFactory = componentCreatorImplementationFactory;
- this.types = types;
- this.elements = elements;
- this.topLevelImplementationComponent = topLevelImplementationComponent;
- this.metadataUtil = metadataUtil;
- }
-
- /**
- * Returns a {@link ComponentImplementation} for this component. This is only intended to be
- * called once (and will throw on successive invocations). If the component must be regenerated,
- * use a new instance.
- */
- ComponentImplementation build() {
- checkState(
- !done,
- "ComponentImplementationBuilder has already built the ComponentImplementation for [%s].",
- componentImplementation.name());
- setSupertype();
-
- componentCreatorImplementationFactory.create()
- .map(ComponentCreatorImplementation::spec)
- .ifPresent(this::addCreatorClass);
-
- elements
- .getLocalAndInheritedMethods(graph.componentTypeElement())
- .forEach(method -> componentImplementation.claimMethodName(method.getSimpleName()));
-
- addFactoryMethods();
- addInterfaceMethods();
- addChildComponents();
-
- addConstructorAndInitializationMethods();
-
- if (graph.componentDescriptor().isProduction()) {
- addCancellationListenerImplementation();
- }
-
- done = true;
- return componentImplementation;
- }
-
- /** Set the supertype for this generated class. */
- private void setSupertype() {
- componentImplementation.addSupertype(graph.componentTypeElement());
- }
-
- private void addCreatorClass(TypeSpec creator) {
- if (parent.isPresent()) {
- // In an inner implementation of a subcomponent the creator is a peer class.
- parent.get().componentImplementation.addType(SUBCOMPONENT, creator);
- } else {
- componentImplementation.addType(COMPONENT_CREATOR, creator);
- }
- }
-
- private void addFactoryMethods() {
- if (parent.isPresent()) {
- graph.factoryMethod().ifPresent(this::createSubcomponentFactoryMethod);
- } else {
- createRootComponentFactoryMethod();
- }
- }
-
- private void addInterfaceMethods() {
- // Each component method may have been declared by several supertypes. We want to implement
- // only one method for each distinct signature.
- ImmutableListMultimap<MethodSignature, ComponentMethodDescriptor> componentMethodsBySignature =
- Multimaps.index(graph.componentDescriptor().entryPointMethods(), this::getMethodSignature);
- for (List<ComponentMethodDescriptor> methodsWithSameSignature :
- Multimaps.asMap(componentMethodsBySignature).values()) {
- ComponentMethodDescriptor anyOneMethod = methodsWithSameSignature.stream().findAny().get();
- MethodSpec methodSpec = bindingExpressions.getComponentMethod(anyOneMethod);
-
- componentImplementation.addMethod(COMPONENT_METHOD, methodSpec);
- }
- }
-
- private void addCancellationListenerImplementation() {
- componentImplementation.addSupertype(elements.getTypeElement(CancellationListener.class));
- componentImplementation.claimMethodName(CANCELLATION_LISTENER_METHOD_NAME);
-
- ImmutableList<ParameterSpec> parameters =
- ImmutableList.of(ParameterSpec.builder(boolean.class, MAY_INTERRUPT_IF_RUNNING).build());
-
- MethodSpec.Builder methodBuilder =
- methodBuilder(CANCELLATION_LISTENER_METHOD_NAME)
- .addModifiers(PUBLIC)
- .addAnnotation(Override.class)
- .addParameters(parameters);
-
- ImmutableList<CodeBlock> cancellationStatements = cancellationStatements();
-
- if (cancellationStatements.size() < STATEMENTS_PER_METHOD) {
- methodBuilder.addCode(CodeBlocks.concat(cancellationStatements)).build();
- } else {
- ImmutableList<MethodSpec> cancelProducersMethods =
- createPartitionedMethods(
- "cancelProducers",
- parameters,
- cancellationStatements,
- methodName -> methodBuilder(methodName).addModifiers(PRIVATE));
- for (MethodSpec cancelProducersMethod : cancelProducersMethods) {
- methodBuilder.addStatement("$N($L)", cancelProducersMethod, MAY_INTERRUPT_IF_RUNNING);
- componentImplementation.addMethod(CANCELLATION_LISTENER_METHOD, cancelProducersMethod);
- }
- }
-
- cancelParentStatement().ifPresent(methodBuilder::addCode);
-
- componentImplementation.addMethod(CANCELLATION_LISTENER_METHOD, methodBuilder.build());
- }
-
- private ImmutableList<CodeBlock> cancellationStatements() {
- // Reversing should order cancellations starting from entry points and going down to leaves
- // rather than the other way around. This shouldn't really matter but seems *slightly*
- // preferable because:
- // When a future that another future depends on is cancelled, that cancellation will propagate
- // up the future graph toward the entry point. Cancelling in reverse order should ensure that
- // everything that depends on a particular node has already been cancelled when that node is
- // cancelled, so there's no need to propagate. Otherwise, when we cancel a leaf node, it might
- // propagate through most of the graph, making most of the cancel calls that follow in the
- // onProducerFutureCancelled method do nothing.
- ImmutableList<Key> cancellationKeys =
- componentImplementation.getCancellableProducerKeys().reverse();
-
- ImmutableList.Builder<CodeBlock> cancellationStatements = ImmutableList.builder();
- for (Key cancellationKey : cancellationKeys) {
- cancellationStatements.add(
- CodeBlock.of(
- "$T.cancel($L, $N);",
- Producers.class,
- bindingExpressions
- .getDependencyExpression(
- bindingRequest(cancellationKey, FrameworkType.PRODUCER_NODE),
- componentImplementation.name())
- .codeBlock(),
- MAY_INTERRUPT_IF_RUNNING));
- }
- return cancellationStatements.build();
- }
-
- private Optional<CodeBlock> cancelParentStatement() {
- if (!shouldPropagateCancellationToParent()) {
- return Optional.empty();
- }
- return Optional.of(
- CodeBlock.builder()
- .addStatement(
- "$T.this.$N($N)",
- parent.get().componentImplementation.name(),
- CANCELLATION_LISTENER_METHOD_NAME,
- MAY_INTERRUPT_IF_RUNNING)
- .build());
- }
-
- private boolean shouldPropagateCancellationToParent() {
- return parent.isPresent()
- && parent
- .get()
- .componentImplementation
- .componentDescriptor()
- .cancellationPolicy()
- .map(policy -> policy.fromSubcomponents().equals(PROPAGATE))
- .orElse(false);
- }
-
- private MethodSignature getMethodSignature(ComponentMethodDescriptor method) {
- return MethodSignature.forComponentMethod(
- method, MoreTypes.asDeclared(graph.componentTypeElement().asType()), types);
- }
-
- private void addChildComponents() {
- for (BindingGraph subgraph : graph.subgraphs()) {
- componentImplementation.addType(SUBCOMPONENT, childComponent(subgraph));
- }
- }
-
- private TypeSpec childComponent(BindingGraph childGraph) {
- return topLevelImplementationComponent
- .currentImplementationSubcomponentBuilder()
- .componentImplementation(subcomponent(childGraph))
- .bindingGraph(childGraph)
- .parentBuilder(Optional.of(this))
- .parentBindingExpressions(Optional.of(bindingExpressions))
- .parentRequirementExpressions(Optional.of(componentRequirementExpressions))
- .build()
- .componentImplementationBuilder()
- .build()
- .generate()
- .build();
- }
-
- /** Creates an inner subcomponent implementation. */
- private ComponentImplementation subcomponent(BindingGraph childGraph) {
- return componentImplementation.childComponentImplementation(childGraph);
- }
-
- /** Creates and adds the constructor and methods needed for initializing the component. */
- private void addConstructorAndInitializationMethods() {
- MethodSpec.Builder constructor = constructorBuilder().addModifiers(PRIVATE);
- implementInitializationMethod(constructor, initializationParameters());
- componentImplementation.addMethod(CONSTRUCTOR, constructor.build());
- }
-
- /** Adds parameters and code to the given {@code initializationMethod}. */
- private void implementInitializationMethod(
- MethodSpec.Builder initializationMethod,
- ImmutableMap<ComponentRequirement, ParameterSpec> initializationParameters) {
- initializationMethod.addParameters(initializationParameters.values());
- initializationMethod.addCode(
- CodeBlocks.concat(componentImplementation.getComponentRequirementInitializations()));
- addInitializeMethods(initializationMethod, initializationParameters.values().asList());
- }
-
- /**
- * Adds any necessary {@code initialize} methods to the component and adds calls to them to the
- * given {@code callingMethod}.
- */
- private void addInitializeMethods(
- MethodSpec.Builder callingMethod, ImmutableList<ParameterSpec> parameters) {
- // TODO(cgdecker): It's not the case that each initialize() method has need for all of the
- // given parameters. In some cases, those parameters may have already been assigned to fields
- // which could be referenced instead. In other cases, an initialize method may just not need
- // some of the parameters because the set of initializations in that partition does not
- // include any reference to them. Right now, the Dagger code has no way of getting that
- // information because, among other things, componentImplementation.getImplementations() just
- // returns a bunch of CodeBlocks with no semantic information. Additionally, we may not know
- // yet whether a field will end up needing to be created for a specific requirement, and we
- // don't want to create a field that ends up only being used during initialization.
- CodeBlock args = parameterNames(parameters);
- ImmutableList<MethodSpec> methods =
- createPartitionedMethods(
- "initialize",
- makeFinal(parameters),
- componentImplementation.getInitializations(),
- methodName ->
- methodBuilder(methodName)
- .addModifiers(PRIVATE)
- /* TODO(gak): Strictly speaking, we only need the suppression here if we are
- * also initializing a raw field in this method, but the structure of this
- * code makes it awkward to pass that bit through. This will be cleaned up
- * when we no longer separate fields and initialization as we do now. */
- .addAnnotation(AnnotationSpecs.suppressWarnings(UNCHECKED)));
- for (MethodSpec method : methods) {
- callingMethod.addStatement("$N($L)", method, args);
- componentImplementation.addMethod(INITIALIZE_METHOD, method);
- }
- }
-
- /**
- * Creates one or more methods, all taking the given {@code parameters}, which partition the given
- * list of {@code statements} among themselves such that no method has more than {@code
- * STATEMENTS_PER_METHOD} statements in it and such that the returned methods, if called in order,
- * will execute the {@code statements} in the given order.
- */
- private ImmutableList<MethodSpec> createPartitionedMethods(
- String methodName,
- Iterable<ParameterSpec> parameters,
- List<CodeBlock> statements,
- Function<String, MethodSpec.Builder> methodBuilderCreator) {
- return Lists.partition(statements, STATEMENTS_PER_METHOD).stream()
- .map(
- partition ->
- methodBuilderCreator
- .apply(componentImplementation.getUniqueMethodName(methodName))
- .addParameters(parameters)
- .addCode(CodeBlocks.concat(partition))
- .build())
- .collect(toImmutableList());
- }
-
- /** Returns the given parameters with a final modifier added. */
- private final ImmutableList<ParameterSpec> makeFinal(Collection<ParameterSpec> parameters) {
- return parameters.stream()
- .map(param -> param.toBuilder().addModifiers(FINAL).build())
- .collect(toImmutableList());
- }
-
- /**
- * Returns the parameters for the constructor as a map from the requirement the parameter fulfills
- * to the spec for the parameter.
- */
- private final ImmutableMap<ComponentRequirement, ParameterSpec> initializationParameters() {
- Map<ComponentRequirement, ParameterSpec> parameters;
- if (componentImplementation.componentDescriptor().hasCreator()) {
- parameters = Maps.toMap(graph.componentRequirements(), ComponentRequirement::toParameterSpec);
- } else if (graph.factoryMethod().isPresent()) {
- parameters = getFactoryMethodParameters(graph);
- } else {
- throw new AssertionError(
- "Expected either a component creator or factory method but found neither.");
- }
-
- return renameParameters(parameters);
- }
-
- /**
- * Renames the given parameters to guarantee their names do not conflict with fields in the
- * component to ensure that a parameter is never referenced where a reference to a field was
- * intended.
- */
- // TODO(cgdecker): This is a bit kludgy; it would be preferable to either qualify the field
- // references with "this." or "super." when needed to disambiguate between field and parameter,
- // but that would require more context than is currently available when the code referencing a
- // field is generated.
- private ImmutableMap<ComponentRequirement, ParameterSpec> renameParameters(
- Map<ComponentRequirement, ParameterSpec> parameters) {
- return ImmutableMap.copyOf(
- Maps.transformEntries(
- parameters,
- (requirement, parameter) ->
- renameParameter(
- parameter,
- componentImplementation.getParameterName(requirement, parameter.name))));
- }
-
- private ParameterSpec renameParameter(ParameterSpec parameter, String newName) {
- return ParameterSpec.builder(parameter.type, newName)
- .addAnnotations(parameter.annotations)
- .addModifiers(parameter.modifiers)
- .build();
- }
-
- private void createRootComponentFactoryMethod() {
- checkState(!parent.isPresent());
- // Top-level components have a static method that returns a builder or factory for the
- // component. If the user defined a @Component.Builder or @Component.Factory, an
- // implementation of their type is returned. Otherwise, an autogenerated Builder type is
- // returned.
- // TODO(cgdecker): Replace this abomination with a small class?
- // Better yet, change things so that an autogenerated builder type has a descriptor of sorts
- // just like a user-defined creator type.
- ComponentCreatorKind creatorKind;
- ClassName creatorType;
- String factoryMethodName;
- boolean noArgFactoryMethod;
- Optional<ComponentCreatorDescriptor> creatorDescriptor =
- graph.componentDescriptor().creatorDescriptor();
- if (creatorDescriptor.isPresent()) {
- ComponentCreatorDescriptor descriptor = creatorDescriptor.get();
- creatorKind = descriptor.kind();
- creatorType = ClassName.get(descriptor.typeElement());
- factoryMethodName = descriptor.factoryMethod().getSimpleName().toString();
- noArgFactoryMethod = descriptor.factoryParameters().isEmpty();
- } else {
- creatorKind = BUILDER;
- creatorType = componentImplementation.getCreatorName();
- factoryMethodName = "build";
- noArgFactoryMethod = true;
- }
-
- MethodSpec creatorFactoryMethod =
- methodBuilder(creatorKind.methodName())
- .addModifiers(PUBLIC, STATIC)
- .returns(creatorType)
- .addStatement("return new $T()", componentImplementation.getCreatorName())
- .build();
- componentImplementation.addMethod(BUILDER_METHOD, creatorFactoryMethod);
- if (noArgFactoryMethod && canInstantiateAllRequirements()) {
- componentImplementation.addMethod(
- BUILDER_METHOD,
- methodBuilder("create")
- .returns(ClassName.get(graph.componentTypeElement()))
- .addModifiers(PUBLIC, STATIC)
- .addStatement("return new $L().$L()", creatorKind.typeName(), factoryMethodName)
- .build());
- }
- }
-
- /** {@code true} if all of the graph's required dependencies can be automatically constructed */
- private boolean canInstantiateAllRequirements() {
- return !Iterables.any(
- graph.componentRequirements(),
- dependency -> dependency.requiresAPassedInstance(elements, metadataUtil));
- }
-
- private void createSubcomponentFactoryMethod(ExecutableElement factoryMethod) {
- checkState(parent.isPresent());
- Collection<ParameterSpec> params = getFactoryMethodParameters(graph).values();
- MethodSpec.Builder method = MethodSpec.overriding(factoryMethod, parentType(), types);
- params.forEach(
- param -> method.addStatement("$T.checkNotNull($N)", Preconditions.class, param));
- method.addStatement(
- "return new $T($L)", componentImplementation.name(), parameterNames(params));
-
- parent.get().componentImplementation.addMethod(COMPONENT_METHOD, method.build());
- }
-
- private DeclaredType parentType() {
- return asDeclared(parent.get().graph.componentTypeElement().asType());
- }
- /**
- * Returns the map of {@link ComponentRequirement}s to {@link ParameterSpec}s for the given
- * graph's factory method.
- */
- private static Map<ComponentRequirement, ParameterSpec> getFactoryMethodParameters(
- BindingGraph graph) {
- return Maps.transformValues(graph.factoryMethodParameters(), ParameterSpec::get);
- }
-}
diff --git a/java/dagger/internal/codegen/componentgenerator/ComponentImplementationFactory.java b/java/dagger/internal/codegen/componentgenerator/ComponentImplementationFactory.java
deleted file mode 100644
index 0d29b8693..000000000
--- a/java/dagger/internal/codegen/componentgenerator/ComponentImplementationFactory.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.componentgenerator;
-
-import static dagger.internal.codegen.componentgenerator.ComponentGenerator.componentName;
-
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.KeyFactory;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.writing.ComponentImplementation;
-import dagger.internal.codegen.writing.SubcomponentNames;
-import java.util.Optional;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/** Factory for {@link ComponentImplementation}s. */
-@Singleton
-final class ComponentImplementationFactory {
- private final KeyFactory keyFactory;
- private final CompilerOptions compilerOptions;
- private final TopLevelImplementationComponent.Builder topLevelImplementationComponentBuilder;
-
- @Inject
- ComponentImplementationFactory(
- KeyFactory keyFactory,
- CompilerOptions compilerOptions,
- TopLevelImplementationComponent.Builder topLevelImplementationComponentBuilder) {
- this.keyFactory = keyFactory;
- this.compilerOptions = compilerOptions;
- this.topLevelImplementationComponentBuilder = topLevelImplementationComponentBuilder;
- }
-
- /**
- * Returns a top-level (non-nested) component implementation for a binding graph.
- */
- ComponentImplementation createComponentImplementation(BindingGraph bindingGraph) {
- ComponentImplementation componentImplementation =
- ComponentImplementation.topLevelComponentImplementation(
- bindingGraph,
- componentName(bindingGraph.componentTypeElement()),
- new SubcomponentNames(bindingGraph, keyFactory),
- compilerOptions);
-
- // TODO(dpb): explore using optional bindings for the "parent" bindings
- return topLevelImplementationComponentBuilder
- .topLevelComponent(componentImplementation)
- .build()
- .currentImplementationSubcomponentBuilder()
- .componentImplementation(componentImplementation)
- .bindingGraph(bindingGraph)
- .parentBuilder(Optional.empty())
- .parentBindingExpressions(Optional.empty())
- .parentRequirementExpressions(Optional.empty())
- .build()
- .componentImplementationBuilder()
- .build();
- }
-}
diff --git a/java/dagger/internal/codegen/componentgenerator/CurrentImplementationSubcomponent.java b/java/dagger/internal/codegen/componentgenerator/CurrentImplementationSubcomponent.java
index 558437239..4a193ce41 100644
--- a/java/dagger/internal/codegen/componentgenerator/CurrentImplementationSubcomponent.java
+++ b/java/dagger/internal/codegen/componentgenerator/CurrentImplementationSubcomponent.java
@@ -17,41 +17,64 @@
package dagger.internal.codegen.componentgenerator;
import dagger.BindsInstance;
+import dagger.Module;
+import dagger.Provides;
import dagger.Subcomponent;
import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.writing.ComponentBindingExpressions;
import dagger.internal.codegen.writing.ComponentImplementation;
+import dagger.internal.codegen.writing.ComponentImplementation.ChildComponentImplementationFactory;
+import dagger.internal.codegen.writing.ComponentRequestRepresentations;
import dagger.internal.codegen.writing.ComponentRequirementExpressions;
import dagger.internal.codegen.writing.ParentComponent;
import dagger.internal.codegen.writing.PerComponentImplementation;
import java.util.Optional;
+import javax.inject.Provider;
/**
* A subcomponent that injects all objects that are responsible for creating a single {@link
* ComponentImplementation} instance. Each child {@link ComponentImplementation} will have its own
* instance of {@link CurrentImplementationSubcomponent}.
*/
-@Subcomponent
+@Subcomponent(
+ modules = CurrentImplementationSubcomponent.ChildComponentImplementationFactoryModule.class)
@PerComponentImplementation
// This only needs to be public because the type is referenced by generated component.
public interface CurrentImplementationSubcomponent {
- ComponentImplementationBuilder componentImplementationBuilder();
+ ComponentImplementation componentImplementation();
+
+ /** A module to bind the {@link ChildComponentImplementationFactory}. */
+ @Module
+ interface ChildComponentImplementationFactoryModule {
+ @Provides
+ static ChildComponentImplementationFactory provideChildComponentImplementationFactory(
+ CurrentImplementationSubcomponent.Builder currentImplementationSubcomponentBuilder,
+ Provider<ComponentImplementation> componentImplementation,
+ Provider<ComponentRequestRepresentations> componentRequestRepresentations,
+ Provider<ComponentRequirementExpressions> componentRequirementExpressions) {
+ return childGraph ->
+ currentImplementationSubcomponentBuilder
+ .bindingGraph(childGraph)
+ .parentImplementation(Optional.of(componentImplementation.get()))
+ .parentRequestRepresentations(Optional.of(componentRequestRepresentations.get()))
+ .parentRequirementExpressions(Optional.of(componentRequirementExpressions.get()))
+ .build()
+ .componentImplementation();
+ }
+ }
/** Returns the builder for {@link CurrentImplementationSubcomponent}. */
@Subcomponent.Builder
interface Builder {
@BindsInstance
- Builder componentImplementation(ComponentImplementation componentImplementation);
-
- @BindsInstance
Builder bindingGraph(BindingGraph bindingGraph);
@BindsInstance
- Builder parentBuilder(@ParentComponent Optional<ComponentImplementationBuilder> parentBuilder);
+ Builder parentImplementation(
+ @ParentComponent Optional<ComponentImplementation> parentImplementation);
@BindsInstance
- Builder parentBindingExpressions(
- @ParentComponent Optional<ComponentBindingExpressions> parentBindingExpressions);
+ Builder parentRequestRepresentations(
+ @ParentComponent Optional<ComponentRequestRepresentations> parentRequestRepresentations);
@BindsInstance
Builder parentRequirementExpressions(
diff --git a/java/dagger/internal/codegen/componentgenerator/MethodSignature.java b/java/dagger/internal/codegen/componentgenerator/MethodSignature.java
deleted file mode 100644
index 99b05a44a..000000000
--- a/java/dagger/internal/codegen/componentgenerator/MethodSignature.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2014 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.componentgenerator;
-
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-
-import com.google.auto.common.MoreTypes;
-import com.google.auto.value.AutoValue;
-import com.google.common.base.Equivalence;
-import com.google.common.collect.ImmutableList;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.util.List;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
-
-/** A class that defines proper {@code equals} and {@code hashcode} for a method signature. */
-@AutoValue
-abstract class MethodSignature {
-
- abstract String name();
-
- abstract ImmutableList<? extends Equivalence.Wrapper<? extends TypeMirror>> parameterTypes();
-
- abstract ImmutableList<? extends Equivalence.Wrapper<? extends TypeMirror>> thrownTypes();
-
- static MethodSignature forComponentMethod(
- ComponentMethodDescriptor componentMethod, DeclaredType componentType, DaggerTypes types) {
- ExecutableType methodType =
- MoreTypes.asExecutable(types.asMemberOf(componentType, componentMethod.methodElement()));
- return new AutoValue_MethodSignature(
- componentMethod.methodElement().getSimpleName().toString(),
- wrapInEquivalence(methodType.getParameterTypes()),
- wrapInEquivalence(methodType.getThrownTypes()));
- }
-
- private static ImmutableList<? extends Equivalence.Wrapper<? extends TypeMirror>>
- wrapInEquivalence(List<? extends TypeMirror> types) {
- return types.stream().map(MoreTypes.equivalence()::wrap).collect(toImmutableList());
- }
-}
diff --git a/java/dagger/internal/codegen/componentgenerator/TopLevelImplementationComponent.java b/java/dagger/internal/codegen/componentgenerator/TopLevelImplementationComponent.java
index 7919e471d..79952c9fa 100644
--- a/java/dagger/internal/codegen/componentgenerator/TopLevelImplementationComponent.java
+++ b/java/dagger/internal/codegen/componentgenerator/TopLevelImplementationComponent.java
@@ -18,6 +18,7 @@ package dagger.internal.codegen.componentgenerator;
import dagger.BindsInstance;
import dagger.Subcomponent;
+import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.writing.ComponentImplementation;
import dagger.internal.codegen.writing.PerGeneratedFile;
import dagger.internal.codegen.writing.TopLevel;
@@ -33,10 +34,8 @@ public interface TopLevelImplementationComponent {
CurrentImplementationSubcomponent.Builder currentImplementationSubcomponentBuilder();
/** Returns the builder for {@link TopLevelImplementationComponent}. */
- @Subcomponent.Builder
- interface Builder {
- @BindsInstance
- Builder topLevelComponent(@TopLevel ComponentImplementation topLevelImplementation);
- TopLevelImplementationComponent build();
+ @Subcomponent.Factory
+ interface Factory {
+ TopLevelImplementationComponent create(@BindsInstance @TopLevel BindingGraph bindingGraph);
}
}
diff --git a/java/dagger/internal/codegen/extension/BUILD b/java/dagger/internal/codegen/extension/BUILD
index 468a68583..6bcb605de 100644
--- a/java/dagger/internal/codegen/extension/BUILD
+++ b/java/dagger/internal/codegen/extension/BUILD
@@ -25,9 +25,9 @@ java_library(
srcs = glob(["*.java"]),
tags = ["maven:merged"],
deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:graph",
- "@google_bazel_common//third_party/java/jsr305_annotations",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/graph",
+ "//third_party/java/jsr305_annotations",
],
)
diff --git a/java/dagger/internal/codegen/javac/BUILD b/java/dagger/internal/codegen/javac/BUILD
index b8cb37c8a..ad2f91be9 100644
--- a/java/dagger/internal/codegen/javac/BUILD
+++ b/java/dagger/internal/codegen/javac/BUILD
@@ -32,6 +32,8 @@ java_library(
"//java/dagger/internal/codegen/binding",
"//java/dagger/internal/codegen/compileroption",
"//java/dagger/internal/codegen/langmodel",
+ "//java/dagger/internal/codegen/xprocessing",
+ "//third_party/java/guava/collect",
],
)
diff --git a/java/dagger/internal/codegen/compileroption/JavacPluginCompilerOptions.java b/java/dagger/internal/codegen/javac/JavacPluginCompilerOptions.java
index a86cc1b7c..c12d86568 100644
--- a/java/dagger/internal/codegen/compileroption/JavacPluginCompilerOptions.java
+++ b/java/dagger/internal/codegen/javac/JavacPluginCompilerOptions.java
@@ -14,17 +14,19 @@
* limitations under the License.
*/
-package dagger.internal.codegen.compileroption;
+package dagger.internal.codegen.javac;
import static dagger.internal.codegen.compileroption.ValidationType.NONE;
import static javax.tools.Diagnostic.Kind.NOTE;
+import androidx.room.compiler.processing.XTypeElement;
+import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.compileroption.ValidationType;
import javax.inject.Inject;
-import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
/** {@link CompilerOptions} for Javac plugins (e.g. for Dagger statistics or Kythe). */
-public final class JavacPluginCompilerOptions extends CompilerOptions {
+final class JavacPluginCompilerOptions extends CompilerOptions {
@Inject
JavacPluginCompilerOptions() {}
@@ -35,7 +37,12 @@ public final class JavacPluginCompilerOptions extends CompilerOptions {
}
@Override
- public boolean fastInit(TypeElement element) {
+ public boolean experimentalMergedMode(XTypeElement element) {
+ return false;
+ }
+
+ @Override
+ public boolean fastInit(XTypeElement element) {
return false;
}
@@ -65,6 +72,11 @@ public final class JavacPluginCompilerOptions extends CompilerOptions {
}
@Override
+ public boolean includeStacktraceWithDeferredErrorMessages() {
+ return false;
+ }
+
+ @Override
public boolean ignorePrivateAndStaticInjectionForComponent() {
return false;
}
@@ -95,7 +107,7 @@ public final class JavacPluginCompilerOptions extends CompilerOptions {
}
@Override
- public boolean pluginsVisitFullBindingGraphs(TypeElement element) {
+ public boolean pluginsVisitFullBindingGraphs(XTypeElement element) {
return false;
}
@@ -118,4 +130,9 @@ public final class JavacPluginCompilerOptions extends CompilerOptions {
public boolean strictMultibindingValidation() {
return false;
}
+
+ @Override
+ public boolean strictSuperficialValidation() {
+ return true;
+ }
}
diff --git a/java/dagger/internal/codegen/javac/JavacPluginModule.java b/java/dagger/internal/codegen/javac/JavacPluginModule.java
index 214191a50..aca9f238c 100644
--- a/java/dagger/internal/codegen/javac/JavacPluginModule.java
+++ b/java/dagger/internal/codegen/javac/JavacPluginModule.java
@@ -16,6 +16,9 @@
package dagger.internal.codegen.javac;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.compat.XConverters;
import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.model.JavacTypes;
import com.sun.tools.javac.util.Context;
@@ -25,68 +28,54 @@ import dagger.Provides;
import dagger.internal.codegen.binding.BindingGraphFactory;
import dagger.internal.codegen.binding.ComponentDescriptorFactory;
import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.compileroption.JavacPluginCompilerOptions;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import javax.annotation.processing.Messager;
-import javax.inject.Inject;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.Element;
-import javax.lang.model.util.Types;
-import javax.tools.Diagnostic;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.util.Elements; // ALLOW_TYPES_ELEMENTS
+import javax.lang.model.util.Types; // ALLOW_TYPES_ELEMENTS
/**
* A module that provides a {@link BindingGraphFactory} and {@link ComponentDescriptorFactory} for
* use in {@code javac} plugins. Requires a binding for the {@code javac} {@link Context}.
*/
-@Module
-public abstract class JavacPluginModule {
- @Binds
- abstract CompilerOptions compilerOptions(JavacPluginCompilerOptions compilerOptions);
-
- @Binds
- abstract Messager messager(NullMessager nullMessager);
-
- static final class NullMessager implements Messager {
-
- @Inject
- NullMessager() {}
-
- @Override
- public void printMessage(Diagnostic.Kind kind, CharSequence charSequence) {}
+@Module(includes = JavacPluginModule.BindsModule.class)
+public final class JavacPluginModule {
+ @Module
+ interface BindsModule {
+ @Binds
+ CompilerOptions compilerOptions(JavacPluginCompilerOptions compilerOptions);
+ }
- @Override
- public void printMessage(Diagnostic.Kind kind, CharSequence charSequence, Element element) {}
+ private final XProcessingEnv processingEnv;
- @Override
- public void printMessage(
- Diagnostic.Kind kind,
- CharSequence charSequence,
- Element element,
- AnnotationMirror annotationMirror) {}
+ public JavacPluginModule(Context context) {
+ this(JavacElements.instance(context), JavacTypes.instance(context));
+ }
- @Override
- public void printMessage(
- Diagnostic.Kind kind,
- CharSequence charSequence,
- Element element,
- AnnotationMirror annotationMirror,
- AnnotationValue annotationValue) {}
+ public JavacPluginModule(Elements elements, Types types) {
+ this.processingEnv =
+ XProcessingEnv.create(new JavacPluginProcessingEnvironment(elements, types));
}
@Provides
- static DaggerElements daggerElements(Context javaContext) {
- return new DaggerElements(
- JavacElements.instance(javaContext), JavacTypes.instance(javaContext));
+ XMessager messager() {
+ return processingEnv.getMessager();
}
@Provides
- static DaggerTypes daggerTypes(Context javaContext, DaggerElements elements) {
- return new DaggerTypes(JavacTypes.instance(javaContext), elements);
+ DaggerElements daggerElements() {
+ ProcessingEnvironment env = XConverters.toJavac(processingEnv);
+ return new DaggerElements(env.getElementUtils(), env.getTypeUtils()); // ALLOW_TYPES_ELEMENTS
}
- @Binds abstract Types types(DaggerTypes daggerTypes);
+ @Provides
+ DaggerTypes daggerTypes(DaggerElements elements) {
+ ProcessingEnvironment env = XConverters.toJavac(processingEnv);
+ return new DaggerTypes(env.getTypeUtils(), elements); // ALLOW_TYPES_ELEMENTS
+ }
- private JavacPluginModule() {}
+ @Provides
+ XProcessingEnv xProcessingEnv() {
+ return processingEnv;
+ }
}
diff --git a/java/dagger/internal/codegen/javac/JavacPluginProcessingEnvironment.java b/java/dagger/internal/codegen/javac/JavacPluginProcessingEnvironment.java
new file mode 100644
index 000000000..3f6a575fb
--- /dev/null
+++ b/java/dagger/internal/codegen/javac/JavacPluginProcessingEnvironment.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.javac;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Locale;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.Messager;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.util.Elements; // ALLOW_TYPES_ELEMENTS since in interface API
+import javax.lang.model.util.Types; // ALLOW_TYPES_ELEMENTS since in interface API
+import javax.tools.Diagnostic;
+import javax.tools.FileObject;
+import javax.tools.JavaFileManager.Location;
+import javax.tools.JavaFileObject;
+
+/**
+ * An implementation of {@link ProcessingEnvironment} that runs in a javac plugin environment.
+ *
+ * <p>This environment runs after the classes are already compiled, so parts of the {@link
+ * ProcessingEnvironment} API like {@link Filer}, {@link Messager} don't make sense in this
+ * environment, so they've been replaced with throwing and no-op implementations respectively.
+ */
+final class JavacPluginProcessingEnvironment implements ProcessingEnvironment {
+ private final Elements elements;
+ private final Types types;
+ private final Filer filer = new ThrowingFiler();
+ private final Messager messager = new NoopMessager();
+
+ JavacPluginProcessingEnvironment(Elements elements, Types types) {
+ this.elements = elements;
+ this.types = types;
+ }
+
+ @Override
+ public Elements getElementUtils() {
+ return elements;
+ }
+
+ @Override
+ public Types getTypeUtils() {
+ return types;
+ }
+
+ @Override
+ public Filer getFiler() {
+ return filer;
+ }
+
+ @Override
+ public Locale getLocale() {
+ // Null means there's no locale in effect
+ return null;
+ }
+
+ @Override
+ public Messager getMessager() {
+ return messager;
+ }
+
+ @Override
+ public ImmutableMap<String, String> getOptions() {
+ // TODO(erichang): You can technically parse options out of the context, but it is internal
+ // implementation and unclear that any of the tools will ever be passing an option.
+ return ImmutableMap.of();
+ }
+
+ @Override
+ public SourceVersion getSourceVersion() {
+ // This source version doesn't really matter because it is saying what version generated code
+ // should adhere to, which there shouldn't be any because the Filer doesn't work.
+ return SourceVersion.latestSupported();
+ }
+
+ private static final class ThrowingFiler implements Filer {
+ @Override
+ public JavaFileObject createClassFile(CharSequence name, Element... originatingElements) {
+ throw new UnsupportedOperationException("Cannot use a Filer in this context");
+ }
+
+ @Override
+ public FileObject createResource(
+ Location location,
+ CharSequence pkg,
+ CharSequence relativeName,
+ Element... originatingElements) {
+ throw new UnsupportedOperationException("Cannot use a Filer in this context");
+ }
+
+ @Override
+ public JavaFileObject createSourceFile(CharSequence name, Element... originatingElements) {
+ throw new UnsupportedOperationException("Cannot use a Filer in this context");
+ }
+
+ @Override
+ public FileObject getResource(Location location, CharSequence pkg, CharSequence relativeName) {
+ throw new UnsupportedOperationException("Cannot use a Filer in this context");
+ }
+ }
+
+ private static final class NoopMessager implements Messager {
+ @Override
+ public void printMessage(Diagnostic.Kind kind, CharSequence charSequence) {}
+
+ @Override
+ public void printMessage(Diagnostic.Kind kind, CharSequence charSequence, Element element) {}
+
+ @Override
+ public void printMessage(
+ Diagnostic.Kind kind,
+ CharSequence charSequence,
+ Element element,
+ AnnotationMirror annotationMirror) {}
+
+ @Override
+ public void printMessage(
+ Diagnostic.Kind kind,
+ CharSequence charSequence,
+ Element element,
+ AnnotationMirror annotationMirror,
+ AnnotationValue annotationValue) {}
+ }
+}
diff --git a/java/dagger/internal/codegen/javapoet/BUILD b/java/dagger/internal/codegen/javapoet/BUILD
index ddb9f8802..4dc44857f 100644
--- a/java/dagger/internal/codegen/javapoet/BUILD
+++ b/java/dagger/internal/codegen/javapoet/BUILD
@@ -25,12 +25,12 @@ java_library(
plugins = ["//java/dagger/internal/codegen/bootstrap"],
tags = ["maven:merged"],
deps = [
- "//java/dagger:core",
"//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/producers",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//java/dagger/internal/codegen/xprocessing",
+ "//third_party/java/auto:common",
+ "//third_party/java/error_prone:annotations",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
diff --git a/java/dagger/internal/codegen/javapoet/CodeBlocks.java b/java/dagger/internal/codegen/javapoet/CodeBlocks.java
index 3e9f75d8a..c0d7a7b1c 100644
--- a/java/dagger/internal/codegen/javapoet/CodeBlocks.java
+++ b/java/dagger/internal/codegen/javapoet/CodeBlocks.java
@@ -112,6 +112,11 @@ public final class CodeBlocks {
}
/** Returns {@code expression} cast to a type. */
+ public static CodeBlock cast(CodeBlock expression, ClassName castTo) {
+ return CodeBlock.of("($T) $L", castTo, expression);
+ }
+
+ /** Returns {@code expression} cast to a type. */
public static CodeBlock cast(CodeBlock expression, Class<?> castTo) {
return CodeBlock.of("($T) $L", castTo, expression);
}
diff --git a/java/dagger/internal/codegen/javapoet/Expression.java b/java/dagger/internal/codegen/javapoet/Expression.java
index b79c55c01..f7bfbb881 100644
--- a/java/dagger/internal/codegen/javapoet/Expression.java
+++ b/java/dagger/internal/codegen/javapoet/Expression.java
@@ -16,6 +16,9 @@
package dagger.internal.codegen.javapoet;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+
+import androidx.room.compiler.processing.XType;
import com.google.auto.common.MoreTypes;
import com.squareup.javapoet.CodeBlock;
import dagger.internal.codegen.langmodel.DaggerTypes;
@@ -45,6 +48,11 @@ public final class Expression {
}
/** Creates a new {@link Expression} with a {@link TypeMirror} and {@link CodeBlock}. */
+ public static Expression create(XType type, CodeBlock expression) {
+ return create(toJavac(type), expression);
+ }
+
+ /** Creates a new {@link Expression} with a {@link TypeMirror} and {@link CodeBlock}. */
public static Expression create(TypeMirror type, CodeBlock expression) {
return new Expression(type, expression);
}
@@ -53,6 +61,14 @@ public final class Expression {
* Creates a new {@link Expression} with a {@link TypeMirror}, {@linkplain CodeBlock#of(String,
* Object[]) format, and arguments}.
*/
+ public static Expression create(XType type, String format, Object... args) {
+ return create(toJavac(type), format, args);
+ }
+
+ /**
+ * Creates a new {@link Expression} with a {@link TypeMirror}, {@linkplain CodeBlock#of(String,
+ * Object[]) format, and arguments}.
+ */
public static Expression create(TypeMirror type, String format, Object... args) {
return create(type, CodeBlock.of(format, args));
}
@@ -60,6 +76,13 @@ public final class Expression {
/** Returns a new expression that casts the current expression to {@code newType}. */
// TODO(ronshapiro): consider overloads that take a Types and Elements and only cast if necessary,
// or just embedding a Types/Elements instance in an Expression.
+ public Expression castTo(XType newType) {
+ return castTo(toJavac(newType));
+ }
+
+ /** Returns a new expression that casts the current expression to {@code newType}. */
+ // TODO(ronshapiro): consider overloads that take a Types and Elements and only cast if necessary,
+ // or just embedding a Types/Elements instance in an Expression.
public Expression castTo(TypeMirror newType) {
return create(newType, "($T) $L", newType, codeBlock);
}
diff --git a/java/dagger/internal/codegen/javapoet/TypeNames.java b/java/dagger/internal/codegen/javapoet/TypeNames.java
index 71f03f0e4..ae4145d66 100644
--- a/java/dagger/internal/codegen/javapoet/TypeNames.java
+++ b/java/dagger/internal/codegen/javapoet/TypeNames.java
@@ -16,79 +16,152 @@
package dagger.internal.codegen.javapoet;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
+
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
-import dagger.Lazy;
-import dagger.MembersInjector;
-import dagger.internal.DoubleCheck;
-import dagger.internal.Factory;
-import dagger.internal.InjectedFieldSignature;
-import dagger.internal.InstanceFactory;
-import dagger.internal.MapFactory;
-import dagger.internal.MapProviderFactory;
-import dagger.internal.MembersInjectors;
-import dagger.internal.ProviderOfLazy;
-import dagger.internal.SetFactory;
-import dagger.internal.SingleCheck;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.producers.ProducerModule;
-import dagger.producers.internal.AbstractProducer;
-import dagger.producers.internal.DependencyMethodProducer;
-import dagger.producers.internal.MapOfProducedProducer;
-import dagger.producers.internal.MapOfProducerProducer;
-import dagger.producers.internal.MapProducer;
-import dagger.producers.internal.Producers;
-import dagger.producers.internal.SetOfProducedProducer;
-import dagger.producers.internal.SetProducer;
-import dagger.producers.monitoring.ProducerToken;
-import dagger.producers.monitoring.ProductionComponentMonitor;
-import java.util.List;
-import java.util.Set;
-import javax.inject.Provider;
+import javax.lang.model.type.TypeMirror;
/** Common names and convenience methods for JavaPoet {@link TypeName} usage. */
public final class TypeNames {
- public static final ClassName ABSTRACT_PRODUCER = ClassName.get(AbstractProducer.class);
- public static final ClassName DEPENDENCY_METHOD_PRODUCER =
- ClassName.get(DependencyMethodProducer.class);
- public static final ClassName DOUBLE_CHECK = ClassName.get(DoubleCheck.class);
- public static final ClassName FACTORY = ClassName.get(Factory.class);
- public static final ClassName FUTURES = ClassName.get(Futures.class);
+ // Dagger Core classnames
+ public static final ClassName ASSISTED = ClassName.get("dagger.assisted", "Assisted");
+ public static final ClassName ASSISTED_FACTORY =
+ ClassName.get("dagger.assisted", "AssistedFactory");
+ public static final ClassName ASSISTED_INJECT =
+ ClassName.get("dagger.assisted", "AssistedInject");
+ public static final ClassName BINDS = ClassName.get("dagger", "Binds");
+ public static final ClassName BINDS_INSTANCE = ClassName.get("dagger", "BindsInstance");
+ public static final ClassName BINDS_OPTIONAL_OF = ClassName.get("dagger", "BindsOptionalOf");
+ public static final ClassName COMPONENT = ClassName.get("dagger", "Component");
+ public static final ClassName COMPONENT_BUILDER = COMPONENT.nestedClass("Builder");
+ public static final ClassName COMPONENT_FACTORY = COMPONENT.nestedClass("Factory");
+ public static final ClassName DAGGER_PROCESSING_OPTIONS =
+ ClassName.get("dagger", "DaggerProcessingOptions");
+ public static final ClassName ELEMENTS_INTO_SET =
+ ClassName.get("dagger.multibindings", "ElementsIntoSet");
+ public static final ClassName INTO_MAP = ClassName.get("dagger.multibindings", "IntoMap");
+ public static final ClassName INTO_SET = ClassName.get("dagger.multibindings", "IntoSet");
+ public static final ClassName MAP_KEY = ClassName.get("dagger", "MapKey");
+ public static final ClassName MODULE = ClassName.get("dagger", "Module");
+ public static final ClassName MULTIBINDS = ClassName.get("dagger.multibindings", "Multibinds");
+ public static final ClassName PROVIDES = ClassName.get("dagger", "Provides");
+ public static final ClassName REUSABLE = ClassName.get("dagger", "Reusable");
+ public static final ClassName SUBCOMPONENT = ClassName.get("dagger", "Subcomponent");
+ public static final ClassName SUBCOMPONENT_BUILDER = SUBCOMPONENT.nestedClass("Builder");
+ public static final ClassName SUBCOMPONENT_FACTORY = SUBCOMPONENT.nestedClass("Factory");
+
+ // Dagger Internal classnames
+ public static final ClassName DELEGATE_FACTORY =
+ ClassName.get("dagger.internal", "DelegateFactory");
+ public static final ClassName DOUBLE_CHECK = ClassName.get("dagger.internal", "DoubleCheck");
+ public static final ClassName FACTORY = ClassName.get("dagger.internal", "Factory");
public static final ClassName INJECTED_FIELD_SIGNATURE =
- ClassName.get(InjectedFieldSignature.class);
- public static final ClassName INSTANCE_FACTORY = ClassName.get(InstanceFactory.class);
- public static final ClassName LAZY = ClassName.get(Lazy.class);
- public static final ClassName LIST = ClassName.get(List.class);
- public static final ClassName LISTENABLE_FUTURE = ClassName.get(ListenableFuture.class);
- public static final ClassName MAP_FACTORY = ClassName.get(MapFactory.class);
+ ClassName.get("dagger.internal", "InjectedFieldSignature");
+ public static final ClassName INSTANCE_FACTORY =
+ ClassName.get("dagger.internal", "InstanceFactory");
+ public static final ClassName MAP_FACTORY = ClassName.get("dagger.internal", "MapFactory");
+ public static final ClassName MAP_PROVIDER_FACTORY =
+ ClassName.get("dagger.internal", "MapProviderFactory");
+ public static final ClassName MEMBERS_INJECTOR = ClassName.get("dagger", "MembersInjector");
+ public static final ClassName MEMBERS_INJECTORS =
+ ClassName.get("dagger.internal", "MembersInjectors");
+ public static final ClassName PROVIDER = ClassName.get("javax.inject", "Provider");
+ public static final ClassName PROVIDER_OF_LAZY =
+ ClassName.get("dagger.internal", "ProviderOfLazy");
+ public static final ClassName SCOPE_METADATA = ClassName.get("dagger.internal", "ScopeMetadata");
+ public static final ClassName QUALIFIER_METADATA =
+ ClassName.get("dagger.internal", "QualifierMetadata");
+ public static final ClassName SET_FACTORY = ClassName.get("dagger.internal", "SetFactory");
+ public static final ClassName SINGLE_CHECK = ClassName.get("dagger.internal", "SingleCheck");
+ public static final ClassName LAZY = ClassName.get("dagger", "Lazy");
+
+ // Dagger Producers classnames
+ public static final ClassName ABSTRACT_PRODUCER =
+ ClassName.get("dagger.producers.internal", "AbstractProducer");
+ public static final ClassName CANCELLATION_LISTENER =
+ ClassName.get("dagger.producers.internal", "CancellationListener");
+ public static final ClassName CANCELLATION_POLICY =
+ ClassName.get("dagger.producers", "CancellationPolicy");
+ public static final ClassName DELEGATE_PRODUCER =
+ ClassName.get("dagger.producers.internal", "DelegateProducer");
+ public static final ClassName DEPENDENCY_METHOD_PRODUCER =
+ ClassName.get("dagger.producers.internal", "DependencyMethodProducer");
public static final ClassName MAP_OF_PRODUCED_PRODUCER =
- ClassName.get(MapOfProducedProducer.class);
+ ClassName.get("dagger.producers.internal", "MapOfProducedProducer");
public static final ClassName MAP_OF_PRODUCER_PRODUCER =
- ClassName.get(MapOfProducerProducer.class);
- public static final ClassName MAP_PRODUCER = ClassName.get(MapProducer.class);
- public static final ClassName MAP_PROVIDER_FACTORY = ClassName.get(MapProviderFactory.class);
- public static final ClassName MEMBERS_INJECTOR = ClassName.get(MembersInjector.class);
- public static final ClassName MEMBERS_INJECTORS = ClassName.get(MembersInjectors.class);
- public static final ClassName PRODUCER_TOKEN = ClassName.get(ProducerToken.class);
- public static final ClassName PRODUCED = ClassName.get(Produced.class);
- public static final ClassName PRODUCER = ClassName.get(Producer.class);
- public static final ClassName PRODUCERS = ClassName.get(Producers.class);
- public static final ClassName PRODUCER_MODULE = ClassName.get(ProducerModule.class);
+ ClassName.get("dagger.producers.internal", "MapOfProducerProducer");
+ public static final ClassName MAP_PRODUCER =
+ ClassName.get("dagger.producers.internal", "MapProducer");
+ public static final ClassName MONITORS =
+ ClassName.get("dagger.producers.monitoring.internal", "Monitors");
+ public static final ClassName PRODUCED = ClassName.get("dagger.producers", "Produced");
+ public static final ClassName PRODUCER = ClassName.get("dagger.producers", "Producer");
+ public static final ClassName PRODUCERS = ClassName.get("dagger.producers.internal", "Producers");
+ public static final ClassName PRODUCER_MODULE =
+ ClassName.get("dagger.producers", "ProducerModule");
+ public static final ClassName PRODUCES = ClassName.get("dagger.producers", "Produces");
+ public static final ClassName PRODUCTION = ClassName.get("dagger.producers", "Production");
+ public static final ClassName PRODUCTION_COMPONENT =
+ ClassName.get("dagger.producers", "ProductionComponent");
+ public static final ClassName PRODUCTION_COMPONENT_BUILDER =
+ PRODUCTION_COMPONENT.nestedClass("Builder");
+ public static final ClassName PRODUCTION_COMPONENT_FACTORY =
+ PRODUCTION_COMPONENT.nestedClass("Factory");
+ public static final ClassName PRODUCTION_EXECTUTOR_MODULE =
+ ClassName.get("dagger.producers.internal", "ProductionExecutorModule");
+ public static final ClassName PRODUCTION_IMPLEMENTATION =
+ ClassName.get("dagger.producers.internal", "ProductionImplementation");
+ public static final ClassName PRODUCTION_SUBCOMPONENT =
+ ClassName.get("dagger.producers", "ProductionSubcomponent");
+ public static final ClassName PRODUCTION_SUBCOMPONENT_BUILDER =
+ PRODUCTION_SUBCOMPONENT.nestedClass("Builder");
+ public static final ClassName PRODUCTION_SUBCOMPONENT_FACTORY =
+ PRODUCTION_SUBCOMPONENT.nestedClass("Factory");
+ public static final ClassName PRODUCER_TOKEN =
+ ClassName.get("dagger.producers.monitoring", "ProducerToken");
+ public static final ClassName PRODUCTION_COMPONENT_MONITOR =
+ ClassName.get("dagger.producers.monitoring", "ProductionComponentMonitor");
public static final ClassName PRODUCTION_COMPONENT_MONITOR_FACTORY =
- ClassName.get(ProductionComponentMonitor.Factory.class);
- public static final ClassName PROVIDER = ClassName.get(Provider.class);
- public static final ClassName PROVIDER_OF_LAZY = ClassName.get(ProviderOfLazy.class);
- public static final ClassName SET = ClassName.get(Set.class);
- public static final ClassName SET_FACTORY = ClassName.get(SetFactory.class);
+ ClassName.get("dagger.producers.monitoring", "ProductionComponentMonitor", "Factory");
public static final ClassName SET_OF_PRODUCED_PRODUCER =
- ClassName.get(SetOfProducedProducer.class);
- public static final ClassName SET_PRODUCER = ClassName.get(SetProducer.class);
- public static final ClassName SINGLE_CHECK = ClassName.get(SingleCheck.class);
+ ClassName.get("dagger.producers.internal", "SetOfProducedProducer");
+ public static final ClassName SET_PRODUCER =
+ ClassName.get("dagger.producers.internal", "SetProducer");
+ public static final ClassName PRODUCTION_SCOPE =
+ ClassName.get("dagger.producers", "ProductionScope");
+
+ // Other classnames
+ public static final ClassName EXECUTOR = ClassName.get("java.util.concurrent", "Executor");
+ public static final ClassName ERROR = ClassName.get("java.lang", "Error");
+ public static final ClassName EXCEPTION = ClassName.get("java.lang", "Exception");
+ public static final ClassName RUNTIME_EXCEPTION = ClassName.get("java.lang", "RuntimeException");
+ public static final ClassName MAP = ClassName.get("java.util", "Map");
+ public static final ClassName IMMUTABLE_MAP =
+ ClassName.get("com.google.common.collect", "ImmutableMap");
+ public static final ClassName SINGLETON = ClassName.get("jakarta.inject", "Singleton");
+ public static final ClassName SINGLETON_JAVAX = ClassName.get("javax.inject", "Singleton");
+ public static final ClassName SCOPE = ClassName.get("jakarta.inject", "Scope");
+ public static final ClassName SCOPE_JAVAX = ClassName.get("javax.inject", "Scope");
+ public static final ClassName INJECT = ClassName.get("jakarta.inject", "Inject");
+ public static final ClassName INJECT_JAVAX = ClassName.get("javax.inject", "Inject");
+ public static final ClassName QUALIFIER = ClassName.get("jakarta.inject", "Qualifier");
+ public static final ClassName QUALIFIER_JAVAX = ClassName.get("javax.inject", "Qualifier");
+ public static final ClassName COLLECTION = ClassName.get("java.util", "Collection");
+ public static final ClassName LIST = ClassName.get("java.util", "List");
+ public static final ClassName SET = ClassName.get("java.util", "Set");
+ public static final ClassName IMMUTABLE_SET =
+ ClassName.get("com.google.common.collect", "ImmutableSet");
+ public static final ClassName FUTURES =
+ ClassName.get("com.google.common.util.concurrent", "Futures");
+ public static final ClassName LISTENABLE_FUTURE =
+ ClassName.get("com.google.common.util.concurrent", "ListenableFuture");
+ public static final ClassName GUAVA_OPTIONAL =
+ ClassName.get("com.google.common.base", "Optional");
+ public static final ClassName JDK_OPTIONAL = ClassName.get("java.util", "Optional");
+ public static final ClassName OVERRIDE = ClassName.get("java.lang", "Override");
+ public static final ClassName JVM_STATIC = ClassName.get("kotlin.jvm", "JvmStatic");
/**
* {@link TypeName#VOID} is lowercase-v {@code void} whereas this represents the class, {@link
@@ -141,8 +214,8 @@ public final class TypeNames {
}
/**
- * Returns the {@link TypeName} for the raw type of the given type name. If the argument isn't a
- * parameterized type, it returns the argument unchanged.
+ * Returns the {@link TypeName} for the raw type of the given {@link TypeName}. If the argument
+ * isn't a parameterized type, it returns the argument unchanged.
*/
public static TypeName rawTypeName(TypeName typeName) {
return (typeName instanceof ParameterizedTypeName)
@@ -150,5 +223,13 @@ public final class TypeNames {
: typeName;
}
+ /**
+ * Returns the {@link TypeName} for the raw type of the given {@link TypeMirror}. If the argument
+ * isn't a parameterized type, it returns the argument unchanged.
+ */
+ public static TypeName rawTypeName(TypeMirror type) {
+ return rawTypeName(TypeName.get(type));
+ }
+
private TypeNames() {}
}
diff --git a/java/dagger/internal/codegen/javapoet/TypeSpecs.java b/java/dagger/internal/codegen/javapoet/TypeSpecs.java
index 8ec8747dc..570f7022f 100644
--- a/java/dagger/internal/codegen/javapoet/TypeSpecs.java
+++ b/java/dagger/internal/codegen/javapoet/TypeSpecs.java
@@ -16,6 +16,9 @@
package dagger.internal.codegen.javapoet;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+
+import androidx.room.compiler.processing.XTypeElement;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeSpec;
@@ -31,12 +34,28 @@ public final class TypeSpecs {
* @return {@code typeBuilder}
*/
@CanIgnoreReturnValue
+ public static TypeSpec.Builder addSupertype(
+ TypeSpec.Builder typeBuilder, XTypeElement supertype) {
+ return addSupertype(typeBuilder, toJavac(supertype));
+ }
+
+ /**
+ * If {@code supertype} is a class, adds it as a superclass for {@code typeBuilder}; if it is an
+ * interface, adds it as a superinterface.
+ *
+ * @return {@code typeBuilder}
+ */
+ @CanIgnoreReturnValue
public static TypeSpec.Builder addSupertype(TypeSpec.Builder typeBuilder, TypeElement supertype) {
switch (supertype.getKind()) {
case CLASS:
- return typeBuilder.superclass(ClassName.get(supertype));
+ return typeBuilder
+ .superclass(ClassName.get(supertype))
+ .avoidClashesWithNestedClasses(supertype);
case INTERFACE:
- return typeBuilder.addSuperinterface(ClassName.get(supertype));
+ return typeBuilder
+ .addSuperinterface(ClassName.get(supertype))
+ .avoidClashesWithNestedClasses(supertype);
default:
throw new AssertionError(supertype + " is neither a class nor an interface.");
}
diff --git a/java/dagger/internal/codegen/kotlin/BUILD b/java/dagger/internal/codegen/kotlin/BUILD
index d1c5458a1..c2f5f0f40 100644
--- a/java/dagger/internal/codegen/kotlin/BUILD
+++ b/java/dagger/internal/codegen/kotlin/BUILD
@@ -29,12 +29,13 @@ java_library(
"//java/dagger/internal/codegen/base:shared",
"//java/dagger/internal/codegen/extension",
"//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/jsr305_annotations",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
+ "//third_party/java/jsr305_annotations",
+ "//third_party/java/jsr330_inject",
"@maven//:org_jetbrains_kotlin_kotlin_stdlib",
"@maven//:org_jetbrains_kotlinx_kotlinx_metadata_jvm",
],
diff --git a/java/dagger/internal/codegen/kotlin/KotlinMetadata.java b/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
index 5fb49f005..d38eba043 100644
--- a/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
+++ b/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
@@ -34,6 +34,7 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.extension.DaggerCollectors;
import dagger.internal.codegen.langmodel.DaggerElements;
import java.util.HashMap;
@@ -188,13 +189,12 @@ abstract class KotlinMetadata {
private static KotlinClassMetadata.Class metadataOf(TypeElement typeElement) {
Optional<AnnotationMirror> metadataAnnotation =
- getAnnotationMirror(typeElement, Metadata.class);
+ getAnnotationMirror(typeElement, ClassName.get(Metadata.class));
Preconditions.checkState(metadataAnnotation.isPresent());
KotlinClassHeader header =
new KotlinClassHeader(
getIntValue(metadataAnnotation.get(), "k"),
getIntArrayValue(metadataAnnotation.get(), "mv"),
- getIntArrayValue(metadataAnnotation.get(), "bv"),
getStringArrayValue(metadataAnnotation.get(), "d1"),
getStringArrayValue(metadataAnnotation.get(), "d2"),
getStringValue(metadataAnnotation.get(), "xs"),
diff --git a/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java b/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java
index 980ff3438..f9ffe4447 100644
--- a/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java
+++ b/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java
@@ -16,9 +16,12 @@
package dagger.internal.codegen.kotlin;
-import static com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations;
+
import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
import static dagger.internal.codegen.langmodel.DaggerElements.closestEnclosingTypeElement;
+import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotatedAnnotations;
import static kotlinx.metadata.Flag.Class.IS_COMPANION_OBJECT;
import static kotlinx.metadata.Flag.Class.IS_DATA;
import static kotlinx.metadata.Flag.Class.IS_OBJECT;
@@ -26,8 +29,10 @@ import static kotlinx.metadata.Flag.IS_PRIVATE;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.extension.DaggerCollectors;
-import java.lang.annotation.Annotation;
+import dagger.internal.codegen.kotlin.KotlinMetadata.FunctionMetadata;
import java.util.Optional;
import javax.inject.Inject;
import javax.lang.model.element.AnnotationMirror;
@@ -37,7 +42,6 @@ import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.ElementFilter;
import kotlin.Metadata;
-import kotlin.jvm.JvmStatic;
import kotlinx.metadata.Flag;
/** Utility class for interacting with Kotlin Metadata. */
@@ -65,11 +69,12 @@ public final class KotlinMetadataUtil {
* method, if any, of a Kotlin property and not for annotations in its backing field.
*/
public ImmutableCollection<? extends AnnotationMirror> getSyntheticPropertyAnnotations(
- VariableElement fieldElement, Class<? extends Annotation> annotationType) {
+ VariableElement fieldElement, ClassName annotationType) {
return metadataFactory
.create(fieldElement)
.getSyntheticAnnotationMethod(fieldElement)
- .map(methodElement -> getAnnotatedAnnotations(methodElement, annotationType).asList())
+ .map(methodElement ->
+ getAnnotatedAnnotations(methodElement, annotationType).asList())
.orElse(ImmutableList.of());
}
@@ -163,9 +168,13 @@ public final class KotlinMetadataUtil {
}
/**
- * Returns {@code true} if the <code>@JvmStatic</code> annotation is present in the given element.
+ * Returns a map mapping all method signatures within the given class element, including methods
+ * that it inherits from its ancestors, to their method names.
*/
- public static boolean isJvmStaticPresent(ExecutableElement element) {
- return isAnnotationPresent(element, JvmStatic.class);
+ public ImmutableMap<String, String> getAllMethodNamesBySignature(TypeElement element) {
+ checkState(
+ hasMetadata(element), "Can not call getAllMethodNamesBySignature for non-Kotlin class");
+ return metadataFactory.create(element).classMetadata().functionsBySignature().values().stream()
+ .collect(toImmutableMap(FunctionMetadata::signature, FunctionMetadata::name));
}
}
diff --git a/java/dagger/internal/codegen/kythe/BUILD b/java/dagger/internal/codegen/kythe/BUILD
index 9e8dea127..0d77841e6 100644
--- a/java/dagger/internal/codegen/kythe/BUILD
+++ b/java/dagger/internal/codegen/kythe/BUILD
@@ -28,13 +28,13 @@ java_library(
"//java/dagger:core",
"//java/dagger/internal/codegen/binding",
"//java/dagger/internal/codegen/javac",
+ "//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/langmodel",
"//java/dagger/internal/codegen/validation",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/producers",
+ "//java/dagger/internal/codegen/xprocessing",
"//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:service",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:service",
+ "//third_party/java/guava/collect",
],
)
diff --git a/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java b/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java
index 4c6f85e21..a2bc0c23f 100644
--- a/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java
+++ b/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java
@@ -19,8 +19,12 @@
// the regular kythe/java tree.
package dagger.internal.codegen.kythe;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.compat.XConverters;
import com.google.auto.service.AutoService;
import com.google.common.collect.Iterables;
import com.google.devtools.kythe.analyzers.base.EntrySet;
@@ -31,8 +35,6 @@ import com.google.devtools.kythe.proto.Storage.VName;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
-import com.sun.tools.javac.util.Context;
-import dagger.BindsInstance;
import dagger.Component;
import dagger.internal.codegen.binding.Binding;
import dagger.internal.codegen.binding.BindingDeclaration;
@@ -41,13 +43,13 @@ import dagger.internal.codegen.binding.BindingNode;
import dagger.internal.codegen.binding.ComponentDescriptorFactory;
import dagger.internal.codegen.binding.ModuleDescriptor;
import dagger.internal.codegen.javac.JavacPluginModule;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.validation.InjectBindingRegistryModule;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.Edge;
-import dagger.model.BindingGraph.Node;
-import dagger.model.DependencyRequest;
-import dagger.producers.ProductionComponent;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraph.DependencyEdge;
+import dagger.spi.model.BindingGraph.Edge;
+import dagger.spi.model.BindingGraph.Node;
+import dagger.spi.model.DependencyRequest;
import java.util.Optional;
import java.util.logging.Logger;
import javax.inject.Inject;
@@ -65,14 +67,17 @@ public class DaggerKythePlugin extends Plugin.Scanner<Void, Void> {
private FactEmitter emitter;
@Inject ComponentDescriptorFactory componentDescriptorFactory;
@Inject BindingGraphFactory bindingGraphFactory;
+ @Inject XProcessingEnv xProcessingEnv;
@Override
public Void visitClassDef(JCClassDecl tree, Void p) {
if (tree.sym != null
- && isAnyAnnotationPresent(tree.sym, Component.class, ProductionComponent.class)) {
+ && isAnyAnnotationPresent(tree.sym, TypeNames.COMPONENT, TypeNames.PRODUCTION_COMPONENT)) {
addNodesForGraph(
bindingGraphFactory.create(
- componentDescriptorFactory.rootComponentDescriptor(tree.sym), false));
+ componentDescriptorFactory.rootComponentDescriptor(
+ XConverters.toXProcessing(tree.sym, xProcessingEnv)),
+ false));
}
return super.visitClassDef(tree, p);
}
@@ -128,8 +133,8 @@ public class DaggerKythePlugin extends Plugin.Scanner<Void, Void> {
private void addDependencyEdge(
DependencyRequest dependency, BindingDeclaration bindingDeclaration) {
- Element requestElement = dependency.requestElement().get();
- Element bindingElement = bindingDeclaration.bindingElement().get();
+ Element requestElement = dependency.requestElement().get().java();
+ Element bindingElement = toJavac(bindingDeclaration.bindingElement().get());
Optional<VName> requestElementNode = jvmNode(requestElement, "request element");
Optional<VName> bindingElementNode = jvmNode(bindingElement, "binding element");
emitEdge(requestElementNode, "/inject/satisfiedby", bindingElementNode);
@@ -155,6 +160,10 @@ public class DaggerKythePlugin extends Plugin.Scanner<Void, Void> {
graph.subgraphs().forEach(this::addChildComponentEdges);
}
+ private Optional<VName> jvmNode(XElement element, String name) {
+ return jvmNode(toJavac(element), name);
+ }
+
private Optional<VName> jvmNode(Element element, String name) {
Optional<VName> jvmNode = kytheGraph.getJvmNode((Symbol) element).map(KytheNode::getVName);
if (!jvmNode.isPresent()) {
@@ -174,7 +183,7 @@ public class DaggerKythePlugin extends Plugin.Scanner<Void, Void> {
if (bindingGraphFactory == null) {
emitter = entrySets.getEmitter();
DaggerDaggerKythePlugin_PluginComponent.builder()
- .context(kytheGraph.getJavaContext())
+ .javacPluginModule(new JavacPluginModule(kytheGraph.getJavaContext()))
.build()
.inject(this);
}
@@ -185,13 +194,5 @@ public class DaggerKythePlugin extends Plugin.Scanner<Void, Void> {
@Component(modules = {InjectBindingRegistryModule.class, JavacPluginModule.class})
interface PluginComponent {
void inject(DaggerKythePlugin plugin);
-
- @Component.Builder
- interface Builder {
- @BindsInstance
- Builder context(Context context);
-
- PluginComponent build();
- }
}
}
diff --git a/java/dagger/internal/codegen/langmodel/Accessibility.java b/java/dagger/internal/codegen/langmodel/Accessibility.java
index 62c1fbdbd..a90e6fd28 100644
--- a/java/dagger/internal/codegen/langmodel/Accessibility.java
+++ b/java/dagger/internal/codegen/langmodel/Accessibility.java
@@ -16,12 +16,17 @@
package dagger.internal.codegen.langmodel;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.auto.common.MoreElements.getPackage;
+import static com.google.auto.common.MoreTypes.asElement;
import static com.google.common.base.Preconditions.checkArgument;
import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PROTECTED;
import static javax.lang.model.element.Modifier.PUBLIC;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import java.util.Optional;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
@@ -35,12 +40,11 @@ import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.NoType;
import javax.lang.model.type.NullType;
import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
-import javax.lang.model.type.TypeVisitor;
import javax.lang.model.type.WildcardType;
-import javax.lang.model.util.SimpleElementVisitor6;
-import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.SimpleElementVisitor8;
import javax.lang.model.util.SimpleTypeVisitor8;
/**
@@ -61,28 +65,45 @@ import javax.lang.model.util.SimpleTypeVisitor8;
public final class Accessibility {
/** Returns true if the given type can be referenced from any package. */
public static boolean isTypePubliclyAccessible(TypeMirror type) {
- return type.accept(new TypeAccessibilityVisitor(), null);
+ return type.accept(new TypeAccessibilityVisitor(Optional.empty()), null);
}
/** Returns true if the given type can be referenced from code in the given package. */
- public static boolean isTypeAccessibleFrom(TypeMirror type, String packageName) {
- return type.accept(new TypeAccessibilityVisitor(packageName), null);
+ public static boolean isTypeAccessibleFrom(XType type, String packageName) {
+ return isTypeAccessibleFrom(toJavac(type), packageName);
}
- private static boolean isTypeAccessibleFrom(TypeMirror type, Optional<String> packageName) {
- return type.accept(new TypeAccessibilityVisitor(packageName), null);
+ /** Returns true if the given type can be referenced from code in the given package. */
+ public static boolean isTypeAccessibleFrom(TypeMirror type, String packageName) {
+ return type.accept(new TypeAccessibilityVisitor(Optional.of(packageName)), null);
}
- private static final class TypeAccessibilityVisitor extends SimpleTypeVisitor6<Boolean, Void> {
- final Optional<String> packageName;
+ /**
+ * Returns true if the given type is protected and can be referenced from the given requesting
+ * element.
+ */
+ public static boolean isProtectedMemberOf(DeclaredType type, XTypeElement requestingElement) {
+ return isProtectedAccessibleFromElement(type.asElement(), requestingElement);
+ }
- TypeAccessibilityVisitor() {
- this(Optional.empty());
+ private static Boolean isProtectedAccessibleFromElement(
+ Element element, XTypeElement requestingElement) {
+ if (!element.getModifiers().contains(PROTECTED)) {
+ return false;
}
-
- TypeAccessibilityVisitor(String packageName) {
- this(Optional.of(packageName));
+ if (element.getEnclosingElement().equals(toJavac(requestingElement))) {
+ return true;
+ }
+ // Check if the element is protected member of the requesting element's super class.
+ if (requestingElement.getSuperType() != null) {
+ return isProtectedAccessibleFromElement(
+ element, requestingElement.getSuperType().getTypeElement());
}
+ return false;
+ }
+
+ private static final class TypeAccessibilityVisitor extends SimpleTypeVisitor8<Boolean, Void> {
+ private final Optional<String> packageName;
TypeAccessibilityVisitor(Optional<String> packageName) {
this.packageName = packageName;
@@ -103,7 +124,7 @@ public final class Accessibility {
// TODO(gak): investigate this check. see comment in Binding
return false;
}
- if (!isElementAccessibleFrom(type.asElement(), packageName)) {
+ if (!type.asElement().accept(new ElementAccessibilityVisitor(packageName), null)) {
return false;
}
for (TypeMirror typeArgument : type.getTypeArguments()) {
@@ -156,36 +177,35 @@ public final class Accessibility {
/** Returns true if the given element can be referenced from any package. */
public static boolean isElementPubliclyAccessible(Element element) {
- return element.accept(new ElementAccessibilityVisitor(), null);
+ return element.accept(new ElementAccessibilityVisitor(Optional.empty()), null);
+ }
+
+ /** Returns true if the given element can be referenced from code in the given package. */
+ // TODO(gak): account for protected
+ // TODO(bcorso): account for kotlin srcs (package-private doesn't exist, internal does exist).
+ public static boolean isElementAccessibleFrom(XElement element, String packageName) {
+ return isElementAccessibleFrom(toJavac(element), packageName);
}
/** Returns true if the given element can be referenced from code in the given package. */
// TODO(gak): account for protected
public static boolean isElementAccessibleFrom(Element element, String packageName) {
- return element.accept(new ElementAccessibilityVisitor(packageName), null);
+ return element.accept(new ElementAccessibilityVisitor(Optional.of(packageName)), null);
}
- private static boolean isElementAccessibleFrom(Element element, Optional<String> packageName) {
- return element.accept(new ElementAccessibilityVisitor(packageName), null);
+ /** Returns true if the given element can be referenced from other code in its own package. */
+ public static boolean isElementAccessibleFromOwnPackage(XElement element) {
+ return isElementAccessibleFromOwnPackage(toJavac(element));
}
/** Returns true if the given element can be referenced from other code in its own package. */
public static boolean isElementAccessibleFromOwnPackage(Element element) {
- return isElementAccessibleFrom(
- element, MoreElements.getPackage(element).getQualifiedName().toString());
+ return isElementAccessibleFrom(element, getPackage(element).getQualifiedName().toString());
}
private static final class ElementAccessibilityVisitor
- extends SimpleElementVisitor6<Boolean, Void> {
- final Optional<String> packageName;
-
- ElementAccessibilityVisitor() {
- this(Optional.empty());
- }
-
- ElementAccessibilityVisitor(String packageName) {
- this(Optional.of(packageName));
- }
+ extends SimpleElementVisitor8<Boolean, Void> {
+ private final Optional<String> packageName;
ElementAccessibilityVisitor(Optional<String> packageName) {
this.packageName = packageName;
@@ -211,10 +231,7 @@ public final class Accessibility {
}
boolean accessibleMember(Element element) {
- if (!element.getEnclosingElement().accept(this, null)) {
- return false;
- }
- return accessibleModifiers(element);
+ return element.getEnclosingElement().accept(this, null) && accessibleModifiers(element);
}
boolean accessibleModifiers(Element element) {
@@ -222,12 +239,9 @@ public final class Accessibility {
return true;
} else if (element.getModifiers().contains(PRIVATE)) {
return false;
- } else if (packageName.isPresent()
- && getPackage(element).getQualifiedName().contentEquals(packageName.get())) {
- return true;
- } else {
- return false;
}
+ return packageName.isPresent()
+ && getPackage(element).getQualifiedName().contentEquals(packageName.get());
}
@Override
@@ -249,27 +263,18 @@ public final class Accessibility {
}
}
- private static final TypeVisitor<Boolean, Optional<String>> RAW_TYPE_ACCESSIBILITY_VISITOR =
- new SimpleTypeVisitor8<Boolean, Optional<String>>() {
- @Override
- protected Boolean defaultAction(TypeMirror e, Optional<String> requestingPackage) {
- return isTypeAccessibleFrom(e, requestingPackage);
- }
-
- @Override
- public Boolean visitDeclared(DeclaredType t, Optional<String> requestingPackage) {
- return isElementAccessibleFrom(t.asElement(), requestingPackage);
- }
- };
-
/** Returns true if the raw type of {@code type} is accessible from the given package. */
public static boolean isRawTypeAccessible(TypeMirror type, String requestingPackage) {
- return type.accept(RAW_TYPE_ACCESSIBILITY_VISITOR, Optional.of(requestingPackage));
+ return type.getKind() == TypeKind.DECLARED
+ ? isElementAccessibleFrom(asElement(type), requestingPackage)
+ : isTypeAccessibleFrom(type, requestingPackage);
}
/** Returns true if the raw type of {@code type} is accessible from any package. */
public static boolean isRawTypePubliclyAccessible(TypeMirror type) {
- return type.accept(RAW_TYPE_ACCESSIBILITY_VISITOR, Optional.empty());
+ return type.getKind() == TypeKind.DECLARED
+ ? isElementPubliclyAccessible(asElement(type))
+ : isTypePubliclyAccessible(type);
}
private Accessibility() {}
diff --git a/java/dagger/internal/codegen/langmodel/BUILD b/java/dagger/internal/codegen/langmodel/BUILD
index 25f1e6210..5e961a12d 100644
--- a/java/dagger/internal/codegen/langmodel/BUILD
+++ b/java/dagger/internal/codegen/langmodel/BUILD
@@ -27,11 +27,13 @@ java_library(
deps = [
"//java/dagger:core",
"//java/dagger/internal/codegen/base:shared",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "//java/dagger/internal/guava:graph",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
+ "//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
+ "//third_party/java/auto:common",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/graph",
+ "//third_party/java/guava/util/concurrent",
+ "//third_party/java/javapoet",
],
)
diff --git a/java/dagger/internal/codegen/langmodel/DaggerElements.java b/java/dagger/internal/codegen/langmodel/DaggerElements.java
index 51c2a605a..4d5501e75 100644
--- a/java/dagger/internal/codegen/langmodel/DaggerElements.java
+++ b/java/dagger/internal/codegen/langmodel/DaggerElements.java
@@ -16,41 +16,32 @@
package dagger.internal.codegen.langmodel;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.auto.common.MoreElements.asExecutable;
-import static com.google.auto.common.MoreElements.hasModifiers;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Lists.asList;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static java.util.Comparator.comparing;
-import static java.util.stream.Collectors.toSet;
-import static javax.lang.model.element.Modifier.ABSTRACT;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XMethodElement;
import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.graph.Traverser;
import com.squareup.javapoet.ClassName;
import dagger.Reusable;
import dagger.internal.codegen.base.ClearableCache;
import java.io.Writer;
-import java.lang.annotation.Annotation;
-import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.Set;
-import java.util.function.Predicate;
import java.util.stream.Collectors;
-import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ElementVisitor;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement;
@@ -63,15 +54,12 @@ import javax.lang.model.type.ErrorType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.IntersectionType;
import javax.lang.model.type.NoType;
-import javax.lang.model.type.NullType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
-import javax.lang.model.type.UnionType;
import javax.lang.model.type.WildcardType;
-import javax.lang.model.util.AbstractTypeVisitor8;
import javax.lang.model.util.Elements;
-import javax.lang.model.util.SimpleElementVisitor8;
+import javax.lang.model.util.SimpleTypeVisitor8;
import javax.lang.model.util.Types;
/** Extension of {@link Elements} that adds Dagger-specific methods. */
@@ -87,37 +75,32 @@ public final class DaggerElements implements Elements, ClearableCache {
this.types = checkNotNull(types);
}
- public DaggerElements(ProcessingEnvironment processingEnv) {
- this(processingEnv.getElementUtils(), processingEnv.getTypeUtils());
+ /**
+ * Returns {@code true} if {@code encloser} is equal to or recursively encloses {@code enclosed}.
+ */
+ public static boolean transitivelyEncloses(XElement encloser, XElement enclosed) {
+ return transitivelyEncloses(toJavac(encloser), toJavac(enclosed));
}
/**
- * Returns {@code true} if {@code encloser} is equal to {@code enclosed} or recursively encloses
- * it.
+ * Returns {@code true} if {@code encloser} is equal to or recursively encloses {@code enclosed}.
*/
- public static boolean elementEncloses(TypeElement encloser, Element enclosed) {
- return Iterables.contains(GET_ENCLOSED_ELEMENTS.breadthFirst(encloser), enclosed);
+ public static boolean transitivelyEncloses(Element encloser, Element enclosed) {
+ Element current = enclosed;
+ while (current != null) {
+ if (current.equals(encloser)) {
+ return true;
+ }
+ current = current.getEnclosingElement();
+ }
+ return false;
}
- private static final Traverser<Element> GET_ENCLOSED_ELEMENTS =
- Traverser.forTree(Element::getEnclosedElements);
-
public ImmutableSet<ExecutableElement> getLocalAndInheritedMethods(TypeElement type) {
return getLocalAndInheritedMethodsCache.computeIfAbsent(
type, k -> MoreElements.getLocalAndInheritedMethods(type, types, elements));
}
- public ImmutableSet<ExecutableElement> getUnimplementedMethods(TypeElement type) {
- return FluentIterable.from(getLocalAndInheritedMethods(type))
- .filter(hasModifiers(ABSTRACT))
- .toSet();
- }
-
- /** Returns the type element for a class. */
- public TypeElement getTypeElement(Class<?> clazz) {
- return getTypeElement(clazz.getCanonicalName());
- }
-
@Override
public TypeElement getTypeElement(CharSequence name) {
return elements.getTypeElement(name);
@@ -130,22 +113,16 @@ public final class DaggerElements implements Elements, ClearableCache {
/** Returns the argument or the closest enclosing element that is a {@link TypeElement}. */
public static TypeElement closestEnclosingTypeElement(Element element) {
- return element.accept(CLOSEST_ENCLOSING_TYPE_ELEMENT, null);
+ Element current = element;
+ while (current != null) {
+ if (MoreElements.isType(current)) {
+ return MoreElements.asType(current);
+ }
+ current = current.getEnclosingElement();
+ }
+ throw new IllegalStateException("There is no enclosing TypeElement for: " + element);
}
- private static final ElementVisitor<TypeElement, Void> CLOSEST_ENCLOSING_TYPE_ELEMENT =
- new SimpleElementVisitor8<TypeElement, Void>() {
- @Override
- protected TypeElement defaultAction(Element element, Void p) {
- return element.getEnclosingElement().accept(this, null);
- }
-
- @Override
- public TypeElement visitType(TypeElement type, Void p) {
- return type;
- }
- };
-
/**
* Compares elements according to their declaration order among siblings. Only valid to compare
* elements enclosed by the same parent.
@@ -167,9 +144,9 @@ public final class DaggerElements implements Elements, ClearableCache {
* that of {@code annotationClasses}.
*/
public static boolean isAnyAnnotationPresent(
- Element element, Iterable<? extends Class<? extends Annotation>> annotationClasses) {
- for (Class<? extends Annotation> annotation : annotationClasses) {
- if (MoreElements.isAnnotationPresent(element, annotation)) {
+ Element element, Iterable<ClassName> annotationClasses) {
+ for (ClassName annotation : annotationClasses) {
+ if (isAnnotationPresent(element, annotation)) {
return true;
}
}
@@ -178,53 +155,23 @@ public final class DaggerElements implements Elements, ClearableCache {
@SafeVarargs
public static boolean isAnyAnnotationPresent(
- Element element,
- Class<? extends Annotation> first,
- Class<? extends Annotation>... otherAnnotations) {
+ Element element, ClassName first, ClassName... otherAnnotations) {
return isAnyAnnotationPresent(element, asList(first, otherAnnotations));
}
/**
- * Returns {@code true} iff the given element has an {@link AnnotationMirror} whose {@linkplain
- * AnnotationMirror#getAnnotationType() annotation type} is equivalent to {@code annotationType}.
- */
- public static boolean isAnnotationPresent(Element element, TypeMirror annotationType) {
- return element.getAnnotationMirrors().stream()
- .map(AnnotationMirror::getAnnotationType)
- .anyMatch(candidate -> MoreTypes.equivalence().equivalent(candidate, annotationType));
- }
-
- /**
- * Returns the annotation present on {@code element} whose type is {@code first} or within {@code
- * rest}, checking each annotation type in order.
- */
- @SafeVarargs
- public static Optional<AnnotationMirror> getAnyAnnotation(
- Element element, Class<? extends Annotation> first, Class<? extends Annotation>... rest) {
- return getAnyAnnotation(element, asList(first, rest));
- }
-
- /**
- * Returns the annotation present on {@code element} whose type is in {@code annotations},
- * checking each annotation type in order.
+ * Returns {@code true} iff the given element has an {@link AnnotationMirror} whose {@link
+ * AnnotationMirror#getAnnotationType() annotation type} has the same canonical name as that of
+ * {@code annotationClass}. This method is a safer alternative to calling {@link
+ * Element#getAnnotation} and checking for {@code null} as it avoids any interaction with
+ * annotation proxies.
*/
- public static Optional<AnnotationMirror> getAnyAnnotation(
- Element element, Collection<? extends Class<? extends Annotation>> annotations) {
- return element.getAnnotationMirrors().stream()
- .filter(hasAnnotationTypeIn(annotations))
- .map((AnnotationMirror a) -> a) // Avoid returning Optional<? extends AnnotationMirror>.
- .findFirst();
- }
-
- /** Returns the annotations present on {@code element} of all types. */
- @SafeVarargs
- public static ImmutableSet<AnnotationMirror> getAllAnnotations(
- Element element, Class<? extends Annotation> first, Class<? extends Annotation>... rest) {
- return ImmutableSet.copyOf(
- Iterables.filter(
- element.getAnnotationMirrors(), hasAnnotationTypeIn(asList(first, rest))::test));
+ public static boolean isAnnotationPresent(Element element, ClassName annotationName) {
+ return getAnnotationMirror(element, annotationName).isPresent();
}
+ // Note: This is similar to auto-common's MoreElements except using ClassName rather than Class.
+ // TODO(bcorso): Contribute a String version to auto-common's MoreElements?
/**
* Returns an {@link AnnotationMirror} for the annotation of type {@code annotationClass} on
* {@code element}, or {@link Optional#empty()} if no such annotation exists. This method is a
@@ -232,25 +179,23 @@ public final class DaggerElements implements Elements, ClearableCache {
* annotation proxies.
*/
public static Optional<AnnotationMirror> getAnnotationMirror(
- Element element, Class<? extends Annotation> annotationClass) {
- return Optional.ofNullable(MoreElements.getAnnotationMirror(element, annotationClass).orNull());
- }
-
- private static Predicate<AnnotationMirror> hasAnnotationTypeIn(
- Collection<? extends Class<? extends Annotation>> annotations) {
- Set<String> annotationClassNames =
- annotations.stream().map(Class::getCanonicalName).collect(toSet());
- return annotation ->
- annotationClassNames.contains(
- MoreTypes.asTypeElement(annotation.getAnnotationType()).getQualifiedName().toString());
+ Element element, ClassName annotationName) {
+ String annotationClassName = annotationName.canonicalName();
+ for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
+ TypeElement annotationTypeElement =
+ MoreElements.asType(annotationMirror.getAnnotationType().asElement());
+ if (annotationTypeElement.getQualifiedName().contentEquals(annotationClassName)) {
+ return Optional.of(annotationMirror);
+ }
+ }
+ return Optional.empty();
}
- public static ImmutableSet<String> suppressedWarnings(Element element) {
- SuppressWarnings suppressedWarnings = element.getAnnotation(SuppressWarnings.class);
- if (suppressedWarnings == null) {
- return ImmutableSet.of();
- }
- return ImmutableSet.copyOf(suppressedWarnings.value());
+ public static ImmutableSet<? extends AnnotationMirror> getAnnotatedAnnotations(
+ Element element, ClassName annotationName) {
+ return element.getAnnotationMirrors().stream()
+ .filter(input -> isAnnotationPresent(input.getAnnotationType().asElement(), annotationName))
+ .collect(toImmutableSet());
}
/**
@@ -275,6 +220,20 @@ public final class DaggerElements implements Elements, ClearableCache {
* href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.3">JVM
* specification, section 4.3.3</a>.
*/
+ // TODO(bcorso): Expose getMethodDescriptor() method in XProcessing instead.
+ public static String getMethodDescriptor(XMethodElement element) {
+ return getMethodDescriptor(toJavac(element));
+ }
+
+ /**
+ * Returns the method descriptor of the given {@code element}.
+ *
+ * <p>This is useful for matching Kotlin Metadata JVM Signatures with elements from the AST.
+ *
+ * <p>For reference, see the <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.3">JVM
+ * specification, section 4.3.3</a>.
+ */
public static String getMethodDescriptor(ExecutableElement element) {
return element.getSimpleName() + getDescriptor(element.asType());
}
@@ -283,8 +242,8 @@ public final class DaggerElements implements Elements, ClearableCache {
return t.accept(JVM_DESCRIPTOR_TYPE_VISITOR, null);
}
- private static final AbstractTypeVisitor8<String, Void> JVM_DESCRIPTOR_TYPE_VISITOR =
- new AbstractTypeVisitor8<String, Void>() {
+ private static final SimpleTypeVisitor8<String, Void> JVM_DESCRIPTOR_TYPE_VISITOR =
+ new SimpleTypeVisitor8<String, Void>() {
@Override
public String visitArray(ArrayType arrayType, Void v) {
@@ -326,11 +285,6 @@ public final class DaggerElements implements Elements, ClearableCache {
}
@Override
- public String visitNull(NullType nullType, Void v) {
- return visitUnknown(nullType, null);
- }
-
- @Override
public String visitPrimitive(PrimitiveType primitiveType, Void v) {
switch (primitiveType.getKind()) {
case BOOLEAN:
@@ -361,12 +315,7 @@ public final class DaggerElements implements Elements, ClearableCache {
}
@Override
- public String visitUnion(UnionType unionType, Void v) {
- return visitUnknown(unionType, null);
- }
-
- @Override
- public String visitUnknown(TypeMirror typeMirror, Void v) {
+ public String defaultAction(TypeMirror typeMirror, Void v) {
throw new IllegalArgumentException("Unsupported type: " + typeMirror);
}
@@ -408,18 +357,6 @@ public final class DaggerElements implements Elements, ClearableCache {
}
};
- /**
- * Invokes {@link Elements#getTypeElement(CharSequence)}, throwing {@link TypeNotPresentException}
- * if it is not accessible in the current compilation.
- */
- public TypeElement checkTypePresent(String typeName) {
- TypeElement type = elements.getTypeElement(typeName);
- if (type == null) {
- throw new TypeNotPresentException(typeName, null);
- }
- return type;
- }
-
@Override
public PackageElement getPackageElement(CharSequence name) {
return elements.getPackageElement(name);
@@ -491,8 +428,8 @@ public final class DaggerElements implements Elements, ClearableCache {
}
@Override
- public Name getName(CharSequence cs) {
- return elements.getName(cs);
+ public Name getName(CharSequence cs) { // SUPPRESS_GET_NAME_CHECK: This is not xprocessing usage.
+ return elements.getName(cs); // SUPPRESS_GET_NAME_CHECK: This is not xprocessing usage.
}
@Override
diff --git a/java/dagger/internal/codegen/langmodel/DaggerTypes.java b/java/dagger/internal/codegen/langmodel/DaggerTypes.java
index fb291dbdb..855e739e4 100644
--- a/java/dagger/internal/codegen/langmodel/DaggerTypes.java
+++ b/java/dagger/internal/codegen/langmodel/DaggerTypes.java
@@ -16,23 +16,28 @@
package dagger.internal.codegen.langmodel;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static com.google.auto.common.MoreTypes.asDeclared;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.common.MoreElements;
import com.google.auto.common.MoreTypes;
import com.google.common.collect.ImmutableSet;
import com.google.common.graph.Traverser;
import com.google.common.util.concurrent.FluentFuture;
import com.google.common.util.concurrent.ListenableFuture;
+import com.squareup.javapoet.ArrayTypeName;
import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.TypeName;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
-import javax.inject.Inject;
import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
@@ -43,7 +48,6 @@ import javax.lang.model.type.NullType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.SimpleTypeVisitor8;
import javax.lang.model.util.Types;
@@ -53,12 +57,94 @@ public final class DaggerTypes implements Types {
private final Types types;
private final DaggerElements elements;
- @Inject
public DaggerTypes(Types types, DaggerElements elements) {
this.types = checkNotNull(types);
this.elements = checkNotNull(elements);
}
+ // Note: This is similar to auto-common's MoreTypes except using ClassName rather than Class.
+ // TODO(bcorso): Contribute a String version to auto-common's MoreTypes?
+ /**
+ * Returns true if the raw type underlying the given {@link TypeMirror} represents the same raw
+ * type as the given {@link Class} and throws an IllegalArgumentException if the {@link
+ * TypeMirror} does not represent a type that can be referenced by a {@link Class}
+ */
+ public static boolean isTypeOf(final TypeName typeName, TypeMirror type) {
+ checkNotNull(typeName);
+ return type.accept(new IsTypeOf(typeName), null);
+ }
+
+ private static final class IsTypeOf extends SimpleTypeVisitor8<Boolean, Void> {
+ private final TypeName typeName;
+
+ IsTypeOf(TypeName typeName) {
+ this.typeName = typeName;
+ }
+
+ @Override
+ protected Boolean defaultAction(TypeMirror type, Void ignored) {
+ throw new IllegalArgumentException(type + " cannot be represented as a Class<?>.");
+ }
+
+ @Override
+ public Boolean visitNoType(NoType noType, Void p) {
+ if (noType.getKind().equals(TypeKind.VOID)) {
+ return typeName.equals(TypeName.VOID);
+ }
+ throw new IllegalArgumentException(noType + " cannot be represented as a Class<?>.");
+ }
+
+ @Override
+ public Boolean visitError(ErrorType errorType, Void p) {
+ return false;
+ }
+
+ @Override
+ public Boolean visitPrimitive(PrimitiveType type, Void p) {
+ switch (type.getKind()) {
+ case BOOLEAN:
+ return typeName.equals(TypeName.BOOLEAN);
+ case BYTE:
+ return typeName.equals(TypeName.BYTE);
+ case CHAR:
+ return typeName.equals(TypeName.CHAR);
+ case DOUBLE:
+ return typeName.equals(TypeName.DOUBLE);
+ case FLOAT:
+ return typeName.equals(TypeName.FLOAT);
+ case INT:
+ return typeName.equals(TypeName.INT);
+ case LONG:
+ return typeName.equals(TypeName.LONG);
+ case SHORT:
+ return typeName.equals(TypeName.SHORT);
+ default:
+ throw new IllegalArgumentException(type + " cannot be represented as a Class<?>.");
+ }
+ }
+
+ @Override
+ public Boolean visitArray(ArrayType array, Void p) {
+ return (typeName instanceof ArrayTypeName)
+ && isTypeOf(((ArrayTypeName) typeName).componentType, array.getComponentType());
+ }
+
+ @Override
+ public Boolean visitDeclared(DeclaredType type, Void ignored) {
+ TypeElement typeElement = MoreElements.asType(type.asElement());
+ return (typeName instanceof ClassName)
+ && typeElement.getQualifiedName().contentEquals(((ClassName) typeName).canonicalName());
+ }
+ }
+
+ /**
+ * Returns the non-{@link Object} superclass of the type with the proper type parameters. An empty
+ * {@link Optional} is returned if there is no non-{@link Object} superclass.
+ */
+ public Optional<DeclaredType> nonObjectSuperclass(XType type) {
+ return isDeclared(type) ? nonObjectSuperclass(asDeclared(toJavac(type))) : Optional.empty();
+ }
+
/**
* Returns the non-{@link Object} superclass of the type with the proper type parameters. An empty
* {@link Optional} is returned if there is no non-{@link Object} superclass.
@@ -83,22 +169,24 @@ public final class DaggerTypes implements Types {
* @throws IllegalArgumentException if {@code type} is not a declared type or has zero or more
* than one type arguments.
*/
- public static TypeMirror unwrapType(TypeMirror type) {
- TypeMirror unwrapped = unwrapTypeOrDefault(type, null);
+ public static XType unwrapType(XType type) {
+ XType unwrapped = unwrapTypeOrDefault(type, null);
checkArgument(unwrapped != null, "%s is a raw type", type);
return unwrapped;
}
/**
- * Returns {@code type}'s single type argument, if one exists, or {@link Object} if not.
+ * Returns {@code type}'s single type argument.
*
* <p>For example, if {@code type} is {@code List<Number>} this will return {@code Number}.
*
- * @throws IllegalArgumentException if {@code type} is not a declared type or has more than one
- * type argument.
+ * @throws IllegalArgumentException if {@code type} is not a declared type or has zero or more
+ * than one type arguments.
*/
- public TypeMirror unwrapTypeOrObject(TypeMirror type) {
- return unwrapTypeOrDefault(type, elements.getTypeElement(Object.class).asType());
+ public static TypeMirror unwrapType(TypeMirror type) {
+ TypeMirror unwrapped = unwrapTypeOrDefault(type, null);
+ checkArgument(unwrapped != null, "%s is a raw type", type);
+ return unwrapped;
}
private static TypeMirror unwrapTypeOrDefault(TypeMirror type, TypeMirror defaultType) {
@@ -111,14 +199,48 @@ public final class DaggerTypes implements Types {
return getOnlyElement(declaredType.getTypeArguments(), defaultType);
}
+ private static XType unwrapTypeOrDefault(XType type, XType defaultType) {
+ // Check the type parameters of the element's XType since the input XType could be raw.
+ checkArgument(isDeclared(type));
+ XTypeElement typeElement = type.getTypeElement();
+ checkArgument(
+ typeElement.getType().getTypeArguments().size() == 1,
+ "%s does not have exactly 1 type parameter. Found: %s",
+ typeElement.getQualifiedName(),
+ typeElement.getType().getTypeArguments());
+ return getOnlyElement(type.getTypeArguments(), defaultType);
+ }
+
+ /**
+ * Returns {@code type}'s single type argument, if one exists, or {@link Object} if not.
+ *
+ * <p>For example, if {@code type} is {@code List<Number>} this will return {@code Number}.
+ *
+ * @throws IllegalArgumentException if {@code type} is not a declared type or has more than one
+ * type argument.
+ */
+ public TypeMirror unwrapTypeOrObject(TypeMirror type) {
+ return unwrapTypeOrDefault(type, elements.getTypeElement(TypeName.OBJECT).asType());
+ }
+
+ /**
+ * Returns {@code type} wrapped in {@code wrappingClass}.
+ *
+ * <p>For example, if {@code type} is {@code List<Number>} and {@code wrappingClass} is {@code
+ * Set.class}, this will return {@code Set<List<Number>>}.
+ */
+ public DeclaredType wrapType(XType type, ClassName wrappingClassName) {
+ return wrapType(toJavac(type), wrappingClassName);
+ }
+
/**
* Returns {@code type} wrapped in {@code wrappingClass}.
*
* <p>For example, if {@code type} is {@code List<Number>} and {@code wrappingClass} is {@code
* Set.class}, this will return {@code Set<List<Number>>}.
*/
- public DeclaredType wrapType(TypeMirror type, Class<?> wrappingClass) {
- return types.getDeclaredType(elements.getTypeElement(wrappingClass), type);
+ public DeclaredType wrapType(TypeMirror type, ClassName wrappingClassName) {
+ return types.getDeclaredType(elements.getTypeElement(wrappingClassName.canonicalName()), type);
}
/**
@@ -132,9 +254,9 @@ public final class DaggerTypes implements Types {
*
* @throws IllegalArgumentException if {@code} has more than one type argument.
*/
- public DeclaredType rewrapType(TypeMirror type, Class<?> wrappingClass) {
+ public DeclaredType rewrapType(TypeMirror type, ClassName wrappingClassName) {
List<? extends TypeMirror> typeArguments = MoreTypes.asDeclared(type).getTypeArguments();
- TypeElement wrappingType = elements.getTypeElement(wrappingClass);
+ TypeElement wrappingType = elements.getTypeElement(wrappingClassName.canonicalName());
switch (typeArguments.size()) {
case 0:
return getDeclaredType(wrappingType);
@@ -146,17 +268,16 @@ public final class DaggerTypes implements Types {
}
/**
- * Returns a publicly accessible type based on {@code type}:
+ * Returns an accessible type in {@code requestingClass}'s package based on {@code type}:
*
* <ul>
- * <li>If {@code type} is publicly accessible, returns it.
- * <li>If not, but {@code type}'s raw type is publicly accessible, returns the raw type.
+ * <li>If {@code type} is accessible from the package, returns it.
+ * <li>If not, but {@code type}'s raw type is accessible from the package, returns the raw type.
* <li>Otherwise returns {@link Object}.
* </ul>
*/
- public TypeMirror publiclyAccessibleType(TypeMirror type) {
- return accessibleType(
- type, Accessibility::isTypePubliclyAccessible, Accessibility::isRawTypePubliclyAccessible);
+ public TypeMirror accessibleType(XType type, ClassName requestingClass) {
+ return accessibleType(toJavac(type), requestingClass);
}
/**
@@ -185,7 +306,7 @@ public final class DaggerTypes implements Types {
&& rawTypeAccessibilityPredicate.test(type)) {
return getDeclaredType(MoreTypes.asTypeElement(type));
} else {
- return elements.getTypeElement(Object.class).asType();
+ return elements.getTypeElement(TypeName.OBJECT).asType();
}
}
@@ -220,42 +341,12 @@ public final class DaggerTypes implements Types {
private static final ImmutableSet<Class<?>> FUTURE_TYPES =
ImmutableSet.of(ListenableFuture.class, FluentFuture.class);
- public static boolean isFutureType(TypeMirror type) {
- return FUTURE_TYPES.stream().anyMatch(t -> MoreTypes.isTypeOf(t, type));
- }
-
- public static boolean hasTypeVariable(TypeMirror type) {
- return type.accept(
- new SimpleTypeVisitor8<Boolean, Void>() {
- @Override
- public Boolean visitArray(ArrayType arrayType, Void p) {
- return arrayType.getComponentType().accept(this, p);
- }
-
- @Override
- public Boolean visitDeclared(DeclaredType declaredType, Void p) {
- return declaredType.getTypeArguments().stream().anyMatch(type -> type.accept(this, p));
- }
-
- @Override
- public Boolean visitTypeVariable(TypeVariable t, Void aVoid) {
- return true;
- }
-
- @Override
- protected Boolean defaultAction(TypeMirror e, Void aVoid) {
- return false;
- }
- },
- null);
+ public static boolean isFutureType(XType type) {
+ return isFutureType(toJavac(type));
}
- /**
- * Resolves the type of the given executable element as a member of the given type. This may
- * resolve type variables to concrete types, etc.
- */
- public ExecutableType resolveExecutableType(ExecutableElement element, TypeMirror containerType) {
- return MoreTypes.asExecutable(asMemberOf(MoreTypes.asDeclared(containerType), element));
+ public static boolean isFutureType(TypeMirror type) {
+ return FUTURE_TYPES.stream().anyMatch(t -> MoreTypes.isTypeOf(t, type));
}
// Implementation of Types methods, delegating to types.
@@ -270,6 +361,10 @@ public final class DaggerTypes implements Types {
return types.isSameType(t1, t2);
}
+ public boolean isSubtype(XType t1, XType t2) {
+ return isSubtype(toJavac(t1), toJavac(t2));
+ }
+
@Override
public boolean isSubtype(TypeMirror t1, TypeMirror t2) {
return types.isSubtype(t1, t2);
diff --git a/java/dagger/internal/codegen/validation/AnyBindingMethodValidator.java b/java/dagger/internal/codegen/validation/AnyBindingMethodValidator.java
index 140afd215..896ba1598 100644
--- a/java/dagger/internal/codegen/validation/AnyBindingMethodValidator.java
+++ b/java/dagger/internal/codegen/validation/AnyBindingMethodValidator.java
@@ -16,33 +16,32 @@
package dagger.internal.codegen.validation;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static dagger.internal.codegen.xprocessing.XElements.hasAnyAnnotation;
import static java.util.stream.Collectors.joining;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XMethodElement;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.base.ClearableCache;
-import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
-import javax.lang.model.element.ExecutableElement;
/** Validates any binding method. */
@Singleton
public final class AnyBindingMethodValidator implements ClearableCache {
- private final ImmutableMap<Class<? extends Annotation>, BindingMethodValidator> validators;
- private final Map<ExecutableElement, ValidationReport<ExecutableElement>> reports =
- new HashMap<>();
+ private final ImmutableMap<ClassName, BindingMethodValidator> validators;
+ private final Map<XMethodElement, ValidationReport> reports = new HashMap<>();
@Inject
- AnyBindingMethodValidator(
- ImmutableMap<Class<? extends Annotation>, BindingMethodValidator> validators) {
+ AnyBindingMethodValidator(ImmutableMap<ClassName, BindingMethodValidator> validators) {
this.validators = validators;
}
@@ -52,7 +51,7 @@ public final class AnyBindingMethodValidator implements ClearableCache {
}
/** Returns the binding method annotations considered by this validator. */
- ImmutableSet<Class<? extends Annotation>> methodAnnotations() {
+ ImmutableSet<ClassName> methodAnnotations() {
return validators.keySet();
}
@@ -60,8 +59,8 @@ public final class AnyBindingMethodValidator implements ClearableCache {
* Returns {@code true} if {@code method} is annotated with at least one of {@link
* #methodAnnotations()}.
*/
- boolean isBindingMethod(ExecutableElement method) {
- return isAnyAnnotationPresent(method, methodAnnotations());
+ boolean isBindingMethod(XExecutableElement method) {
+ return hasAnyAnnotation(method, methodAnnotations());
}
/**
@@ -77,25 +76,22 @@ public final class AnyBindingMethodValidator implements ClearableCache {
* @throws IllegalArgumentException if {@code method} is not annotated by any {@linkplain
* #methodAnnotations() binding method annotation}
*/
- ValidationReport<ExecutableElement> validate(ExecutableElement method) {
+ ValidationReport validate(XMethodElement method) {
return reentrantComputeIfAbsent(reports, method, this::validateUncached);
}
/**
- * Returns {@code true} if {@code method} was already {@linkplain #validate(ExecutableElement)
+ * Returns {@code true} if {@code method} was already {@linkplain #validate(XMethodElement)
* validated}.
*/
- boolean wasAlreadyValidated(ExecutableElement method) {
+ boolean wasAlreadyValidated(XMethodElement method) {
return reports.containsKey(method);
}
- private ValidationReport<ExecutableElement> validateUncached(ExecutableElement method) {
- ValidationReport.Builder<ExecutableElement> report = ValidationReport.about(method);
- ImmutableSet<? extends Class<? extends Annotation>> bindingMethodAnnotations =
- methodAnnotations()
- .stream()
- .filter(annotation -> isAnnotationPresent(method, annotation))
- .collect(toImmutableSet());
+ private ValidationReport validateUncached(XMethodElement method) {
+ ValidationReport.Builder report = ValidationReport.about(method);
+ ImmutableSet<ClassName> bindingMethodAnnotations =
+ methodAnnotations().stream().filter(method::hasAnnotation).collect(toImmutableSet());
switch (bindingMethodAnnotations.size()) {
case 0:
throw new IllegalArgumentException(
@@ -110,8 +106,8 @@ public final class AnyBindingMethodValidator implements ClearableCache {
report.addError(
String.format(
"%s is annotated with more than one of (%s)",
- method.getSimpleName(),
- methodAnnotations().stream().map(Class::getCanonicalName).collect(joining(", "))),
+ getSimpleName(method),
+ methodAnnotations().stream().map(ClassName::canonicalName).collect(joining(", "))),
method);
break;
}
diff --git a/java/dagger/internal/codegen/validation/BUILD b/java/dagger/internal/codegen/validation/BUILD
index 602157b2f..d41215a9b 100644
--- a/java/dagger/internal/codegen/validation/BUILD
+++ b/java/dagger/internal/codegen/validation/BUILD
@@ -33,18 +33,19 @@ java_library(
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/kotlin",
"//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:cache",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "//java/dagger/internal/guava:graph",
- "//java/dagger/producers",
+ "//java/dagger/internal/codegen/xprocessing",
"//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/checker_framework_annotations",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:value",
+ "//third_party/java/checker_framework_annotations",
+ "//third_party/java/error_prone:annotations",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/cache",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/graph",
+ "//third_party/java/guava/util/concurrent",
+ "//third_party/java/javapoet",
+ "//third_party/java/jsr330_inject",
+ "@maven//:org_jetbrains_kotlin_kotlin_stdlib_jdk8",
],
)
diff --git a/java/dagger/internal/codegen/validation/BindingElementValidator.java b/java/dagger/internal/codegen/validation/BindingElementValidator.java
index b8f9912b4..d4b405ecd 100644
--- a/java/dagger/internal/codegen/validation/BindingElementValidator.java
+++ b/java/dagger/internal/codegen/validation/BindingElementValidator.java
@@ -16,77 +16,73 @@
package dagger.internal.codegen.validation;
-import static com.google.auto.common.MoreTypes.asTypeElement;
+import static androidx.room.compiler.processing.XTypeKt.isArray;
+import static androidx.room.compiler.processing.XTypeKt.isVoid;
import static com.google.common.base.Verify.verifyNotNull;
-import static dagger.internal.codegen.base.Scopes.scopesOf;
+import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedFactoryType;
import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedInjectionType;
import static dagger.internal.codegen.binding.MapKeys.getMapKeys;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
-import static javax.lang.model.type.TypeKind.ARRAY;
-import static javax.lang.model.type.TypeKind.DECLARED;
-import static javax.lang.model.type.TypeKind.TYPEVAR;
-import static javax.lang.model.type.TypeKind.VOID;
-
-import com.google.common.collect.ImmutableCollection;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
+import static dagger.internal.codegen.xprocessing.XTypes.isPrimitive;
+import static dagger.internal.codegen.xprocessing.XTypes.isTypeVariable;
+
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.FormatMethod;
-import dagger.MapKey;
-import dagger.Provides;
+import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.base.ContributionType;
import dagger.internal.codegen.base.FrameworkTypes;
-import dagger.internal.codegen.base.MultibindingAnnotations;
import dagger.internal.codegen.base.SetType;
import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.model.Key;
-import dagger.model.Scope;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntoMap;
-import dagger.producers.Produces;
-import java.lang.annotation.Annotation;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.xprocessing.XElements;
+import dagger.spi.model.Key;
+import dagger.spi.model.Scope;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
+import javax.inject.Inject;
import javax.inject.Qualifier;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
/** A validator for elements that represent binding declarations. */
-public abstract class BindingElementValidator<E extends Element> {
- private final Class<? extends Annotation> bindingAnnotation;
+public abstract class BindingElementValidator<E extends XElement> {
+ private static final ImmutableSet<ClassName> MULTIBINDING_ANNOTATIONS =
+ ImmutableSet.of(TypeNames.INTO_SET, TypeNames.ELEMENTS_INTO_SET, TypeNames.INTO_MAP);
+
+ // TODO(bcorso): Inject this directly into InjectionAnnotations instead of using field injection.
+ @Inject XProcessingEnv processingEnv;
+
private final AllowsMultibindings allowsMultibindings;
private final AllowsScoping allowsScoping;
- private final Map<E, ValidationReport<E>> cache = new HashMap<>();
+ private final Map<E, ValidationReport> cache = new HashMap<>();
private final InjectionAnnotations injectionAnnotations;
- /**
- * Creates a validator object.
- *
- * @param bindingAnnotation the annotation on an element that identifies it as a binding element
- */
+ /** Creates a validator object. */
+ // TODO(bcorso): Consider reworking BindingElementValidator and all subclasses to use composition
+ // rather than inheritance. The web of inheritance makes it difficult to track what implementation
+ // of a method is actually being used.
protected BindingElementValidator(
- Class<? extends Annotation> bindingAnnotation,
AllowsMultibindings allowsMultibindings,
AllowsScoping allowsScoping,
InjectionAnnotations injectionAnnotations) {
- this.bindingAnnotation = bindingAnnotation;
this.allowsMultibindings = allowsMultibindings;
this.allowsScoping = allowsScoping;
this.injectionAnnotations = injectionAnnotations;
}
/** Returns a {@link ValidationReport} for {@code element}. */
- final ValidationReport<E> validate(E element) {
+ final ValidationReport validate(E element) {
return reentrantComputeIfAbsent(cache, element, this::validateUncached);
}
- private ValidationReport<E> validateUncached(E element) {
+ private ValidationReport validateUncached(E element) {
return elementValidator(element).validate();
}
@@ -118,7 +114,7 @@ public abstract class BindingElementValidator<E extends Element> {
/**
* The error message when a the type for a binding element with {@link
- * ElementsIntoSet @ElementsIntoSet} or {@code SET_VALUES} is a not set type.
+ * dagger.multibindings.ElementsIntoSet @ElementsIntoSet} or {@code SET_VALUES} is a not set type.
*/
protected String elementsIntoSetNotASetMessage() {
return bindingElements(
@@ -127,7 +123,7 @@ public abstract class BindingElementValidator<E extends Element> {
/**
* The error message when a the type for a binding element with {@link
- * ElementsIntoSet @ElementsIntoSet} or {@code SET_VALUES} is a raw set.
+ * dagger.multibindings.ElementsIntoSet @ElementsIntoSet} or {@code SET_VALUES} is a raw set.
*/
protected String elementsIntoSetRawSetMessage() {
return bindingElements(
@@ -139,9 +135,9 @@ public abstract class BindingElementValidator<E extends Element> {
/** Validator for a single binding element. */
protected abstract class ElementValidator {
- protected final E element;
- protected final ValidationReport.Builder<E> report;
- private final ImmutableCollection<? extends AnnotationMirror> qualifiers;
+ private final E element;
+ protected final ValidationReport.Builder report;
+ private final ImmutableSet<XAnnotation> qualifiers;
protected ElementValidator(E element) {
this.element = element;
@@ -150,7 +146,7 @@ public abstract class BindingElementValidator<E extends Element> {
}
/** Checks the element for validity. */
- private ValidationReport<E> validate() {
+ private ValidationReport validate() {
checkType();
checkQualifiers();
checkMapKeys();
@@ -169,8 +165,8 @@ public abstract class BindingElementValidator<E extends Element> {
* that the contributed type is ambiguous or missing, i.e. a {@code @BindsInstance} method with
* zero or many parameters.
*/
- // TODO(dpb): should this be an ImmutableList<TypeMirror>, with this class checking the size?
- protected abstract Optional<TypeMirror> bindingElementType();
+ // TODO(dpb): should this be an ImmutableList<XType>, with this class checking the size?
+ protected abstract Optional<XType> bindingElementType();
/**
* Adds an error if the {@link #bindingElementType() binding element type} is not appropriate.
@@ -180,8 +176,8 @@ public abstract class BindingElementValidator<E extends Element> {
* <p>If the binding is not a multibinding contribution, adds an error if the type is a
* framework type.
*
- * <p>If the element has {@link ElementsIntoSet @ElementsIntoSet} or {@code SET_VALUES}, adds an
- * error if the type is not a {@code Set<T>} for some {@code T}
+ * <p>If the element has {@link dagger.multibindings.ElementsIntoSet @ElementsIntoSet} or {@code
+ * SET_VALUES}, adds an error if the type is not a {@code Set<T>} for some {@code T}
*/
protected void checkType() {
switch (ContributionType.fromBindingElement(element)) {
@@ -199,7 +195,7 @@ public abstract class BindingElementValidator<E extends Element> {
case SET:
case MAP:
- bindingElementType().ifPresent(type -> checkKeyType(type));
+ bindingElementType().ifPresent(this::checkKeyType);
break;
case SET_VALUES:
@@ -210,14 +206,13 @@ public abstract class BindingElementValidator<E extends Element> {
/**
* Adds an error if {@code keyType} is not a primitive, declared type, array, or type variable.
*/
- protected void checkKeyType(TypeMirror keyType) {
- TypeKind kind = keyType.getKind();
- if (kind.equals(VOID)) {
+ protected void checkKeyType(XType keyType) {
+ if (isVoid(keyType)) {
report.addError(bindingElements("must %s a value (not void)", bindingElementTypeVerb()));
- } else if (!(kind.isPrimitive()
- || kind.equals(DECLARED)
- || kind.equals(ARRAY)
- || kind.equals(TYPEVAR))) {
+ } else if (!(isPrimitive(keyType)
+ || isDeclared(keyType)
+ || isArray(keyType)
+ || isTypeVariable(keyType))) {
report.addError(badTypeMessage());
}
}
@@ -225,9 +220,9 @@ public abstract class BindingElementValidator<E extends Element> {
/** Adds errors for unqualified assisted types. */
private void checkAssistedType() {
if (qualifiers.isEmpty()
- && bindingElementType().isPresent()
- && bindingElementType().get().getKind() == DECLARED) {
- TypeElement keyElement = asTypeElement(bindingElementType().get());
+ && bindingElementType().isPresent()
+ && isDeclared(bindingElementType().get())) {
+ XTypeElement keyElement = bindingElementType().get().getTypeElement();
if (isAssistedInjectionType(keyElement)) {
report.addError("Dagger does not support providing @AssistedInject types.", keyElement);
}
@@ -238,16 +233,17 @@ public abstract class BindingElementValidator<E extends Element> {
}
/**
- * Adds an error if the type for an element with {@link ElementsIntoSet @ElementsIntoSet} or
- * {@code SET_VALUES} is not a a {@code Set<T>} for a reasonable {@code T}.
+ * Adds an error if the type for an element with {@link
+ * dagger.multibindings.ElementsIntoSet @ElementsIntoSet} or {@code SET_VALUES} is not a a
+ * {@code Set<T>} for a reasonable {@code T}.
*/
// TODO(gak): should we allow "covariant return" for set values?
protected void checkSetValuesType() {
- bindingElementType().ifPresent(keyType -> checkSetValuesType(keyType));
+ bindingElementType().ifPresent(this::checkSetValuesType);
}
/** Adds an error if {@code type} is not a {@code Set<T>} for a reasonable {@code T}. */
- protected final void checkSetValuesType(TypeMirror type) {
+ protected final void checkSetValuesType(XType type) {
if (!SetType.isSet(type)) {
report.addError(elementsIntoSetNotASetMessage());
} else {
@@ -255,7 +251,10 @@ public abstract class BindingElementValidator<E extends Element> {
if (setType.isRawType()) {
report.addError(elementsIntoSetRawSetMessage());
} else {
- checkKeyType(setType.elementType());
+ // TODO(bcorso): Use setType.elementType() once setType is fully converted to XProcessing.
+ // However, currently SetType returns TypeMirror instead of XType and we have no
+ // conversion from TypeMirror to XType, so we just get the type ourselves.
+ checkKeyType(getOnlyElement(type.getTypeArguments()));
}
}
}
@@ -265,7 +264,7 @@ public abstract class BindingElementValidator<E extends Element> {
*/
private void checkQualifiers() {
if (qualifiers.size() > 1) {
- for (AnnotationMirror qualifier : qualifiers) {
+ for (XAnnotation qualifier : qualifiers) {
report.addError(
bindingElements("may not use more than one @Qualifier"),
element,
@@ -275,14 +274,15 @@ public abstract class BindingElementValidator<E extends Element> {
}
/**
- * Adds an error if an {@link IntoMap @IntoMap} element doesn't have exactly one {@link
- * MapKey @MapKey} annotation, or if an element that is {@link IntoMap @IntoMap} has any.
+ * Adds an error if an {@link dagger.multibindings.IntoMap @IntoMap} element doesn't have
+ * exactly one {@link dagger.MapKey @MapKey} annotation, or if an element that is {@link
+ * dagger.multibindings.IntoMap @IntoMap} has any.
*/
private void checkMapKeys() {
if (!allowsMultibindings.allowsMultibindings()) {
return;
}
- ImmutableSet<? extends AnnotationMirror> mapKeys = getMapKeys(element);
+ ImmutableSet<XAnnotation> mapKeys = getMapKeys(element);
if (ContributionType.fromBindingElement(element).equals(ContributionType.MAP)) {
switch (mapKeys.size()) {
case 0:
@@ -306,17 +306,17 @@ public abstract class BindingElementValidator<E extends Element> {
* <li>the element doesn't allow {@linkplain MultibindingAnnotations multibinding annotations}
* and has any
* <li>the element does allow them but has more than one
- * <li>the element has a multibinding annotation and its {@link Provides} or {@link Produces}
- * annotation has a {@code type} parameter.
+ * <li>the element has a multibinding annotation and its {@link dagger.Provides} or {@link
+ * dagger.producers.Produces} annotation has a {@code type} parameter.
* </ul>
*/
private void checkMultibindings() {
- ImmutableSet<AnnotationMirror> multibindingAnnotations =
- MultibindingAnnotations.forElement(element);
+ ImmutableSet<XAnnotation> multibindingAnnotations =
+ XElements.getAllAnnotations(element, MULTIBINDING_ANNOTATIONS);
switch (allowsMultibindings) {
case NO_MULTIBINDINGS:
- for (AnnotationMirror annotation : multibindingAnnotations) {
+ for (XAnnotation annotation : multibindingAnnotations) {
report.addError(
bindingElements("cannot have multibinding annotations"),
element,
@@ -326,7 +326,7 @@ public abstract class BindingElementValidator<E extends Element> {
case ALLOWS_MULTIBINDINGS:
if (multibindingAnnotations.size() > 1) {
- for (AnnotationMirror annotation : multibindingAnnotations) {
+ for (XAnnotation annotation : multibindingAnnotations) {
report.addError(
bindingElements("cannot have more than one multibinding annotation"),
element,
@@ -335,20 +335,6 @@ public abstract class BindingElementValidator<E extends Element> {
}
break;
}
-
- // TODO(ronshapiro): move this into ProvidesMethodValidator
- if (bindingAnnotation.equals(Provides.class)) {
- AnnotationMirror bindingAnnotationMirror =
- getAnnotationMirror(element, bindingAnnotation).get();
- boolean usesProvidesType = false;
- for (ExecutableElement member : bindingAnnotationMirror.getElementValues().keySet()) {
- usesProvidesType |= member.getSimpleName().contentEquals("type");
- }
- if (usesProvidesType && !multibindingAnnotations.isEmpty()) {
- report.addError(
- "@Provides.type cannot be used with multibinding annotations", element);
- }
- }
}
/**
@@ -356,7 +342,7 @@ public abstract class BindingElementValidator<E extends Element> {
* one {@linkplain Scope scope} annotation.
*/
private void checkScopes() {
- ImmutableSet<Scope> scopes = scopesOf(element);
+ ImmutableSet<Scope> scopes = injectionAnnotations.getScopes(element);
String error = null;
switch (allowsScoping) {
case ALLOWS_SCOPING:
@@ -371,7 +357,7 @@ public abstract class BindingElementValidator<E extends Element> {
}
verifyNotNull(error);
for (Scope scope : scopes) {
- report.addError(error, element, scope.scopeAnnotation());
+ report.addError(error, element, scope.scopeAnnotation().xprocessing());
}
}
diff --git a/java/dagger/internal/codegen/validation/BindingGraphValidator.java b/java/dagger/internal/codegen/validation/BindingGraphValidator.java
index 99e86e762..09477d848 100644
--- a/java/dagger/internal/codegen/validation/BindingGraphValidator.java
+++ b/java/dagger/internal/codegen/validation/BindingGraphValidator.java
@@ -16,41 +16,32 @@
package dagger.internal.codegen.validation;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import com.google.common.collect.ImmutableSet;
+import androidx.room.compiler.processing.XTypeElement;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.compileroption.ValidationType;
-import dagger.internal.codegen.validation.DiagnosticReporterFactory.DiagnosticReporterImpl;
-import dagger.model.BindingGraph;
-import dagger.spi.BindingGraphPlugin;
+import dagger.spi.model.BindingGraph;
import javax.inject.Inject;
import javax.inject.Singleton;
-import javax.lang.model.element.TypeElement;
/** Validates a {@link BindingGraph}. */
@Singleton
public final class BindingGraphValidator {
- private final ImmutableSet<BindingGraphPlugin> validationPlugins;
- private final ImmutableSet<BindingGraphPlugin> externalPlugins;
- private final DiagnosticReporterFactory diagnosticReporterFactory;
+ private final ValidationBindingGraphPlugins validationPlugins;
+ private final ExternalBindingGraphPlugins externalPlugins;
private final CompilerOptions compilerOptions;
@Inject
BindingGraphValidator(
- @Validation ImmutableSet<BindingGraphPlugin> validationPlugins,
- ImmutableSet<BindingGraphPlugin> externalPlugins,
- DiagnosticReporterFactory diagnosticReporterFactory,
+ ValidationBindingGraphPlugins validationPlugins,
+ ExternalBindingGraphPlugins externalPlugins,
CompilerOptions compilerOptions) {
this.validationPlugins = validationPlugins;
this.externalPlugins = externalPlugins;
- this.diagnosticReporterFactory = checkNotNull(diagnosticReporterFactory);
this.compilerOptions = compilerOptions;
}
/** Returns {@code true} if validation or analysis is required on the full binding graph. */
- public boolean shouldDoFullBindingGraphValidation(TypeElement component) {
+ public boolean shouldDoFullBindingGraphValidation(XTypeElement component) {
return requiresFullBindingGraphValidation()
|| compilerOptions.pluginsVisitFullBindingGraphs(component);
}
@@ -61,47 +52,29 @@ public final class BindingGraphValidator {
/** Returns {@code true} if no errors are reported for {@code graph}. */
public boolean isValid(BindingGraph graph) {
- return validate(graph) && visitPlugins(graph);
+ return visitValidationPlugins(graph) && visitExternalPlugins(graph);
}
/** Returns {@code true} if validation plugins report no errors. */
- private boolean validate(BindingGraph graph) {
+ private boolean visitValidationPlugins(BindingGraph graph) {
if (graph.isFullBindingGraph() && !requiresFullBindingGraphValidation()) {
return true;
}
- boolean errorsAsWarnings =
- graph.isFullBindingGraph()
- && compilerOptions.fullBindingGraphValidationType().equals(ValidationType.WARNING);
-
- return runPlugins(validationPlugins, graph, errorsAsWarnings);
+ return validationPlugins.visit(graph);
}
/** Returns {@code true} if external plugins report no errors. */
- private boolean visitPlugins(BindingGraph graph) {
- TypeElement component = graph.rootComponentNode().componentPath().currentComponent();
+ private boolean visitExternalPlugins(BindingGraph graph) {
if (graph.isFullBindingGraph()
// TODO(b/135938915): Consider not visiting plugins if only
// fullBindingGraphValidation is enabled.
&& !requiresFullBindingGraphValidation()
- && !compilerOptions.pluginsVisitFullBindingGraphs(component)) {
+ && !compilerOptions.pluginsVisitFullBindingGraphs(
+ graph.rootComponentNode().componentPath().currentComponent().xprocessing())) {
return true;
}
- return runPlugins(externalPlugins, graph, /*errorsAsWarnings=*/ false);
- }
- /** Returns {@code false} if any of the plugins reported an error. */
- private boolean runPlugins(
- ImmutableSet<BindingGraphPlugin> plugins, BindingGraph graph, boolean errorsAsWarnings) {
- boolean isClean = true;
- for (BindingGraphPlugin plugin : plugins) {
- DiagnosticReporterImpl reporter =
- diagnosticReporterFactory.reporter(graph, plugin, errorsAsWarnings);
- plugin.visitGraph(graph, reporter);
- if (reporter.reportedDiagnosticKinds().contains(ERROR)) {
- isClean = false;
- }
- }
- return isClean;
+ return externalPlugins.visit(graph);
}
}
diff --git a/java/dagger/internal/codegen/validation/BindingMethodProcessingStep.java b/java/dagger/internal/codegen/validation/BindingMethodProcessingStep.java
index 10aec063f..03aff8a85 100644
--- a/java/dagger/internal/codegen/validation/BindingMethodProcessingStep.java
+++ b/java/dagger/internal/codegen/validation/BindingMethodProcessingStep.java
@@ -18,37 +18,32 @@ package dagger.internal.codegen.validation;
import static com.google.common.base.Preconditions.checkArgument;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XMethodElement;
import com.google.common.collect.ImmutableSet;
-import java.lang.annotation.Annotation;
-import java.util.Set;
-import javax.annotation.processing.Messager;
+import com.squareup.javapoet.ClassName;
import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
/** A step that validates all binding methods that were not validated while processing modules. */
-public final class BindingMethodProcessingStep
- extends TypeCheckingProcessingStep<ExecutableElement> {
+public final class BindingMethodProcessingStep extends TypeCheckingProcessingStep<XMethodElement> {
- private final Messager messager;
+ private final XMessager messager;
private final AnyBindingMethodValidator anyBindingMethodValidator;
@Inject
BindingMethodProcessingStep(
- Messager messager, AnyBindingMethodValidator anyBindingMethodValidator) {
- super(MoreElements::asExecutable);
+ XMessager messager, AnyBindingMethodValidator anyBindingMethodValidator) {
this.messager = messager;
this.anyBindingMethodValidator = anyBindingMethodValidator;
}
@Override
- public Set<? extends Class<? extends Annotation>> annotations() {
+ public ImmutableSet<ClassName> annotationClassNames() {
return anyBindingMethodValidator.methodAnnotations();
}
@Override
- protected void process(
- ExecutableElement method, ImmutableSet<Class<? extends Annotation>> annotations) {
+ protected void process(XMethodElement method, ImmutableSet<ClassName> annotations) {
checkArgument(
anyBindingMethodValidator.isBindingMethod(method),
"%s is not annotated with any of %s",
diff --git a/java/dagger/internal/codegen/validation/BindingMethodValidator.java b/java/dagger/internal/codegen/validation/BindingMethodValidator.java
index 81349b9fb..1542b458f 100644
--- a/java/dagger/internal/codegen/validation/BindingMethodValidator.java
+++ b/java/dagger/internal/codegen/validation/BindingMethodValidator.java
@@ -16,34 +16,31 @@
package dagger.internal.codegen.validation;
-import static com.google.auto.common.MoreElements.asType;
-import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
+import static dagger.internal.codegen.xprocessing.XElements.hasAnyAnnotation;
+import static dagger.internal.codegen.xprocessing.XMethodElements.getEnclosingTypeElement;
+import static dagger.internal.codegen.xprocessing.XMethodElements.hasTypeParameters;
import static java.util.stream.Collectors.joining;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.PRIVATE;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.XVariableElement;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.FormatMethod;
+import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.lang.annotation.Annotation;
import java.util.Optional;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
/** A validator for methods that represent binding declarations. */
-abstract class BindingMethodValidator extends BindingElementValidator<ExecutableElement> {
+abstract class BindingMethodValidator extends BindingElementValidator<XMethodElement> {
- private final DaggerElements elements;
private final DaggerTypes types;
- private final KotlinMetadataUtil metadataUtil;
private final DependencyRequestValidator dependencyRequestValidator;
- private final Class<? extends Annotation> methodAnnotation;
- private final ImmutableSet<? extends Class<? extends Annotation>> enclosingElementAnnotations;
+ private final ClassName methodAnnotation;
+ private final ImmutableSet<ClassName> enclosingElementAnnotations;
private final Abstractness abstractness;
private final ExceptionSuperclass exceptionSuperclass;
@@ -55,21 +52,17 @@ abstract class BindingMethodValidator extends BindingElementValidator<Executable
* with this annotation
*/
protected BindingMethodValidator(
- DaggerElements elements,
DaggerTypes types,
- KotlinMetadataUtil metadataUtil,
DependencyRequestValidator dependencyRequestValidator,
- Class<? extends Annotation> methodAnnotation,
- Class<? extends Annotation> enclosingElementAnnotation,
+ ClassName methodAnnotation,
+ ClassName enclosingElementAnnotation,
Abstractness abstractness,
ExceptionSuperclass exceptionSuperclass,
AllowsMultibindings allowsMultibindings,
AllowsScoping allowsScoping,
InjectionAnnotations injectionAnnotations) {
this(
- elements,
types,
- metadataUtil,
methodAnnotation,
ImmutableSet.of(enclosingElementAnnotation),
dependencyRequestValidator,
@@ -88,21 +81,17 @@ abstract class BindingMethodValidator extends BindingElementValidator<Executable
* annotated with one of these annotations
*/
protected BindingMethodValidator(
- DaggerElements elements,
DaggerTypes types,
- KotlinMetadataUtil metadataUtil,
- Class<? extends Annotation> methodAnnotation,
- Iterable<? extends Class<? extends Annotation>> enclosingElementAnnotations,
+ ClassName methodAnnotation,
+ Iterable<ClassName> enclosingElementAnnotations,
DependencyRequestValidator dependencyRequestValidator,
Abstractness abstractness,
ExceptionSuperclass exceptionSuperclass,
AllowsMultibindings allowsMultibindings,
AllowsScoping allowsScoping,
InjectionAnnotations injectionAnnotations) {
- super(methodAnnotation, allowsMultibindings, allowsScoping, injectionAnnotations);
- this.elements = elements;
+ super(allowsMultibindings, allowsScoping, injectionAnnotations);
this.types = types;
- this.metadataUtil = metadataUtil;
this.methodAnnotation = methodAnnotation;
this.enclosingElementAnnotations = ImmutableSet.copyOf(enclosingElementAnnotations);
this.dependencyRequestValidator = dependencyRequestValidator;
@@ -111,7 +100,7 @@ abstract class BindingMethodValidator extends BindingElementValidator<Executable
}
/** The annotation that identifies binding methods validated by this object. */
- final Class<? extends Annotation> methodAnnotation() {
+ final ClassName methodAnnotation() {
return methodAnnotation;
}
@@ -127,7 +116,7 @@ abstract class BindingMethodValidator extends BindingElementValidator<Executable
@Override
protected final String bindingElements() {
- return String.format("@%s methods", methodAnnotation.getSimpleName());
+ return String.format("@%s methods", methodAnnotation.simpleName());
}
@Override
@@ -137,13 +126,16 @@ abstract class BindingMethodValidator extends BindingElementValidator<Executable
/** Abstract validator for individual binding method elements. */
protected abstract class MethodValidator extends ElementValidator {
- protected MethodValidator(ExecutableElement element) {
- super(element);
+ private final XMethodElement method;
+
+ protected MethodValidator(XMethodElement method) {
+ super(method);
+ this.method = method;
}
@Override
- protected final Optional<TypeMirror> bindingElementType() {
- return Optional.of(element.getReturnType());
+ protected final Optional<XType> bindingElementType() {
+ return Optional.of(method.getReturnType());
}
@Override
@@ -165,38 +157,38 @@ abstract class BindingMethodValidator extends BindingElementValidator<Executable
* {@link #enclosingElementAnnotations}.
*/
private void checkEnclosingElement() {
- TypeElement enclosingElement = asType(element.getEnclosingElement());
- if (metadataUtil.isCompanionObjectClass(enclosingElement)) {
+ XTypeElement enclosingTypeElement = getEnclosingTypeElement(method);
+ if (enclosingTypeElement.isCompanionObject()) {
// Binding method is in companion object, use companion object's enclosing class instead.
- enclosingElement = asType(enclosingElement.getEnclosingElement());
+ enclosingTypeElement = enclosingTypeElement.getEnclosingTypeElement();
}
- if (!isAnyAnnotationPresent(enclosingElement, enclosingElementAnnotations)) {
+ if (!hasAnyAnnotation(enclosingTypeElement, enclosingElementAnnotations)) {
report.addError(
bindingMethods(
"can only be present within a @%s",
enclosingElementAnnotations.stream()
- .map(Class::getSimpleName)
+ .map(ClassName::simpleName)
.collect(joining(" or @"))));
}
}
/** Adds an error if the method is generic. */
private void checkTypeParameters() {
- if (!element.getTypeParameters().isEmpty()) {
+ if (hasTypeParameters(method)) {
report.addError(bindingMethods("may not have type parameters"));
}
}
/** Adds an error if the method is private. */
private void checkNotPrivate() {
- if (element.getModifiers().contains(PRIVATE)) {
+ if (method.isPrivate()) {
report.addError(bindingMethods("cannot be private"));
}
}
/** Adds an error if the method is abstract but must not be, or is not and must be. */
private void checkAbstractness() {
- boolean isAbstract = element.getModifiers().contains(ABSTRACT);
+ boolean isAbstract = method.isAbstract();
switch (abstractness) {
case MUST_BE_ABSTRACT:
if (!isAbstract) {
@@ -216,12 +208,12 @@ abstract class BindingMethodValidator extends BindingElementValidator<Executable
* subtype of {@link Exception}.
*/
private void checkThrows() {
- exceptionSuperclass.checkThrows(BindingMethodValidator.this, element, report);
+ exceptionSuperclass.checkThrows(BindingMethodValidator.this, method, report);
}
/** Adds errors for the method parameters. */
protected void checkParameters() {
- for (VariableElement parameter : element.getParameters()) {
+ for (XVariableElement parameter : method.getParameters()) {
checkParameter(parameter);
}
}
@@ -230,8 +222,8 @@ abstract class BindingMethodValidator extends BindingElementValidator<Executable
* Adds errors for a method parameter. This implementation reports an error if the parameter has
* more than one qualifier.
*/
- protected void checkParameter(VariableElement parameter) {
- dependencyRequestValidator.validateDependencyRequest(report, parameter, parameter.asType());
+ protected void checkParameter(XVariableElement parameter) {
+ dependencyRequestValidator.validateDependencyRequest(report, parameter, parameter.getType());
}
}
@@ -256,8 +248,8 @@ abstract class BindingMethodValidator extends BindingElementValidator<Executable
@Override
protected void checkThrows(
BindingMethodValidator validator,
- ExecutableElement element,
- ValidationReport.Builder<ExecutableElement> report) {
+ XExecutableElement element,
+ ValidationReport.Builder report) {
if (!element.getThrownTypes().isEmpty()) {
report.addError(validator.bindingMethods("may not throw"));
return;
@@ -266,7 +258,7 @@ abstract class BindingMethodValidator extends BindingElementValidator<Executable
},
/** Methods may throw checked or unchecked exceptions or errors. */
- EXCEPTION(Exception.class) {
+ EXCEPTION(TypeNames.EXCEPTION) {
@Override
protected String errorMessage(BindingMethodValidator validator) {
return validator.bindingMethods(
@@ -275,7 +267,7 @@ abstract class BindingMethodValidator extends BindingElementValidator<Executable
},
/** Methods may throw unchecked exceptions or errors. */
- RUNTIME_EXCEPTION(RuntimeException.class) {
+ RUNTIME_EXCEPTION(TypeNames.RUNTIME_EXCEPTION) {
@Override
protected String errorMessage(BindingMethodValidator validator) {
return validator.bindingMethods("may only throw unchecked exceptions");
@@ -283,13 +275,14 @@ abstract class BindingMethodValidator extends BindingElementValidator<Executable
},
;
- private final Class<? extends Exception> superclass;
+ @SuppressWarnings("Immutable")
+ private final ClassName superclass;
ExceptionSuperclass() {
this(null);
}
- ExceptionSuperclass(Class<? extends Exception> superclass) {
+ ExceptionSuperclass(ClassName superclass) {
this.superclass = superclass;
}
@@ -301,11 +294,11 @@ abstract class BindingMethodValidator extends BindingElementValidator<Executable
*/
protected void checkThrows(
BindingMethodValidator validator,
- ExecutableElement element,
- ValidationReport.Builder<ExecutableElement> report) {
- TypeMirror exceptionSupertype = validator.elements.getTypeElement(superclass).asType();
- TypeMirror errorType = validator.elements.getTypeElement(Error.class).asType();
- for (TypeMirror thrownType : element.getThrownTypes()) {
+ XExecutableElement element,
+ ValidationReport.Builder report) {
+ XType exceptionSupertype = validator.processingEnv.findType(superclass);
+ XType errorType = validator.processingEnv.findType(TypeNames.ERROR);
+ for (XType thrownType : element.getThrownTypes()) {
if (!validator.types.isSubtype(thrownType, exceptionSupertype)
&& !validator.types.isSubtype(thrownType, errorType)) {
report.addError(errorMessage(validator));
diff --git a/java/dagger/internal/codegen/validation/BindingMethodValidatorsModule.java b/java/dagger/internal/codegen/validation/BindingMethodValidatorsModule.java
index 08afbc81f..3b196a620 100644
--- a/java/dagger/internal/codegen/validation/BindingMethodValidatorsModule.java
+++ b/java/dagger/internal/codegen/validation/BindingMethodValidatorsModule.java
@@ -19,11 +19,11 @@ package dagger.internal.codegen.validation;
import static com.google.common.collect.Maps.uniqueIndex;
import com.google.common.collect.ImmutableMap;
+import com.squareup.javapoet.ClassName;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoSet;
-import java.lang.annotation.Annotation;
import java.util.Set;
/**
@@ -33,7 +33,7 @@ import java.util.Set;
@Module
public interface BindingMethodValidatorsModule {
@Provides
- static ImmutableMap<Class<? extends Annotation>, BindingMethodValidator> indexValidators(
+ static ImmutableMap<ClassName, BindingMethodValidator> indexValidators(
Set<BindingMethodValidator> validators) {
return uniqueIndex(validators, BindingMethodValidator::methodAnnotation);
}
diff --git a/java/dagger/internal/codegen/validation/BindsInstanceElementValidator.java b/java/dagger/internal/codegen/validation/BindsInstanceElementValidator.java
index 283af7d0b..c22f8db83 100644
--- a/java/dagger/internal/codegen/validation/BindsInstanceElementValidator.java
+++ b/java/dagger/internal/codegen/validation/BindsInstanceElementValidator.java
@@ -16,14 +16,13 @@
package dagger.internal.codegen.validation;
-import dagger.BindsInstance;
+import androidx.room.compiler.processing.XElement;
import dagger.internal.codegen.binding.InjectionAnnotations;
-import javax.lang.model.element.Element;
-abstract class BindsInstanceElementValidator<E extends Element> extends BindingElementValidator<E> {
+abstract class BindsInstanceElementValidator<E extends XElement>
+ extends BindingElementValidator<E> {
BindsInstanceElementValidator(InjectionAnnotations injectionAnnotations) {
super(
- BindsInstance.class,
AllowsMultibindings.NO_MULTIBINDINGS,
AllowsScoping.NO_SCOPING,
injectionAnnotations);
diff --git a/java/dagger/internal/codegen/validation/BindsInstanceMethodValidator.java b/java/dagger/internal/codegen/validation/BindsInstanceMethodValidator.java
index 6d144bd28..234a55305 100644
--- a/java/dagger/internal/codegen/validation/BindsInstanceMethodValidator.java
+++ b/java/dagger/internal/codegen/validation/BindsInstanceMethodValidator.java
@@ -19,48 +19,56 @@ package dagger.internal.codegen.validation;
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.base.ComponentAnnotation.anyComponentAnnotation;
import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
-import static javax.lang.model.element.Modifier.ABSTRACT;
+import static dagger.internal.codegen.xprocessing.XMethodElements.getEnclosingTypeElement;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.XVariableElement;
+import dagger.internal.codegen.base.DaggerSuperficialValidation;
import dagger.internal.codegen.base.ModuleAnnotation;
import dagger.internal.codegen.binding.InjectionAnnotations;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
-final class BindsInstanceMethodValidator extends BindsInstanceElementValidator<ExecutableElement> {
+final class BindsInstanceMethodValidator extends BindsInstanceElementValidator<XMethodElement> {
+ private final DaggerSuperficialValidation superficialValidation;
+
@Inject
- BindsInstanceMethodValidator(InjectionAnnotations injectionAnnotations) {
+ BindsInstanceMethodValidator(
+ InjectionAnnotations injectionAnnotations,
+ DaggerSuperficialValidation superficialValidation) {
super(injectionAnnotations);
+ this.superficialValidation = superficialValidation;
}
@Override
- protected ElementValidator elementValidator(ExecutableElement element) {
- return new Validator(element);
+ protected ElementValidator elementValidator(XMethodElement method) {
+ return new Validator(method);
}
private class Validator extends ElementValidator {
- Validator(ExecutableElement element) {
- super(element);
+ private final XMethodElement method;
+
+ Validator(XMethodElement method) {
+ super(method);
+ this.method = method;
}
@Override
protected void checkAdditionalProperties() {
- if (!element.getModifiers().contains(ABSTRACT)) {
+ if (!method.isAbstract()) {
report.addError("@BindsInstance methods must be abstract");
}
- if (element.getParameters().size() != 1) {
+ if (method.getParameters().size() != 1) {
report.addError(
"@BindsInstance methods should have exactly one parameter for the bound type");
}
- TypeElement enclosingType = MoreElements.asType(element.getEnclosingElement());
- moduleAnnotation(enclosingType)
+ XTypeElement enclosingTypeElement = getEnclosingTypeElement(method);
+ moduleAnnotation(enclosingTypeElement, superficialValidation)
.ifPresent(moduleAnnotation -> report.addError(didYouMeanBinds(moduleAnnotation)));
- anyComponentAnnotation(enclosingType)
+ anyComponentAnnotation(enclosingTypeElement, superficialValidation)
.ifPresent(
componentAnnotation ->
report.addError(
@@ -71,11 +79,10 @@ final class BindsInstanceMethodValidator extends BindsInstanceElementValidator<E
}
@Override
- protected Optional<TypeMirror> bindingElementType() {
- List<? extends VariableElement> parameters =
- MoreElements.asExecutable(element).getParameters();
+ protected Optional<XType> bindingElementType() {
+ List<? extends XVariableElement> parameters = method.getParameters();
return parameters.size() == 1
- ? Optional.of(getOnlyElement(parameters).asType())
+ ? Optional.of(getOnlyElement(parameters).getType())
: Optional.empty();
}
}
@@ -83,6 +90,6 @@ final class BindsInstanceMethodValidator extends BindsInstanceElementValidator<E
private static String didYouMeanBinds(ModuleAnnotation moduleAnnotation) {
return String.format(
"@BindsInstance methods should not be included in @%ss. Did you mean @Binds?",
- moduleAnnotation.annotationName());
+ moduleAnnotation.simpleName());
}
}
diff --git a/java/dagger/internal/codegen/validation/BindsInstanceParameterValidator.java b/java/dagger/internal/codegen/validation/BindsInstanceParameterValidator.java
index 24d65a979..b071aa7a9 100644
--- a/java/dagger/internal/codegen/validation/BindsInstanceParameterValidator.java
+++ b/java/dagger/internal/codegen/validation/BindsInstanceParameterValidator.java
@@ -16,53 +16,46 @@
package dagger.internal.codegen.validation;
-import static javax.lang.model.element.ElementKind.METHOD;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.type.TypeKind.DECLARED;
-import static javax.lang.model.type.TypeKind.TYPEVAR;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
+import static dagger.internal.codegen.xprocessing.XTypes.isTypeVariable;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XExecutableParameterElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
import dagger.internal.codegen.binding.InjectionAnnotations;
import java.util.Optional;
import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-final class BindsInstanceParameterValidator extends BindsInstanceElementValidator<VariableElement> {
+final class BindsInstanceParameterValidator
+ extends BindsInstanceElementValidator<XExecutableParameterElement> {
@Inject
BindsInstanceParameterValidator(InjectionAnnotations injectionAnnotations) {
super(injectionAnnotations);
}
@Override
- protected ElementValidator elementValidator(VariableElement element) {
- return new Validator(element);
+ protected ElementValidator elementValidator(XExecutableParameterElement parameter) {
+ return new Validator(parameter);
}
private class Validator extends ElementValidator {
- Validator(VariableElement element) {
- super(element);
+ private final XExecutableParameterElement parameter;
+
+ Validator(XExecutableParameterElement parameter) {
+ super(parameter);
+ this.parameter = parameter;
}
@Override
protected void checkAdditionalProperties() {
- Element enclosing = element.getEnclosingElement();
- if (!enclosing.getKind().equals(METHOD)) {
- report.addError(
- "@BindsInstance should only be applied to methods or parameters of methods");
- return;
- }
-
- ExecutableElement method = MoreElements.asExecutable(enclosing);
- if (!method.getModifiers().contains(ABSTRACT)) {
+ if (!parameter.getEnclosingMethodElement().isAbstract()) {
report.addError("@BindsInstance parameters may only be used in abstract methods");
}
- TypeKind returnKind = method.getReturnType().getKind();
- if (!(returnKind.equals(DECLARED) || returnKind.equals(TYPEVAR))) {
+ // The above check should rule out constructors since constructors cannot be abstract, so we
+ // know the XExecutableElement enclosing the parameter has to be an XMethodElement.
+ XMethodElement method = (XMethodElement) parameter.getEnclosingMethodElement();
+ if (!(isDeclared(method.getReturnType()) || isTypeVariable(method.getReturnType()))) {
report.addError(
"@BindsInstance parameters may not be used in methods with a void, array or primitive "
+ "return type");
@@ -70,8 +63,8 @@ final class BindsInstanceParameterValidator extends BindsInstanceElementValidato
}
@Override
- protected Optional<TypeMirror> bindingElementType() {
- return Optional.of(element.asType());
+ protected Optional<XType> bindingElementType() {
+ return Optional.of(parameter.getType());
}
}
}
diff --git a/java/dagger/internal/codegen/validation/BindsInstanceProcessingStep.java b/java/dagger/internal/codegen/validation/BindsInstanceProcessingStep.java
index 0e79b910f..b4132df67 100644
--- a/java/dagger/internal/codegen/validation/BindsInstanceProcessingStep.java
+++ b/java/dagger/internal/codegen/validation/BindsInstanceProcessingStep.java
@@ -16,51 +16,50 @@
package dagger.internal.codegen.validation;
-import com.google.auto.common.MoreElements;
+import static androidx.room.compiler.processing.XElementKt.isMethod;
+import static androidx.room.compiler.processing.XElementKt.isMethodParameter;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XExecutableParameterElement;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XMethodElement;
import com.google.common.collect.ImmutableSet;
-import dagger.BindsInstance;
-import java.lang.annotation.Annotation;
-import java.util.Set;
-import javax.annotation.processing.Messager;
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.javapoet.TypeNames;
import javax.inject.Inject;
-import javax.lang.model.element.Element;
/**
* Processing step that validates that the {@code BindsInstance} annotation is applied to the
* correct elements.
*/
-public final class BindsInstanceProcessingStep extends TypeCheckingProcessingStep<Element> {
+public final class BindsInstanceProcessingStep extends TypeCheckingProcessingStep<XElement> {
private final BindsInstanceMethodValidator methodValidator;
private final BindsInstanceParameterValidator parameterValidator;
- private final Messager messager;
+ private final XMessager messager;
@Inject
BindsInstanceProcessingStep(
BindsInstanceMethodValidator methodValidator,
BindsInstanceParameterValidator parameterValidator,
- Messager messager) {
- super(element -> element);
+ XMessager messager) {
this.methodValidator = methodValidator;
this.parameterValidator = parameterValidator;
this.messager = messager;
}
@Override
- public Set<? extends Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(BindsInstance.class);
+ public ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(TypeNames.BINDS_INSTANCE);
}
@Override
- protected void process(Element element, ImmutableSet<Class<? extends Annotation>> annotations) {
- switch (element.getKind()) {
- case PARAMETER:
- parameterValidator.validate(MoreElements.asVariable(element)).printMessagesTo(messager);
- break;
- case METHOD:
- methodValidator.validate(MoreElements.asExecutable(element)).printMessagesTo(messager);
- break;
- default:
- throw new AssertionError(element);
+ protected void process(XElement element, ImmutableSet<ClassName> annotations) {
+ if (isMethod(element)) {
+ methodValidator.validate((XMethodElement) element).printMessagesTo(messager);
+ } else if (isMethodParameter(element)) {
+ parameterValidator.validate((XExecutableParameterElement) element).printMessagesTo(messager);
+ } else {
+ throw new AssertionError(element);
}
}
}
diff --git a/java/dagger/internal/codegen/validation/BindsMethodValidator.java b/java/dagger/internal/codegen/validation/BindsMethodValidator.java
index 6d2dd1878..20f9eb523 100644
--- a/java/dagger/internal/codegen/validation/BindsMethodValidator.java
+++ b/java/dagger/internal/codegen/validation/BindsMethodValidator.java
@@ -20,67 +20,63 @@ import static dagger.internal.codegen.validation.BindingElementValidator.AllowsM
import static dagger.internal.codegen.validation.BindingElementValidator.AllowsScoping.ALLOWS_SCOPING;
import static dagger.internal.codegen.validation.BindingMethodValidator.Abstractness.MUST_BE_ABSTRACT;
import static dagger.internal.codegen.validation.BindingMethodValidator.ExceptionSuperclass.NO_EXCEPTIONS;
-import static dagger.internal.codegen.validation.TypeHierarchyValidator.validateTypeHierarchy;
+import static dagger.internal.codegen.xprocessing.XTypes.isPrimitive;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XVariableElement;
import com.google.common.collect.ImmutableSet;
-import dagger.Binds;
-import dagger.Module;
import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.base.DaggerSuperficialValidation;
import dagger.internal.codegen.base.SetType;
import dagger.internal.codegen.binding.BindsTypeChecker;
import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.producers.ProducerModule;
import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
-/** A validator for {@link Binds} methods. */
+/** A validator for {@link dagger.Binds} methods. */
final class BindsMethodValidator extends BindingMethodValidator {
- private final DaggerTypes types;
private final BindsTypeChecker bindsTypeChecker;
+ private final DaggerSuperficialValidation superficialValidation;
@Inject
BindsMethodValidator(
- DaggerElements elements,
DaggerTypes types,
- KotlinMetadataUtil kotlinMetadataUtil,
BindsTypeChecker bindsTypeChecker,
DependencyRequestValidator dependencyRequestValidator,
+ DaggerSuperficialValidation superficialValidation,
InjectionAnnotations injectionAnnotations) {
super(
- elements,
types,
- kotlinMetadataUtil,
- Binds.class,
- ImmutableSet.of(Module.class, ProducerModule.class),
+ TypeNames.BINDS,
+ ImmutableSet.of(TypeNames.MODULE, TypeNames.PRODUCER_MODULE),
dependencyRequestValidator,
MUST_BE_ABSTRACT,
NO_EXCEPTIONS,
ALLOWS_MULTIBINDINGS,
ALLOWS_SCOPING,
injectionAnnotations);
- this.types = types;
this.bindsTypeChecker = bindsTypeChecker;
+ this.superficialValidation = superficialValidation;
}
@Override
- protected ElementValidator elementValidator(ExecutableElement element) {
- return new Validator(element);
+ protected ElementValidator elementValidator(XMethodElement method) {
+ return new Validator(method);
}
private class Validator extends MethodValidator {
- Validator(ExecutableElement element) {
- super(element);
+ private final XMethodElement method;
+
+ Validator(XMethodElement method) {
+ super(method);
+ this.method = method;
}
@Override
protected void checkParameters() {
- if (element.getParameters().size() != 1) {
+ if (method.getParameters().size() != 1) {
report.addError(
bindingMethods(
"must have exactly one parameter, whose type is assignable to the return type"));
@@ -90,24 +86,24 @@ final class BindsMethodValidator extends BindingMethodValidator {
}
@Override
- protected void checkParameter(VariableElement parameter) {
+ protected void checkParameter(XVariableElement parameter) {
super.checkParameter(parameter);
- TypeMirror leftHandSide = boxIfNecessary(element.getReturnType());
- TypeMirror rightHandSide = parameter.asType();
- ContributionType contributionType = ContributionType.fromBindingElement(element);
- if (contributionType.equals(ContributionType.SET_VALUES) && !SetType.isSet(leftHandSide)) {
+ XType returnType = boxIfNecessary(method.getReturnType());
+ XType parameterType = parameter.getType();
+ ContributionType contributionType = ContributionType.fromBindingElement(method);
+ if (contributionType.equals(ContributionType.SET_VALUES) && !SetType.isSet(returnType)) {
report.addError(
"@Binds @ElementsIntoSet methods must return a Set and take a Set parameter");
}
- if (!bindsTypeChecker.isAssignable(rightHandSide, leftHandSide, contributionType)) {
+ if (!bindsTypeChecker.isAssignable(parameterType, returnType, contributionType)) {
// Validate the type hierarchy of both sides to make sure they're both valid.
// If one of the types isn't valid it means we need to delay validation to the next round.
// Note: BasicAnnotationProcessor only performs superficial validation on the referenced
// types within the module. Thus, we're guaranteed that the types in the @Binds method are
// valid, but it says nothing about their supertypes, which are needed for isAssignable.
- validateTypeHierarchy(leftHandSide, types);
- validateTypeHierarchy(rightHandSide, types);
+ superficialValidation.validateTypeHierarchyOf("return type", method, returnType);
+ superficialValidation.validateTypeHierarchyOf("parameter", parameter, parameterType);
// TODO(ronshapiro): clarify this error message for @ElementsIntoSet cases, where the
// right-hand-side might not be assignable to the left-hand-side, but still compatible with
// Set.addAll(Collection<? extends E>)
@@ -115,11 +111,8 @@ final class BindsMethodValidator extends BindingMethodValidator {
}
}
- private TypeMirror boxIfNecessary(TypeMirror maybePrimitive) {
- if (maybePrimitive.getKind().isPrimitive()) {
- return types.boxedClass(MoreTypes.asPrimitiveType(maybePrimitive)).asType();
- }
- return maybePrimitive;
+ private XType boxIfNecessary(XType maybePrimitive) {
+ return isPrimitive(maybePrimitive) ? maybePrimitive.boxed() : maybePrimitive;
}
}
}
diff --git a/java/dagger/internal/codegen/validation/BindsOptionalOfMethodValidator.java b/java/dagger/internal/codegen/validation/BindsOptionalOfMethodValidator.java
index cb776e196..fff851fcc 100644
--- a/java/dagger/internal/codegen/validation/BindsOptionalOfMethodValidator.java
+++ b/java/dagger/internal/codegen/validation/BindsOptionalOfMethodValidator.java
@@ -16,7 +16,6 @@
package dagger.internal.codegen.validation;
-import static com.google.auto.common.MoreTypes.asTypeElement;
import static dagger.internal.codegen.base.Keys.isValidImplicitProvisionKey;
import static dagger.internal.codegen.binding.InjectionAnnotations.injectedConstructors;
import static dagger.internal.codegen.validation.BindingElementValidator.AllowsMultibindings.NO_MULTIBINDINGS;
@@ -24,64 +23,55 @@ import static dagger.internal.codegen.validation.BindingElementValidator.AllowsS
import static dagger.internal.codegen.validation.BindingMethodValidator.Abstractness.MUST_BE_ABSTRACT;
import static dagger.internal.codegen.validation.BindingMethodValidator.ExceptionSuperclass.NO_EXCEPTIONS;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
import com.google.common.collect.ImmutableSet;
-import dagger.BindsOptionalOf;
-import dagger.Module;
import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.producers.ProducerModule;
import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.TypeMirror;
-/** A validator for {@link BindsOptionalOf} methods. */
+/** A validator for {@link dagger.BindsOptionalOf} methods. */
final class BindsOptionalOfMethodValidator extends BindingMethodValidator {
-
- private final DaggerTypes types;
private final InjectionAnnotations injectionAnnotations;
@Inject
BindsOptionalOfMethodValidator(
- DaggerElements elements,
DaggerTypes types,
- KotlinMetadataUtil kotlinMetadataUtil,
DependencyRequestValidator dependencyRequestValidator,
InjectionAnnotations injectionAnnotations) {
super(
- elements,
types,
- kotlinMetadataUtil,
- BindsOptionalOf.class,
- ImmutableSet.of(Module.class, ProducerModule.class),
+ TypeNames.BINDS_OPTIONAL_OF,
+ ImmutableSet.of(TypeNames.MODULE, TypeNames.PRODUCER_MODULE),
dependencyRequestValidator,
MUST_BE_ABSTRACT,
NO_EXCEPTIONS,
NO_MULTIBINDINGS,
NO_SCOPING,
injectionAnnotations);
- this.types = types;
this.injectionAnnotations = injectionAnnotations;
}
-
@Override
- protected ElementValidator elementValidator(ExecutableElement element) {
- return new Validator(element);
+ protected ElementValidator elementValidator(XMethodElement method) {
+ return new Validator(method);
}
private class Validator extends MethodValidator {
- Validator(ExecutableElement element) {
- super(element);
+ private final XMethodElement method;
+
+ Validator(XMethodElement method) {
+ super(method);
+ this.method = method;
}
@Override
- protected void checkKeyType(TypeMirror keyType) {
+ protected void checkKeyType(XType keyType) {
super.checkKeyType(keyType);
if (isValidImplicitProvisionKey(
- injectionAnnotations.getQualifiers(element).stream().findFirst(), keyType, types)
- && !injectedConstructors(asTypeElement(keyType)).isEmpty()) {
+ injectionAnnotations.getQualifiers(method).stream().findFirst(), keyType)
+ && !injectedConstructors(keyType.getTypeElement()).isEmpty()) {
report.addError(
"@BindsOptionalOf methods cannot return unqualified types that have an @Inject-"
+ "annotated constructor because those are always present");
@@ -90,7 +80,7 @@ final class BindsOptionalOfMethodValidator extends BindingMethodValidator {
@Override
protected void checkParameters() {
- if (!element.getParameters().isEmpty()) {
+ if (!method.getParameters().isEmpty()) {
report.addError("@BindsOptionalOf methods cannot have parameters");
}
}
diff --git a/java/dagger/internal/codegen/validation/ComponentCreatorValidator.java b/java/dagger/internal/codegen/validation/ComponentCreatorValidator.java
index a6d9a3fb5..f1d043816 100644
--- a/java/dagger/internal/codegen/validation/ComponentCreatorValidator.java
+++ b/java/dagger/internal/codegen/validation/ComponentCreatorValidator.java
@@ -16,53 +16,50 @@
package dagger.internal.codegen.validation;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static androidx.room.compiler.processing.XTypeKt.isVoid;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.getCreatorAnnotations;
import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.getCreatorAnnotations;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.STATIC;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.auto.common.MoreElements;
+import static dagger.internal.codegen.xprocessing.XMethodElements.hasTypeParameters;
+import static dagger.internal.codegen.xprocessing.XTypeElements.getAllUnimplementedMethods;
+import static dagger.internal.codegen.xprocessing.XTypeElements.hasTypeParameters;
+import static dagger.internal.codegen.xprocessing.XTypes.isPrimitive;
+import static javax.lang.model.SourceVersion.isKeyword;
+
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XExecutableParameterElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ObjectArrays;
-import dagger.BindsInstance;
import dagger.internal.codegen.base.ClearableCache;
-import dagger.internal.codegen.binding.ComponentCreatorAnnotation;
+import dagger.internal.codegen.base.ComponentCreatorAnnotation;
import dagger.internal.codegen.binding.ErrorMessages;
import dagger.internal.codegen.binding.ErrorMessages.ComponentCreatorMessages;
-import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
import dagger.internal.codegen.langmodel.DaggerTypes;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementFilter;
/** Validates types annotated with component creator annotations. */
@Singleton
public final class ComponentCreatorValidator implements ClearableCache {
- private final DaggerElements elements;
+ private final Map<XTypeElement, ValidationReport> reports = new HashMap<>();
private final DaggerTypes types;
- private final Map<TypeElement, ValidationReport<TypeElement>> reports = new HashMap<>();
+ private final KotlinMetadataUtil metadataUtil;
@Inject
- ComponentCreatorValidator(DaggerElements elements, DaggerTypes types) {
- this.elements = elements;
+ ComponentCreatorValidator(DaggerTypes types, KotlinMetadataUtil metadataUtil) {
this.types = types;
+ this.metadataUtil = metadataUtil;
}
@Override
@@ -71,12 +68,12 @@ public final class ComponentCreatorValidator implements ClearableCache {
}
/** Validates that the given {@code type} is potentially a valid component creator type. */
- public ValidationReport<TypeElement> validate(TypeElement type) {
+ public ValidationReport validate(XTypeElement type) {
return reentrantComputeIfAbsent(reports, type, this::validateUncached);
}
- private ValidationReport<TypeElement> validateUncached(TypeElement type) {
- ValidationReport.Builder<TypeElement> report = ValidationReport.about(type);
+ private ValidationReport validateUncached(XTypeElement type) {
+ ValidationReport.Builder report = ValidationReport.about(type);
ImmutableSet<ComponentCreatorAnnotation> creatorAnnotations = getCreatorAnnotations(type);
if (!validateOnlyOneCreatorAnnotation(creatorAnnotations, report)) {
@@ -93,7 +90,7 @@ public final class ComponentCreatorValidator implements ClearableCache {
private boolean validateOnlyOneCreatorAnnotation(
ImmutableSet<ComponentCreatorAnnotation> creatorAnnotations,
- ValidationReport.Builder<?> report) {
+ ValidationReport.Builder report) {
// creatorAnnotations should never be empty because this should only ever be called for
// types that have been found to have some creator annotation
if (creatorAnnotations.size() > 1) {
@@ -109,30 +106,29 @@ public final class ComponentCreatorValidator implements ClearableCache {
}
/**
- * Validator for a single {@link TypeElement} that is annotated with a {@code Builder} or {@code
+ * Validator for a single {@link XTypeElement} that is annotated with a {@code Builder} or {@code
* Factory} annotation.
*/
private final class ElementValidator {
- private final TypeElement type;
- private final Element component;
- private final ValidationReport.Builder<TypeElement> report;
+ private final XTypeElement creator;
+ private final ValidationReport.Builder report;
private final ComponentCreatorAnnotation annotation;
private final ComponentCreatorMessages messages;
private ElementValidator(
- TypeElement type,
- ValidationReport.Builder<TypeElement> report,
+ XTypeElement creator,
+ ValidationReport.Builder report,
ComponentCreatorAnnotation annotation) {
- this.type = type;
- this.component = type.getEnclosingElement();
+ this.creator = creator;
this.report = report;
this.annotation = annotation;
this.messages = ErrorMessages.creatorMessagesFor(annotation);
}
/** Validates the creator type. */
- final ValidationReport<TypeElement> validate() {
- if (!isAnnotationPresent(component, annotation.componentAnnotation())) {
+ final ValidationReport validate() {
+ XTypeElement enclosingType = creator.getEnclosingTypeElement();
+ if (enclosingType == null || !enclosingType.hasAnnotation(annotation.componentAnnotation())) {
report.addError(messages.mustBeInComponent());
}
@@ -156,29 +152,26 @@ public final class ComponentCreatorValidator implements ClearableCache {
/** Validates that the type is a class or interface type and returns true if it is. */
private boolean validateIsClassOrInterface() {
- switch (type.getKind()) {
- case CLASS:
- validateConstructor();
- return true;
- case INTERFACE:
- return true;
- default:
- report.addError(messages.mustBeClassOrInterface());
+ if (creator.isClass()) {
+ validateConstructor();
+ return true;
+ }
+ if (creator.isInterface()) {
+ return true;
}
+ report.addError(messages.mustBeClassOrInterface());
return false;
}
private void validateConstructor() {
- List<? extends Element> allElements = type.getEnclosedElements();
- List<ExecutableElement> constructors = ElementFilter.constructorsIn(allElements);
+ List<XConstructorElement> constructors = creator.getConstructors();
boolean valid = true;
if (constructors.size() != 1) {
valid = false;
} else {
- ExecutableElement constructor = getOnlyElement(constructors);
- valid =
- constructor.getParameters().isEmpty() && !constructor.getModifiers().contains(PRIVATE);
+ XConstructorElement constructor = getOnlyElement(constructors);
+ valid = constructor.getParameters().isEmpty() && !constructor.isPrivate();
}
if (!valid) {
@@ -188,26 +181,26 @@ public final class ComponentCreatorValidator implements ClearableCache {
/** Validates basic requirements about the type that are common to both creator kinds. */
private void validateTypeRequirements() {
- if (!type.getTypeParameters().isEmpty()) {
+ if (hasTypeParameters(creator)) {
report.addError(messages.generics());
}
- Set<Modifier> modifiers = type.getModifiers();
- if (modifiers.contains(PRIVATE)) {
+ if (creator.isPrivate()) {
report.addError(messages.isPrivate());
}
- if (!modifiers.contains(STATIC)) {
+ if (!creator.isStatic()) {
report.addError(messages.mustBeStatic());
}
// Note: Must be abstract, so no need to check for final.
- if (!modifiers.contains(ABSTRACT)) {
+ if (!creator.isAbstract()) {
report.addError(messages.mustBeAbstract());
}
}
private void validateBuilder() {
- ExecutableElement buildMethod = null;
- for (ExecutableElement method : elements.getUnimplementedMethods(type)) {
+ validateClassMethodName();
+ XMethodElement buildMethod = null;
+ for (XMethodElement method : getAllUnimplementedMethods(creator)) {
switch (method.getParameters().size()) {
case 0: // If this is potentially a build() method, validate it returns the correct type.
if (validateFactoryMethodReturnType(method)) {
@@ -244,9 +237,24 @@ public final class ComponentCreatorValidator implements ClearableCache {
}
}
- private void validateSetterMethod(ExecutableElement method) {
- TypeMirror returnType = types.resolveExecutableType(method, type.asType()).getReturnType();
- if (returnType.getKind() != TypeKind.VOID && !types.isSubtype(type.asType(), returnType)) {
+ private void validateClassMethodName() {
+ // Only Kotlin class can have method name the same as a Java reserved keyword, so only check
+ // the method name if this class is a Kotlin class.
+ if (metadataUtil.hasMetadata(toJavac(creator))) {
+ metadataUtil
+ .getAllMethodNamesBySignature(toJavac(creator))
+ .forEach(
+ (signature, name) -> {
+ if (isKeyword(name)) {
+ report.addError("Can not use a Java keyword as method name: " + signature);
+ }
+ });
+ }
+ }
+
+ private void validateSetterMethod(XMethodElement method) {
+ XType returnType = method.asMemberOf(creator.getType()).getReturnType();
+ if (!isVoid(returnType) && !types.isSubtype(creator.getType(), returnType)) {
error(
method,
messages.setterMethodsMustReturnVoidOrBuilder(),
@@ -255,10 +263,10 @@ public final class ComponentCreatorValidator implements ClearableCache {
validateNotGeneric(method);
- VariableElement parameter = method.getParameters().get(0);
+ XExecutableParameterElement parameter = method.getParameters().get(0);
- boolean methodIsBindsInstance = isAnnotationPresent(method, BindsInstance.class);
- boolean parameterIsBindsInstance = isAnnotationPresent(parameter, BindsInstance.class);
+ boolean methodIsBindsInstance = method.hasAnnotation(TypeNames.BINDS_INSTANCE);
+ boolean parameterIsBindsInstance = parameter.hasAnnotation(TypeNames.BINDS_INSTANCE);
boolean bindsInstance = methodIsBindsInstance || parameterIsBindsInstance;
if (methodIsBindsInstance && parameterIsBindsInstance) {
@@ -268,7 +276,7 @@ public final class ComponentCreatorValidator implements ClearableCache {
messages.inheritedBindsInstanceNotAllowedOnBothSetterMethodAndParameter());
}
- if (!bindsInstance && parameter.asType().getKind().isPrimitive()) {
+ if (!bindsInstance && isPrimitive(parameter.getType())) {
error(
method,
messages.nonBindsInstanceParametersMayNotBePrimitives(),
@@ -277,8 +285,7 @@ public final class ComponentCreatorValidator implements ClearableCache {
}
private void validateFactory() {
- ImmutableList<ExecutableElement> abstractMethods =
- elements.getUnimplementedMethods(type).asList();
+ ImmutableList<XMethodElement> abstractMethods = getAllUnimplementedMethods(creator);
switch (abstractMethods.size()) {
case 0:
report.addError(messages.missingFactoryMethod());
@@ -298,7 +305,7 @@ public final class ComponentCreatorValidator implements ClearableCache {
}
/** Validates that the given {@code method} is a valid component factory method. */
- private void validateFactoryMethod(ExecutableElement method) {
+ private void validateFactoryMethod(XMethodElement method) {
validateNotGeneric(method);
if (!validateFactoryMethodReturnType(method)) {
@@ -307,9 +314,9 @@ public final class ComponentCreatorValidator implements ClearableCache {
return;
}
- for (VariableElement parameter : method.getParameters()) {
- if (!isAnnotationPresent(parameter, BindsInstance.class)
- && parameter.asType().getKind().isPrimitive()) {
+ for (XExecutableParameterElement parameter : method.getParameters()) {
+ if (!parameter.hasAnnotation(TypeNames.BINDS_INSTANCE)
+ && isPrimitive(parameter.getType())) {
error(
method,
messages.nonBindsInstanceParametersMayNotBePrimitives(),
@@ -322,10 +329,10 @@ public final class ComponentCreatorValidator implements ClearableCache {
* Validates that the factory method that actually returns a new component instance. Returns
* true if the return type was valid.
*/
- private boolean validateFactoryMethodReturnType(ExecutableElement method) {
- TypeMirror returnType = types.resolveExecutableType(method, type.asType()).getReturnType();
-
- if (!types.isSubtype(component.asType(), returnType)) {
+ private boolean validateFactoryMethodReturnType(XMethodElement method) {
+ XTypeElement component = creator.getEnclosingTypeElement();
+ XType returnType = method.asMemberOf(creator.getType()).getReturnType();
+ if (!types.isSubtype(component.getType(), returnType)) {
error(
method,
messages.factoryMethodMustReturnComponentType(),
@@ -333,7 +340,7 @@ public final class ComponentCreatorValidator implements ClearableCache {
return false;
}
- if (isAnnotationPresent(method, BindsInstance.class)) {
+ if (method.hasAnnotation(TypeNames.BINDS_INSTANCE)) {
error(
method,
messages.factoryMethodMayNotBeAnnotatedWithBindsInstance(),
@@ -341,14 +348,16 @@ public final class ComponentCreatorValidator implements ClearableCache {
return false;
}
- TypeElement componentType = MoreElements.asType(component);
- if (!types.isSameType(componentType.asType(), returnType)) {
- ImmutableSet<ExecutableElement> methodsOnlyInComponent =
- methodsOnlyInComponent(componentType);
- if (!methodsOnlyInComponent.isEmpty()) {
+ if (!returnType.isSameType(component.getType())) {
+ // TODO(ronshapiro): Ideally this shouldn't return methods which are redeclared from a
+ // supertype, but do not change the return type. We don't have a good/simple way of checking
+ // that, and it doesn't seem likely, so the warning won't be too bad.
+ ImmutableSet<XMethodElement> declaredMethods =
+ ImmutableSet.copyOf(component.getDeclaredMethods());
+ if (!declaredMethods.isEmpty()) {
report.addWarning(
messages.factoryMethodReturnsSupertypeWithMissingMethods(
- componentType, type, returnType, method, methodsOnlyInComponent),
+ component, creator, returnType, method, declaredMethods),
method);
}
}
@@ -374,11 +383,8 @@ public final class ComponentCreatorValidator implements ClearableCache {
* class was included in this compile run. But that's hard, and this is close enough.
*/
private void error(
- ExecutableElement method,
- String enclosedError,
- String inheritedError,
- Object... extraArgs) {
- if (method.getEnclosingElement().equals(type)) {
+ XMethodElement method, String enclosedError, String inheritedError, Object... extraArgs) {
+ if (method.getEnclosingElement().equals(creator)) {
report.addError(String.format(enclosedError, extraArgs), method);
} else {
report.addError(String.format(inheritedError, ObjectArrays.concat(extraArgs, method)));
@@ -386,23 +392,13 @@ public final class ComponentCreatorValidator implements ClearableCache {
}
/** Validates that the given {@code method} is not generic. * */
- private void validateNotGeneric(ExecutableElement method) {
- if (!method.getTypeParameters().isEmpty()) {
+ private void validateNotGeneric(XMethodElement method) {
+ if (hasTypeParameters(method)) {
error(
method,
messages.methodsMayNotHaveTypeParameters(),
messages.inheritedMethodsMayNotHaveTypeParameters());
}
}
-
- /**
- * Returns all methods defind in {@code componentType} which are not inherited from a supertype.
- */
- private ImmutableSet<ExecutableElement> methodsOnlyInComponent(TypeElement componentType) {
- // TODO(ronshapiro): Ideally this shouldn't return methods which are redeclared from a
- // supertype, but do not change the return type. We don't have a good/simple way of checking
- // that, and it doesn't seem likely, so the warning won't be too bad.
- return ImmutableSet.copyOf(methodsIn(componentType.getEnclosedElements()));
- }
}
}
diff --git a/java/dagger/internal/codegen/validation/ComponentDescriptorValidator.java b/java/dagger/internal/codegen/validation/ComponentDescriptorValidator.java
index 28b1c2bc8..dc7eac6a3 100644
--- a/java/dagger/internal/codegen/validation/ComponentDescriptorValidator.java
+++ b/java/dagger/internal/codegen/validation/ComponentDescriptorValidator.java
@@ -16,7 +16,9 @@
package dagger.internal.codegen.validation;
-import static com.google.auto.common.MoreTypes.asDeclared;
+import static androidx.room.compiler.processing.XElementKt.isMethod;
+import static androidx.room.compiler.processing.XElementKt.isMethodParameter;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.in;
import static com.google.common.collect.Collections2.transform;
@@ -24,22 +26,30 @@ import static dagger.internal.codegen.base.ComponentAnnotation.rootComponentAnno
import static dagger.internal.codegen.base.DiagnosticFormatting.stripCommonTypePrefixes;
import static dagger.internal.codegen.base.Formatter.INDENT;
import static dagger.internal.codegen.base.Scopes.getReadableSource;
-import static dagger.internal.codegen.base.Scopes.scopesOf;
-import static dagger.internal.codegen.base.Scopes.singletonScope;
import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSetMultimap;
+import static dagger.internal.codegen.xprocessing.XElements.asMethod;
+import static dagger.internal.codegen.xprocessing.XElements.asMethodParameter;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static javax.tools.Diagnostic.Kind.ERROR;
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.base.Equivalence.Wrapper;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XExecutableParameterElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XMethodType;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.base.DaggerSuperficialValidation;
import dagger.internal.codegen.binding.ComponentCreatorDescriptor;
import dagger.internal.codegen.binding.ComponentDescriptor;
import dagger.internal.codegen.binding.ComponentRequirement;
@@ -47,14 +57,13 @@ import dagger.internal.codegen.binding.ComponentRequirement.NullPolicy;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.binding.ErrorMessages;
import dagger.internal.codegen.binding.ErrorMessages.ComponentCreatorMessages;
+import dagger.internal.codegen.binding.InjectionAnnotations;
import dagger.internal.codegen.binding.MethodSignatureFormatter;
import dagger.internal.codegen.binding.ModuleDescriptor;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.compileroption.ValidationType;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Scope;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.spi.model.Scope;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
@@ -65,14 +74,6 @@ import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
/**
@@ -88,30 +89,27 @@ import javax.tools.Diagnostic;
// TODO(dpb): Combine with ComponentHierarchyValidator.
public final class ComponentDescriptorValidator {
- private final DaggerElements elements;
- private final DaggerTypes types;
private final CompilerOptions compilerOptions;
private final MethodSignatureFormatter methodSignatureFormatter;
private final ComponentHierarchyValidator componentHierarchyValidator;
- private final KotlinMetadataUtil metadataUtil;
+ private final InjectionAnnotations injectionAnnotations;
+ private final DaggerSuperficialValidation superficialValidation;
@Inject
ComponentDescriptorValidator(
- DaggerElements elements,
- DaggerTypes types,
CompilerOptions compilerOptions,
MethodSignatureFormatter methodSignatureFormatter,
ComponentHierarchyValidator componentHierarchyValidator,
- KotlinMetadataUtil metadataUtil) {
- this.elements = elements;
- this.types = types;
+ InjectionAnnotations injectionAnnotations,
+ DaggerSuperficialValidation superficialValidation) {
this.compilerOptions = compilerOptions;
this.methodSignatureFormatter = methodSignatureFormatter;
this.componentHierarchyValidator = componentHierarchyValidator;
- this.metadataUtil = metadataUtil;
+ this.injectionAnnotations = injectionAnnotations;
+ this.superficialValidation = superficialValidation;
}
- public ValidationReport<TypeElement> validate(ComponentDescriptor component) {
+ public ValidationReport validate(ComponentDescriptor component) {
ComponentValidation validation = new ComponentValidation(component);
validation.visitComponent(component);
validation.report(component).addSubreport(componentHierarchyValidator.validate(component));
@@ -120,23 +118,21 @@ public final class ComponentDescriptorValidator {
private final class ComponentValidation {
final ComponentDescriptor rootComponent;
- final Map<ComponentDescriptor, ValidationReport.Builder<TypeElement>> reports =
- new LinkedHashMap<>();
+ final Map<ComponentDescriptor, ValidationReport.Builder> reports = new LinkedHashMap<>();
ComponentValidation(ComponentDescriptor rootComponent) {
this.rootComponent = checkNotNull(rootComponent);
}
/** Returns a report that contains all validation messages found during traversal. */
- ValidationReport<TypeElement> buildReport() {
- ValidationReport.Builder<TypeElement> report =
- ValidationReport.about(rootComponent.typeElement());
+ ValidationReport buildReport() {
+ ValidationReport.Builder report = ValidationReport.about(rootComponent.typeElement());
reports.values().forEach(subreport -> report.addSubreport(subreport.build()));
return report.build();
}
/** Returns the report builder for a (sub)component. */
- private ValidationReport.Builder<TypeElement> report(ComponentDescriptor component) {
+ private ValidationReport.Builder report(ComponentDescriptor component) {
return reentrantComputeIfAbsent(
reports, component, descriptor -> ValidationReport.about(descriptor.typeElement()));
}
@@ -166,7 +162,9 @@ public final class ComponentDescriptorValidator {
/** Recursive method to validate that component dependencies do not form a cycle. */
private void validateComponentDependencyHierarchy(
- ComponentDescriptor component, TypeElement dependency, Deque<TypeElement> dependencyStack) {
+ ComponentDescriptor component,
+ XTypeElement dependency,
+ Deque<XTypeElement> dependencyStack) {
if (dependencyStack.contains(dependency)) {
// Current component has already appeared in the component chain.
StringBuilder message = new StringBuilder();
@@ -183,16 +181,14 @@ public final class ComponentDescriptorValidator {
// Always validate direct component dependencies referenced by this component regardless
// of the flag value
|| dependencyStack.isEmpty()) {
- rootComponentAnnotation(dependency)
+ rootComponentAnnotation(dependency, superficialValidation)
.ifPresent(
componentAnnotation -> {
dependencyStack.push(dependency);
-
- for (TypeElement nextDependency : componentAnnotation.dependencies()) {
+ for (XTypeElement nextDependency : componentAnnotation.dependencies()) {
validateComponentDependencyHierarchy(
component, nextDependency, dependencyStack);
}
-
dependencyStack.pop();
});
}
@@ -203,19 +199,18 @@ public final class ComponentDescriptorValidator {
* singleton components have no scoped dependencies.
*/
private void validateDependencyScopes(ComponentDescriptor component) {
- ImmutableSet<Scope> scopes = component.scopes();
- ImmutableSet<TypeElement> scopedDependencies =
+ ImmutableSet<ClassName> scopes =
+ component.scopes().stream().map(Scope::className).collect(toImmutableSet());
+ ImmutableSet<XTypeElement> scopedDependencies =
scopedTypesIn(
- component
- .dependencies()
- .stream()
+ component.dependencies().stream()
.map(ComponentRequirement::typeElement)
.collect(toImmutableSet()));
if (!scopes.isEmpty()) {
- Scope singletonScope = singletonScope(elements);
// Dagger 1.x scope compatibility requires this be suppress-able.
if (compilerOptions.scopeCycleValidationType().diagnosticKind().isPresent()
- && scopes.contains(singletonScope)) {
+ && (scopes.contains(TypeNames.SINGLETON)
+ || scopes.contains(TypeNames.SINGLETON_JAVAX))) {
// Singleton is a special-case representing the longest lifetime, and therefore
// @Singleton components may not depend on scoped components
if (!scopedDependencies.isEmpty()) {
@@ -249,7 +244,7 @@ public final class ComponentDescriptorValidator {
private void validateModules(ComponentDescriptor component) {
for (ModuleDescriptor module : component.modules()) {
- if (module.moduleElement().getModifiers().contains(Modifier.ABSTRACT)) {
+ if (module.moduleElement().isAbstract()) {
for (ContributionBinding binding : module.bindings()) {
if (binding.requiresModuleInstance()) {
report(component).addError(abstractModuleHasInstanceBindingMethodsError(module));
@@ -300,9 +295,9 @@ public final class ComponentDescriptorValidator {
Sets.difference(
creatorModuleAndDependencyRequirements, componentModuleAndDependencyRequirements);
- DeclaredType container = asDeclared(creator.typeElement().asType());
+ XType container = creator.typeElement().getType();
if (!inapplicableRequirementsOnCreator.isEmpty()) {
- Collection<Element> excessElements =
+ Collection<XElement> excessElements =
Multimaps.filterKeys(
creator.unvalidatedRequirementElements(), in(inapplicableRequirementsOnCreator))
.values();
@@ -318,7 +313,7 @@ public final class ComponentDescriptorValidator {
Set<ComponentRequirement> mustBePassed =
Sets.filter(
componentModuleAndDependencyRequirements,
- input -> input.nullPolicy(elements, metadataUtil).equals(NullPolicy.THROW));
+ input -> input.nullPolicy().equals(NullPolicy.THROW));
// Component requirements that the creator must be able to set, but can't
Set<ComponentRequirement> missingRequirements =
Sets.difference(mustBePassed, creatorModuleAndDependencyRequirements);
@@ -333,19 +328,20 @@ public final class ComponentDescriptorValidator {
}
// Validate that declared creator requirements (modules, dependencies) have unique types.
- ImmutableSetMultimap<Wrapper<TypeMirror>, Element> declaredRequirementsByType =
+ ImmutableSetMultimap<TypeName, XElement> declaredRequirementsByType =
Multimaps.filterKeys(
creator.unvalidatedRequirementElements(),
creatorModuleAndDependencyRequirements::contains)
- .entries().stream()
+ .entries()
+ .stream()
.collect(
- toImmutableSetMultimap(entry -> entry.getKey().wrappedType(), Entry::getValue));
+ toImmutableSetMultimap(
+ entry -> entry.getKey().type().getTypeName(), Entry::getValue));
declaredRequirementsByType
.asMap()
.forEach(
- (typeWrapper, elementsForType) -> {
+ (type, elementsForType) -> {
if (elementsForType.size() > 1) {
- TypeMirror type = typeWrapper.get();
// TODO(cgdecker): Attach this error message to the factory method rather than
// the component type if the elements are factory method parameters AND the
// factory method is defined by the factory type itself and not by a supertype.
@@ -365,40 +361,39 @@ public final class ComponentDescriptorValidator {
// for subcomponents.
}
- private String formatElement(Element element, DeclaredType container) {
+ private String formatElement(XElement element, XType container) {
// TODO(cgdecker): Extract some or all of this to another class?
// But note that it does different formatting for parameters than
// DaggerElements.elementToString(Element).
- switch (element.getKind()) {
- case METHOD:
- return methodSignatureFormatter.format(
- MoreElements.asExecutable(element), Optional.of(container));
- case PARAMETER:
- return formatParameter(MoreElements.asVariable(element), container);
- default:
- // This method shouldn't be called with any other type of element.
- throw new AssertionError();
+ if (isMethod(element)) {
+ return methodSignatureFormatter.format(asMethod(element), Optional.of(container));
+ } else if (isMethodParameter(element)) {
+ return formatParameter(asMethodParameter(element), container);
}
+ // This method shouldn't be called with any other type of element.
+ throw new AssertionError();
}
- private String formatParameter(VariableElement parameter, DeclaredType container) {
+ private String formatParameter(XExecutableParameterElement parameter, XType container) {
// TODO(cgdecker): Possibly leave the type (and annotations?) off of the parameters here and
// just use their names, since the type will be redundant in the context of the error message.
StringJoiner joiner = new StringJoiner(" ");
- parameter.getAnnotationMirrors().stream().map(Object::toString).forEach(joiner::add);
- TypeMirror parameterType = resolveParameterType(parameter, container);
+ parameter.getAllAnnotations().stream()
+ .map(XAnnotation::getQualifiedName)
+ .forEach(joiner::add);
+ XType parameterType = resolveParameterType(parameter, container);
return joiner
- .add(stripCommonTypePrefixes(parameterType.toString()))
- .add(parameter.getSimpleName())
+ .add(stripCommonTypePrefixes(parameterType.getTypeName().toString()))
+ .add(getSimpleName(parameter))
.toString();
}
- private TypeMirror resolveParameterType(VariableElement parameter, DeclaredType container) {
- ExecutableElement method =
- MoreElements.asExecutable(parameter.getEnclosingElement());
+ private XType resolveParameterType(XExecutableParameterElement parameter, XType container) {
+ checkArgument(isMethod(parameter.getEnclosingMethodElement()));
+ XMethodElement method = asMethod(parameter.getEnclosingMethodElement());
int parameterIndex = method.getParameters().indexOf(parameter);
- ExecutableType methodType = MoreTypes.asExecutable(types.asMemberOf(container, method));
+ XMethodType methodType = method.asMemberOf(container);
return methodType.getParameterTypes().get(parameterIndex);
}
@@ -413,10 +408,10 @@ public final class ComponentDescriptorValidator {
*/
private void validateDependencyScopeHierarchy(
ComponentDescriptor component,
- TypeElement dependency,
+ XTypeElement dependency,
Deque<ImmutableSet<Scope>> scopeStack,
- Deque<TypeElement> scopedDependencyStack) {
- ImmutableSet<Scope> scopes = scopesOf(dependency);
+ Deque<XTypeElement> scopedDependencyStack) {
+ ImmutableSet<Scope> scopes = injectionAnnotations.getScopes(dependency);
if (stackOverlaps(scopeStack, scopes)) {
scopedDependencyStack.push(dependency);
// Current scope has already appeared in the component chain.
@@ -436,22 +431,19 @@ public final class ComponentDescriptorValidator {
// of the flag value
|| scopedDependencyStack.isEmpty()) {
// TODO(beder): transitively check scopes of production components too.
- rootComponentAnnotation(dependency)
+ rootComponentAnnotation(dependency, superficialValidation)
.filter(componentAnnotation -> !componentAnnotation.isProduction())
.ifPresent(
componentAnnotation -> {
- ImmutableSet<TypeElement> scopedDependencies =
+ ImmutableSet<XTypeElement> scopedDependencies =
scopedTypesIn(componentAnnotation.dependencies());
if (!scopedDependencies.isEmpty()) {
// empty can be ignored (base-case)
scopeStack.push(scopes);
scopedDependencyStack.push(dependency);
- for (TypeElement scopedDependency : scopedDependencies) {
+ for (XTypeElement scopedDependency : scopedDependencies) {
validateDependencyScopeHierarchy(
- component,
- scopedDependency,
- scopeStack,
- scopedDependencyStack);
+ component, scopedDependency, scopeStack, scopedDependencyStack);
}
scopedDependencyStack.pop();
scopeStack.pop();
@@ -470,10 +462,10 @@ public final class ComponentDescriptorValidator {
}
/** Appends and formats a list of indented component types (with their scope annotations). */
- private void appendIndentedComponentsList(StringBuilder message, Iterable<TypeElement> types) {
- for (TypeElement scopedComponent : types) {
+ private void appendIndentedComponentsList(StringBuilder message, Iterable<XTypeElement> types) {
+ for (XTypeElement scopedComponent : types) {
message.append(INDENT);
- for (Scope scope : scopesOf(scopedComponent)) {
+ for (Scope scope : injectionAnnotations.getScopes(scopedComponent)) {
message.append(getReadableSource(scope)).append(' ');
}
message
@@ -486,8 +478,10 @@ public final class ComponentDescriptorValidator {
* Returns a set of type elements containing only those found in the input set that have a
* scoping annotation.
*/
- private ImmutableSet<TypeElement> scopedTypesIn(Collection<TypeElement> types) {
- return types.stream().filter(type -> !scopesOf(type).isEmpty()).collect(toImmutableSet());
+ private ImmutableSet<XTypeElement> scopedTypesIn(Collection<XTypeElement> types) {
+ return types.stream()
+ .filter(type -> !injectionAnnotations.getScopes(type).isEmpty())
+ .collect(toImmutableSet());
}
}
}
diff --git a/java/dagger/internal/codegen/validation/ComponentHierarchyValidator.java b/java/dagger/internal/codegen/validation/ComponentHierarchyValidator.java
index 1861636d3..f67c9e3c7 100644
--- a/java/dagger/internal/codegen/validation/ComponentHierarchyValidator.java
+++ b/java/dagger/internal/codegen/validation/ComponentHierarchyValidator.java
@@ -21,13 +21,13 @@ import static com.google.common.base.Predicates.and;
import static com.google.common.base.Predicates.in;
import static com.google.common.base.Predicates.not;
import static dagger.internal.codegen.base.Scopes.getReadableSource;
-import static dagger.internal.codegen.base.Scopes.uniqueScopeOf;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XExecutableParameterElement;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
-import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
@@ -37,32 +37,35 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
+import dagger.internal.codegen.base.ModuleKind;
import dagger.internal.codegen.binding.ComponentDescriptor;
import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.binding.InjectionAnnotations;
import dagger.internal.codegen.binding.ModuleDescriptor;
-import dagger.internal.codegen.binding.ModuleKind;
import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.model.Scope;
+import dagger.spi.model.Scope;
import java.util.Collection;
import java.util.Formatter;
import java.util.Map;
+import java.util.Optional;
import javax.inject.Inject;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
/** Validates the relationships between parent components and subcomponents. */
final class ComponentHierarchyValidator {
private static final Joiner COMMA_SEPARATED_JOINER = Joiner.on(", ");
+
private final CompilerOptions compilerOptions;
+ private final InjectionAnnotations injectionAnnotations;
@Inject
- ComponentHierarchyValidator(CompilerOptions compilerOptions) {
+ ComponentHierarchyValidator(
+ CompilerOptions compilerOptions, InjectionAnnotations injectionAnnotations) {
this.compilerOptions = compilerOptions;
+ this.injectionAnnotations = injectionAnnotations;
}
- ValidationReport<TypeElement> validate(ComponentDescriptor componentDescriptor) {
- ValidationReport.Builder<TypeElement> report =
- ValidationReport.about(componentDescriptor.typeElement());
+ ValidationReport validate(ComponentDescriptor componentDescriptor) {
+ ValidationReport.Builder report = ValidationReport.about(componentDescriptor.typeElement());
validateSubcomponentMethods(
report,
componentDescriptor,
@@ -78,9 +81,9 @@ final class ComponentHierarchyValidator {
}
private void validateSubcomponentMethods(
- ValidationReport.Builder<?> report,
+ ValidationReport.Builder report,
ComponentDescriptor componentDescriptor,
- ImmutableMap<TypeElement, TypeElement> existingModuleToOwners) {
+ ImmutableMap<XTypeElement, XTypeElement> existingModuleToOwners) {
componentDescriptor
.childComponentsDeclaredByFactoryMethods()
.forEach(
@@ -97,7 +100,7 @@ final class ComponentHierarchyValidator {
validateSubcomponentMethods(
report,
childComponent,
- new ImmutableMap.Builder<TypeElement, TypeElement>()
+ new ImmutableMap.Builder<XTypeElement, XTypeElement>()
.putAll(existingModuleToOwners)
.putAll(
Maps.toMap(
@@ -109,21 +112,21 @@ final class ComponentHierarchyValidator {
}
private void validateFactoryMethodParameters(
- ValidationReport.Builder<?> report,
+ ValidationReport.Builder report,
ComponentMethodDescriptor subcomponentMethodDescriptor,
- ImmutableMap<TypeElement, TypeElement> existingModuleToOwners) {
- for (VariableElement factoryMethodParameter :
+ ImmutableMap<XTypeElement, XTypeElement> existingModuleToOwners) {
+ for (XExecutableParameterElement factoryMethodParameter :
subcomponentMethodDescriptor.methodElement().getParameters()) {
- TypeElement moduleType = MoreTypes.asTypeElement(factoryMethodParameter.asType());
- TypeElement originatingComponent = existingModuleToOwners.get(moduleType);
- if (originatingComponent != null) {
+ XTypeElement moduleType = factoryMethodParameter.getType().getTypeElement();
+ if (existingModuleToOwners.containsKey(moduleType)) {
/* Factory method tries to pass a module that is already present in the parent.
* This is an error. */
report.addError(
String.format(
"%s is present in %s. A subcomponent cannot use an instance of a "
+ "module that differs from its parent.",
- moduleType.getSimpleName(), originatingComponent.getQualifiedName()),
+ getSimpleName(moduleType),
+ existingModuleToOwners.get(moduleType).getQualifiedName()),
factoryMethodParameter);
}
}
@@ -133,7 +136,7 @@ final class ComponentHierarchyValidator {
* Checks that components do not have any scopes that are also applied on any of their ancestors.
*/
private void validateScopeHierarchy(
- ValidationReport.Builder<TypeElement> report,
+ ValidationReport.Builder report,
ComponentDescriptor subject,
SetMultimap<ComponentDescriptor, Scope> scopesByComponent) {
scopesByComponent.putAll(subject, subject.scopes());
@@ -172,7 +175,7 @@ final class ComponentHierarchyValidator {
}
private void validateProductionModuleUniqueness(
- ValidationReport.Builder<TypeElement> report,
+ ValidationReport.Builder report,
ComponentDescriptor componentDescriptor,
SetMultimap<ComponentDescriptor, ModuleDescriptor> producerModulesByComponent) {
ImmutableSet<ModuleDescriptor> producerModules =
@@ -209,7 +212,7 @@ final class ComponentHierarchyValidator {
}
private void validateRepeatedScopedDeclarations(
- ValidationReport.Builder<TypeElement> report,
+ ValidationReport.Builder report,
ComponentDescriptor component,
// TODO(ronshapiro): optimize ModuleDescriptor.hashCode()/equals. Otherwise this could be
// quite costly
@@ -264,10 +267,10 @@ final class ComponentHierarchyValidator {
}
private ImmutableSet<Scope> moduleScopes(ModuleDescriptor module) {
- return FluentIterable.concat(module.allBindingDeclarations())
- .transform(declaration -> uniqueScopeOf(declaration.bindingElement().get()))
+ return module.allBindingDeclarations().stream()
+ .map(declaration -> injectionAnnotations.getScope(declaration.bindingElement().get()))
.filter(scope -> scope.isPresent() && !scope.get().isReusable())
- .transform(scope -> scope.get())
- .toSet();
+ .map(Optional::get)
+ .collect(toImmutableSet());
}
}
diff --git a/java/dagger/internal/codegen/validation/ComponentValidator.java b/java/dagger/internal/codegen/validation/ComponentValidator.java
index 72a44f251..9f2119ac8 100644
--- a/java/dagger/internal/codegen/validation/ComponentValidator.java
+++ b/java/dagger/internal/codegen/validation/ComponentValidator.java
@@ -16,38 +16,43 @@
package dagger.internal.codegen.validation;
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.auto.common.MoreTypes.asExecutable;
-import static com.google.auto.common.MoreTypes.asTypeElement;
+import static androidx.room.compiler.processing.XTypeKt.isVoid;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static androidx.room.compiler.processing.compat.XConverters.toXProcessing;
import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.Iterables.consumingIterable;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.collect.Multimaps.asMap;
import static com.google.common.collect.Sets.intersection;
import static dagger.internal.codegen.base.ComponentAnnotation.anyComponentAnnotation;
+import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotation;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.creatorAnnotationsFor;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.productionCreatorAnnotations;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.subcomponentCreatorAnnotations;
+import static dagger.internal.codegen.base.ComponentKind.annotationsFor;
import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
+import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotations;
import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.creatorAnnotationsFor;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.productionCreatorAnnotations;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.subcomponentCreatorAnnotations;
-import static dagger.internal.codegen.binding.ComponentKind.annotationsFor;
import static dagger.internal.codegen.binding.ConfigurationAnnotations.enclosedAnnotatedTypes;
-import static dagger.internal.codegen.binding.ConfigurationAnnotations.getTransitiveModules;
import static dagger.internal.codegen.binding.ErrorMessages.ComponentCreatorMessages.builderMethodRequiresNoArgs;
import static dagger.internal.codegen.binding.ErrorMessages.ComponentCreatorMessages.moreThanOneRefToSubcomponent;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnyAnnotation;
+import static dagger.internal.codegen.xprocessing.XElements.asMethod;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+import static dagger.internal.codegen.xprocessing.XElements.getAnyAnnotation;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static dagger.internal.codegen.xprocessing.XTypeElements.getAllUnimplementedMethods;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
import static java.util.Comparator.comparing;
-import static javax.lang.model.element.ElementKind.CLASS;
-import static javax.lang.model.element.ElementKind.INTERFACE;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.type.TypeKind.VOID;
import static javax.lang.model.util.ElementFilter.methodsIn;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XExecutableParameterElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XMethodType;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -55,76 +60,75 @@ import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.TypeName;
import dagger.Component;
-import dagger.Reusable;
import dagger.internal.codegen.base.ClearableCache;
import dagger.internal.codegen.base.ComponentAnnotation;
-import dagger.internal.codegen.binding.ComponentKind;
+import dagger.internal.codegen.base.ComponentKind;
+import dagger.internal.codegen.base.DaggerSuperficialValidation;
+import dagger.internal.codegen.base.ModuleKind;
import dagger.internal.codegen.binding.DependencyRequestFactory;
import dagger.internal.codegen.binding.ErrorMessages;
import dagger.internal.codegen.binding.MethodSignatureFormatter;
-import dagger.internal.codegen.binding.ModuleKind;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.producers.CancellationPolicy;
-import dagger.producers.ProductionComponent;
-import java.lang.annotation.Annotation;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
+import java.util.ArrayDeque;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Queue;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVisitor;
-import javax.lang.model.util.SimpleTypeVisitor8;
+import javax.lang.model.SourceVersion;
/**
* Performs superficial validation of the contract of the {@link Component} and {@link
- * ProductionComponent} annotations.
+ * dagger.producers.ProductionComponent} annotations.
*/
@Singleton
public final class ComponentValidator implements ClearableCache {
+ private final XProcessingEnv processingEnv;
private final DaggerElements elements;
- private final DaggerTypes types;
private final ModuleValidator moduleValidator;
private final ComponentCreatorValidator creatorValidator;
private final DependencyRequestValidator dependencyRequestValidator;
private final MembersInjectionValidator membersInjectionValidator;
private final MethodSignatureFormatter methodSignatureFormatter;
private final DependencyRequestFactory dependencyRequestFactory;
- private final Map<TypeElement, ValidationReport<TypeElement>> reports = new HashMap<>();
+ private final DaggerSuperficialValidation superficialValidation;
+ private final Map<XTypeElement, ValidationReport> reports = new HashMap<>();
+ private final KotlinMetadataUtil metadataUtil;
@Inject
ComponentValidator(
+ XProcessingEnv processingEnv,
DaggerElements elements,
- DaggerTypes types,
ModuleValidator moduleValidator,
ComponentCreatorValidator creatorValidator,
DependencyRequestValidator dependencyRequestValidator,
MembersInjectionValidator membersInjectionValidator,
MethodSignatureFormatter methodSignatureFormatter,
- DependencyRequestFactory dependencyRequestFactory) {
+ DependencyRequestFactory dependencyRequestFactory,
+ DaggerSuperficialValidation superficialValidation,
+ KotlinMetadataUtil metadataUtil) {
+ this.processingEnv = processingEnv;
this.elements = elements;
- this.types = types;
this.moduleValidator = moduleValidator;
this.creatorValidator = creatorValidator;
this.dependencyRequestValidator = dependencyRequestValidator;
this.membersInjectionValidator = membersInjectionValidator;
this.methodSignatureFormatter = methodSignatureFormatter;
this.dependencyRequestFactory = dependencyRequestFactory;
+ this.superficialValidation = superficialValidation;
+ this.metadataUtil = metadataUtil;
}
@Override
@@ -133,24 +137,24 @@ public final class ComponentValidator implements ClearableCache {
}
/** Validates the given component. */
- public ValidationReport<TypeElement> validate(TypeElement component) {
+ public ValidationReport validate(XTypeElement component) {
return reentrantComputeIfAbsent(reports, component, this::validateUncached);
}
- private ValidationReport<TypeElement> validateUncached(TypeElement component) {
+ private ValidationReport validateUncached(XTypeElement component) {
return new ElementValidator(component).validateElement();
}
private class ElementValidator {
- private final TypeElement component;
- private final ValidationReport.Builder<TypeElement> report;
+ private final XTypeElement component;
+ private final ValidationReport.Builder report;
private final ImmutableSet<ComponentKind> componentKinds;
// Populated by ComponentMethodValidators
- private final SetMultimap<Element, ExecutableElement> referencedSubcomponents =
+ private final SetMultimap<XTypeElement, XMethodElement> referencedSubcomponents =
LinkedHashMultimap.create();
- ElementValidator(TypeElement component) {
+ ElementValidator(XTypeElement component) {
this.component = component;
this.report = ValidationReport.about(component);
this.componentKinds = ComponentKind.getComponentKinds(component);
@@ -161,14 +165,10 @@ public final class ComponentValidator implements ClearableCache {
}
private ComponentAnnotation componentAnnotation() {
- return anyComponentAnnotation(component).get();
+ return anyComponentAnnotation(component, superficialValidation).get();
}
- private DeclaredType componentType() {
- return asDeclared(component.asType());
- }
-
- ValidationReport<TypeElement> validateElement() {
+ ValidationReport validateElement() {
if (componentKinds.size() > 1) {
return moreThanOneComponentAnnotation();
}
@@ -187,7 +187,7 @@ public final class ComponentValidator implements ClearableCache {
return report.build();
}
- private ValidationReport<TypeElement> moreThanOneComponentAnnotation() {
+ private ValidationReport moreThanOneComponentAnnotation() {
String error =
"Components may not be annotated with more than one component annotation: found "
+ annotationsFor(componentKinds);
@@ -196,8 +196,7 @@ public final class ComponentValidator implements ClearableCache {
}
private void validateUseOfCancellationPolicy() {
- if (isAnnotationPresent(component, CancellationPolicy.class)
- && !componentKind().isProducer()) {
+ if (component.hasAnnotation(TypeNames.CANCELLATION_POLICY) && !componentKind().isProducer()) {
report.addError(
"@CancellationPolicy may only be applied to production components and subcomponents",
component);
@@ -205,23 +204,19 @@ public final class ComponentValidator implements ClearableCache {
}
private void validateIsAbstractType() {
- if (!component.getKind().equals(INTERFACE)
- && !(component.getKind().equals(CLASS) && component.getModifiers().contains(ABSTRACT))) {
+ if (!component.isInterface() && !(component.isClass() && component.isAbstract())) {
report.addError(
String.format(
"@%s may only be applied to an interface or abstract class",
- componentKind().annotation().getSimpleName()),
+ componentKind().annotation().simpleName()),
component);
}
}
private void validateCreators() {
- ImmutableList<DeclaredType> creators =
- creatorAnnotationsFor(componentAnnotation()).stream()
- .flatMap(annotation -> enclosedAnnotatedTypes(component, annotation).stream())
- .collect(toImmutableList());
- creators.forEach(
- creator -> report.addSubreport(creatorValidator.validate(asTypeElement(creator))));
+ ImmutableSet<XTypeElement> creators =
+ enclosedAnnotatedTypes(component, creatorAnnotationsFor(componentAnnotation()));
+ creators.forEach(creator -> report.addSubreport(creatorValidator.validate(creator)));
if (creators.size() > 1) {
report.addError(
String.format(
@@ -231,32 +226,44 @@ public final class ComponentValidator implements ClearableCache {
}
private void validateNoReusableAnnotation() {
- Optional<AnnotationMirror> reusableAnnotation =
- getAnnotationMirror(component, Reusable.class);
- if (reusableAnnotation.isPresent()) {
+ if (component.hasAnnotation(TypeNames.REUSABLE)) {
report.addError(
"@Reusable cannot be applied to components or subcomponents",
component,
- reusableAnnotation.get());
+ component.getAnnotation(TypeNames.REUSABLE));
}
}
private void validateComponentMethods() {
- elements.getUnimplementedMethods(component).stream()
+ validateClassMethodName();
+ getAllUnimplementedMethods(component).stream()
.map(ComponentMethodValidator::new)
.forEachOrdered(ComponentMethodValidator::validateMethod);
}
+ private void validateClassMethodName() {
+ if (metadataUtil.hasMetadata(toJavac(component))) {
+ metadataUtil
+ .getAllMethodNamesBySignature(toJavac(component))
+ .forEach(
+ (signature, name) -> {
+ if (SourceVersion.isKeyword(name)) {
+ report.addError("Can not use a Java keyword as method name: " + signature);
+ }
+ });
+ }
+ }
+
private class ComponentMethodValidator {
- private final ExecutableElement method;
- private final ExecutableType resolvedMethod;
- private final List<? extends TypeMirror> parameterTypes;
- private final List<? extends VariableElement> parameters;
- private final TypeMirror returnType;
+ private final XMethodElement method;
+ private final XMethodType resolvedMethod;
+ private final List<XType> parameterTypes;
+ private final List<XExecutableParameterElement> parameters;
+ private final XType returnType;
- ComponentMethodValidator(ExecutableElement method) {
+ ComponentMethodValidator(XMethodElement method) {
this.method = method;
- this.resolvedMethod = asExecutable(types.asMemberOf(componentType(), method));
+ this.resolvedMethod = method.asMemberOf(component.getType());
this.parameterTypes = resolvedMethod.getParameterTypes();
this.parameters = method.getParameters();
this.returnType = resolvedMethod.getReturnType();
@@ -268,7 +275,7 @@ public final class ComponentValidator implements ClearableCache {
// abstract methods are ones we have to implement, so they each need to be validated
// first, check the return type. if it's a subcomponent, validate that method as
// such.
- Optional<AnnotationMirror> subcomponentAnnotation = subcomponentAnnotation();
+ Optional<ComponentAnnotation> subcomponentAnnotation = legalSubcomponentAnnotation();
if (subcomponentAnnotation.isPresent()) {
validateSubcomponentFactoryMethod(subcomponentAnnotation.get());
} else if (subcomponentCreatorAnnotation().isPresent()) {
@@ -290,20 +297,25 @@ public final class ComponentValidator implements ClearableCache {
}
private void validateNoTypeVariables() {
- if (!resolvedMethod.getTypeVariables().isEmpty()) {
+ if (!resolvedMethod.getTypeVariableNames().isEmpty()) {
report.addError("Component methods cannot have type variables", method);
}
}
- private Optional<AnnotationMirror> subcomponentAnnotation() {
- return checkForAnnotations(
- returnType,
- componentKind().legalSubcomponentKinds().stream()
- .map(ComponentKind::annotation)
- .collect(toImmutableSet()));
+ private Optional<ComponentAnnotation> legalSubcomponentAnnotation() {
+ return Optional.ofNullable(returnType.getTypeElement())
+ .flatMap(element -> subcomponentAnnotation(element, superficialValidation))
+ // TODO(bcorso): Consider failing on illegal subcomponents rather than just filtering.
+ .filter(annotation -> legalSubcomponentAnnotations().contains(annotation.className()));
}
- private Optional<AnnotationMirror> subcomponentCreatorAnnotation() {
+ private ImmutableSet<ClassName> legalSubcomponentAnnotations() {
+ return componentKind().legalSubcomponentKinds().stream()
+ .map(ComponentKind::annotation)
+ .collect(toImmutableSet());
+ }
+
+ private Optional<XAnnotation> subcomponentCreatorAnnotation() {
return checkForAnnotations(
returnType,
componentAnnotation().isProduction()
@@ -311,64 +323,46 @@ public final class ComponentValidator implements ClearableCache {
: subcomponentCreatorAnnotations());
}
- private void validateSubcomponentFactoryMethod(AnnotationMirror subcomponentAnnotation) {
- referencedSubcomponents.put(MoreTypes.asElement(returnType), method);
+ private void validateSubcomponentFactoryMethod(ComponentAnnotation subcomponentAnnotation) {
+ referencedSubcomponents.put(returnType.getTypeElement(), method);
- ComponentKind subcomponentKind =
- ComponentKind.forAnnotatedElement(MoreTypes.asTypeElement(returnType)).get();
- ImmutableSet<TypeElement> moduleTypes =
- ComponentAnnotation.componentAnnotation(subcomponentAnnotation).modules();
+ ImmutableSet<ClassName> legalModuleAnnotations =
+ ComponentKind.forAnnotatedElement(returnType.getTypeElement())
+ .get()
+ .legalModuleKinds()
+ .stream()
+ .map(ModuleKind::annotation)
+ .collect(toImmutableSet());
+ ImmutableSet<XTypeElement> moduleTypes = subcomponentAnnotation.modules();
// TODO(gak): This logic maybe/probably shouldn't live here as it requires us to traverse
// subcomponents and their modules separately from how it is done in ComponentDescriptor and
// ModuleDescriptor
- @SuppressWarnings("deprecation")
- ImmutableSet<TypeElement> transitiveModules =
- getTransitiveModules(types, elements, moduleTypes);
-
- Set<TypeElement> variableTypes = Sets.newHashSet();
+ ImmutableSet<XTypeElement> transitiveModules = getTransitiveModules(moduleTypes);
+ Set<XTypeElement> referencedModules = Sets.newHashSet();
for (int i = 0; i < parameterTypes.size(); i++) {
- VariableElement parameter = parameters.get(i);
- TypeMirror parameterType = parameterTypes.get(i);
- Optional<TypeElement> moduleType =
- parameterType.accept(
- new SimpleTypeVisitor8<Optional<TypeElement>, Void>() {
- @Override
- protected Optional<TypeElement> defaultAction(TypeMirror e, Void p) {
- return Optional.empty();
- }
-
- @Override
- public Optional<TypeElement> visitDeclared(DeclaredType t, Void p) {
- for (ModuleKind moduleKind : subcomponentKind.legalModuleKinds()) {
- if (isAnnotationPresent(t.asElement(), moduleKind.annotation())) {
- return Optional.of(MoreTypes.asTypeElement(t));
- }
- }
- return Optional.empty();
- }
- },
- null);
- if (moduleType.isPresent()) {
- if (variableTypes.contains(moduleType.get())) {
+ XExecutableParameterElement parameter = parameters.get(i);
+ XType parameterType = parameterTypes.get(i);
+ if (checkForAnnotations(parameterType, legalModuleAnnotations).isPresent()) {
+ XTypeElement module = parameterType.getTypeElement();
+ if (referencedModules.contains(module)) {
report.addError(
String.format(
- "A module may only occur once an an argument in a Subcomponent factory "
+ "A module may only occur once as an argument in a Subcomponent factory "
+ "method, but %s was already passed.",
- moduleType.get().getQualifiedName()),
+ module.getQualifiedName()),
parameter);
}
- if (!transitiveModules.contains(moduleType.get())) {
+ if (!transitiveModules.contains(module)) {
report.addError(
String.format(
"%s is present as an argument to the %s factory method, but is not one of the"
+ " modules used to implement the subcomponent.",
- moduleType.get().getQualifiedName(),
- MoreTypes.asTypeElement(returnType).getQualifiedName()),
+ module.getQualifiedName(), returnType.getTypeElement().getQualifiedName()),
method);
}
- variableTypes.add(moduleType.get());
+ referencedModules.add(module);
} else {
report.addError(
String.format(
@@ -379,14 +373,52 @@ public final class ComponentValidator implements ClearableCache {
}
}
+ /**
+ * Returns the full set of modules transitively included from the given seed modules, which
+ * includes all transitive {@link Module#includes} and all transitive super classes. If a
+ * module is malformed and a type listed in {@link Module#includes} is not annotated with
+ * {@link Module}, it is ignored.
+ */
+ private ImmutableSet<XTypeElement> getTransitiveModules(
+ Collection<XTypeElement> seedModules) {
+ Set<XTypeElement> processedElements = Sets.newLinkedHashSet();
+ Queue<XTypeElement> moduleQueue = new ArrayDeque<>(seedModules);
+ ImmutableSet.Builder<XTypeElement> moduleElements = ImmutableSet.builder();
+ for (XTypeElement moduleElement : consumingIterable(moduleQueue)) {
+ if (processedElements.add(moduleElement)) {
+ moduleAnnotation(moduleElement, superficialValidation)
+ .ifPresent(
+ moduleAnnotation -> {
+ moduleElements.add(moduleElement);
+ moduleQueue.addAll(moduleAnnotation.includes());
+ moduleQueue.addAll(includesFromSuperclasses(moduleElement));
+ });
+ }
+ }
+ return moduleElements.build();
+ }
+
+ /** Returns {@link Module#includes()} from all transitive super classes. */
+ private ImmutableSet<XTypeElement> includesFromSuperclasses(XTypeElement element) {
+ ImmutableSet.Builder<XTypeElement> builder = ImmutableSet.builder();
+ XType superclass = element.getSuperType();
+ while (superclass != null && !TypeName.OBJECT.equals(superclass.getTypeName())) {
+ element = superclass.getTypeElement();
+ moduleAnnotation(element, superficialValidation)
+ .ifPresent(moduleAnnotation -> builder.addAll(moduleAnnotation.includes()));
+ superclass = element.getSuperType();
+ }
+ return builder.build();
+ }
+
private void validateSubcomponentCreatorMethod() {
- referencedSubcomponents.put(MoreTypes.asElement(returnType).getEnclosingElement(), method);
+ referencedSubcomponents.put(returnType.getTypeElement().getEnclosingTypeElement(), method);
if (!parameters.isEmpty()) {
report.addError(builderMethodRequiresNoArgs(), method);
}
- TypeElement creatorElement = MoreTypes.asTypeElement(returnType);
+ XTypeElement creatorElement = returnType.getTypeElement();
// TODO(sameb): The creator validator right now assumes the element is being compiled
// in this pass, which isn't true here. We should change error messages to spit out
// this method as the subject and add the original subject to the message output.
@@ -398,10 +430,10 @@ public final class ComponentValidator implements ClearableCache {
}
private void validateMembersInjectionMethod() {
- TypeMirror parameterType = getOnlyElement(parameterTypes);
+ XType parameterType = getOnlyElement(parameterTypes);
report.addSubreport(
membersInjectionValidator.validateMembersInjectionMethod(method, parameterType));
- if (!(returnType.getKind().equals(VOID) || types.isSameType(returnType, parameterType))) {
+ if (!(isVoid(returnType) || returnType.isSameType(parameterType))) {
report.addError(
"Members injection methods may only return the injected type or void.", method);
}
@@ -418,38 +450,40 @@ public final class ComponentValidator implements ClearableCache {
private void validateNoConflictingEntryPoints() {
// Collect entry point methods that are not overridden by others. If the "same" method is
// inherited from more than one supertype, each will be in the multimap.
- SetMultimap<String, ExecutableElement> entryPointMethods = HashMultimap.create();
-
- methodsIn(elements.getAllMembers(component)).stream()
- .filter(
- method ->
- isEntryPoint(method, asExecutable(types.asMemberOf(componentType(), method))))
+ SetMultimap<String, XMethodElement> entryPoints = HashMultimap.create();
+
+ // TODO(b/201729320): There's a bug in auto-common's MoreElements#overrides(), b/201729320,
+ // which prevents us from using XTypeElement#getAllMethods() here (since that method relies on
+ // MoreElements#overrides() under the hood).
+ //
+ // There's two options here.
+ // 1. Fix the bug in auto-common and update XProcessing's auto-common dependency
+ // 2. Add a new method in XProcessing which relies on Elements#overrides(), which does not
+ // have this issue. However, this approach risks causing issues for EJC (Eclipse) users.
+ methodsIn(elements.getAllMembers(toJavac(component))).stream()
+ .map(method -> asMethod(toXProcessing(method, processingEnv)))
+ .filter(method -> isEntryPoint(method, method.asMemberOf(component.getType())))
.forEach(
- method ->
- addMethodUnlessOverridden(
- method, entryPointMethods.get(method.getSimpleName().toString())));
+ method -> addMethodUnlessOverridden(method, entryPoints.get(getSimpleName(method))));
- for (Set<ExecutableElement> methods : asMap(entryPointMethods).values()) {
- if (distinctKeys(methods).size() > 1) {
- reportConflictingEntryPoints(methods);
- }
- }
+ asMap(entryPoints).values().stream()
+ .filter(methods -> distinctKeys(methods).size() > 1)
+ .forEach(this::reportConflictingEntryPoints);
}
- private void reportConflictingEntryPoints(Collection<ExecutableElement> methods) {
+ private void reportConflictingEntryPoints(Collection<XMethodElement> methods) {
verify(
- methods.stream().map(ExecutableElement::getEnclosingElement).distinct().count()
+ methods.stream().map(XMethodElement::getEnclosingElement).distinct().count()
== methods.size(),
"expected each method to be declared on a different type: %s",
methods);
StringBuilder message = new StringBuilder("conflicting entry point declarations:");
methodSignatureFormatter
- .typedFormatter(componentType())
+ .typedFormatter(component.getType())
.formatIndentedList(
message,
ImmutableList.sortedCopyOf(
- comparing(
- method -> asType(method.getEnclosingElement()).getQualifiedName().toString()),
+ comparing(method -> method.getEnclosingElement().getClassName().canonicalName()),
methods),
1);
report.addError(message.toString());
@@ -465,8 +499,12 @@ public final class ComponentValidator implements ClearableCache {
}
private void validateComponentDependencies() {
- for (TypeMirror type : componentAnnotation().dependencyTypes()) {
- type.accept(CHECK_DEPENDENCY_TYPES, report);
+ for (XType type : componentAnnotation().dependencyTypes()) {
+ if (!isDeclared(type)) {
+ report.addError(type + " is not a valid component dependency type");
+ } else if (type.getTypeElement().hasAnyAnnotation(moduleAnnotations())) {
+ report.addError(type + " is a module, which cannot be a component dependency");
+ }
}
}
@@ -481,35 +519,34 @@ public final class ComponentValidator implements ClearableCache {
private void validateSubcomponents() {
// Make sure we validate any subcomponents we're referencing.
- for (Element subcomponent : referencedSubcomponents.keySet()) {
- ValidationReport<TypeElement> subreport = validate(asType(subcomponent));
- report.addSubreport(subreport);
- }
+ referencedSubcomponents
+ .keySet()
+ .forEach(subcomponent -> report.addSubreport(validate(subcomponent)));
}
- private ImmutableSet<Key> distinctKeys(Set<ExecutableElement> methods) {
+ private ImmutableSet<Key> distinctKeys(Set<XMethodElement> methods) {
return methods.stream()
.map(this::dependencyRequest)
.map(DependencyRequest::key)
.collect(toImmutableSet());
}
- private DependencyRequest dependencyRequest(ExecutableElement method) {
- ExecutableType methodType = asExecutable(types.asMemberOf(componentType(), method));
- return ComponentKind.forAnnotatedElement(component).get().isProducer()
+ private DependencyRequest dependencyRequest(XMethodElement method) {
+ XMethodType methodType = method.asMemberOf(component.getType());
+ return componentKind().isProducer()
? dependencyRequestFactory.forComponentProductionMethod(method, methodType)
: dependencyRequestFactory.forComponentProvisionMethod(method, methodType);
}
}
- private static boolean isEntryPoint(ExecutableElement method, ExecutableType methodType) {
- return method.getModifiers().contains(ABSTRACT)
+ private static boolean isEntryPoint(XMethodElement method, XMethodType methodType) {
+ return method.isAbstract()
&& method.getParameters().isEmpty()
- && !methodType.getReturnType().getKind().equals(VOID)
- && methodType.getTypeVariables().isEmpty();
+ && !isVoid(methodType.getReturnType())
+ && methodType.getTypeVariableNames().isEmpty();
}
- private void addMethodUnlessOverridden(ExecutableElement method, Set<ExecutableElement> methods) {
+ private void addMethodUnlessOverridden(XMethodElement method, Set<XMethodElement> methods) {
if (methods.stream().noneMatch(existingMethod -> overridesAsDeclared(existingMethod, method))) {
methods.removeIf(existingMethod -> overridesAsDeclared(method, existingMethod));
methods.add(method);
@@ -521,36 +558,15 @@ public final class ComponentValidator implements ClearableCache {
* the type that declares {@code overrider}.
*/
// TODO(dpb): Does this break for ECJ?
- private boolean overridesAsDeclared(ExecutableElement overrider, ExecutableElement overridden) {
- return elements.overrides(overrider, overridden, asType(overrider.getEnclosingElement()));
+ private boolean overridesAsDeclared(XMethodElement overrider, XMethodElement overridden) {
+ return elements.overrides(
+ toJavac(overrider),
+ toJavac(overridden),
+ toJavac(asTypeElement(overrider.getEnclosingElement())));
}
- private static final TypeVisitor<Void, ValidationReport.Builder<?>> CHECK_DEPENDENCY_TYPES =
- new SimpleTypeVisitor8<Void, ValidationReport.Builder<?>>() {
- @Override
- protected Void defaultAction(TypeMirror type, ValidationReport.Builder<?> report) {
- report.addError(type + " is not a valid component dependency type");
- return null;
- }
-
- @Override
- public Void visitDeclared(DeclaredType type, ValidationReport.Builder<?> report) {
- if (moduleAnnotation(MoreTypes.asTypeElement(type)).isPresent()) {
- report.addError(type + " is a module, which cannot be a component dependency");
- }
- return null;
- }
- };
-
- private static Optional<AnnotationMirror> checkForAnnotations(
- TypeMirror type, final Set<? extends Class<? extends Annotation>> annotations) {
- return type.accept(
- new SimpleTypeVisitor8<Optional<AnnotationMirror>, Void>(Optional.empty()) {
- @Override
- public Optional<AnnotationMirror> visitDeclared(DeclaredType t, Void p) {
- return getAnyAnnotation(t.asElement(), annotations);
- }
- },
- null);
+ private static Optional<XAnnotation> checkForAnnotations(XType type, Set<ClassName> annotations) {
+ return Optional.ofNullable(type.getTypeElement())
+ .flatMap(typeElement -> getAnyAnnotation(typeElement, annotations));
}
}
diff --git a/java/dagger/internal/codegen/validation/CompositeBindingGraphPlugin.java b/java/dagger/internal/codegen/validation/CompositeBindingGraphPlugin.java
index a9c650a1b..63bf32b54 100644
--- a/java/dagger/internal/codegen/validation/CompositeBindingGraphPlugin.java
+++ b/java/dagger/internal/codegen/validation/CompositeBindingGraphPlugin.java
@@ -22,17 +22,17 @@ import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Lists.asList;
import static dagger.internal.codegen.base.ElementFormatter.elementToString;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerElements.elementEncloses;
+import static dagger.internal.codegen.langmodel.DaggerElements.transitivelyEncloses;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.FormatMethod;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ChildFactoryMethodEdge;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.MaybeBinding;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.spi.model.BindingGraph.ComponentNode;
+import dagger.spi.model.BindingGraph.DependencyEdge;
+import dagger.spi.model.BindingGraph.MaybeBinding;
+import dagger.spi.model.BindingGraphPlugin;
+import dagger.spi.model.DiagnosticReporter;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@@ -216,16 +216,18 @@ public final class CompositeBindingGraphPlugin implements BindingGraphPlugin {
String message) {
// TODO(erichang): This repeats some of the logic in DiagnosticReporterImpl. Remove when
// merged.
- if (elementEncloses(
- graph.rootComponentNode().componentPath().currentComponent(),
- childFactoryMethodEdge.factoryMethod())) {
+ if (transitivelyEncloses(
+ graph.rootComponentNode().componentPath().currentComponent().java(),
+ childFactoryMethodEdge.factoryMethod().java())) {
// Let this pass through since it is not an error reported on the root component
delegate.reportSubcomponentFactoryMethod(diagnosticKind, childFactoryMethodEdge, message);
} else {
addMessage(
diagnosticKind,
String.format(
- "[%s] %s", elementToString(childFactoryMethodEdge.factoryMethod()), message));
+ "[%s] %s",
+ elementToString(childFactoryMethodEdge.factoryMethod().java()),
+ message));
}
}
diff --git a/java/dagger/internal/codegen/validation/DependencyRequestValidator.java b/java/dagger/internal/codegen/validation/DependencyRequestValidator.java
index f28049753..45b77631a 100644
--- a/java/dagger/internal/codegen/validation/DependencyRequestValidator.java
+++ b/java/dagger/internal/codegen/validation/DependencyRequestValidator.java
@@ -16,55 +16,54 @@
package dagger.internal.codegen.validation;
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreElements.asVariable;
-import static com.google.auto.common.MoreTypes.asTypeElement;
+import static androidx.room.compiler.processing.XElementKt.isField;
+import static androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static dagger.internal.codegen.base.RequestKinds.extractKeyType;
import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedFactoryType;
import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedInjectionType;
import static dagger.internal.codegen.binding.SourceFiles.membersInjectorNameForType;
-import static javax.lang.model.element.Modifier.STATIC;
-import static javax.lang.model.type.TypeKind.WILDCARD;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableCollection;
-import dagger.MembersInjector;
-import dagger.assisted.Assisted;
+import static dagger.internal.codegen.xprocessing.XElements.asField;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
+import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;
+import static dagger.internal.codegen.xprocessing.XTypes.isWildcard;
+
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFieldElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.XVariableElement;
+import com.google.common.collect.ImmutableSet;
import dagger.internal.codegen.base.FrameworkTypes;
import dagger.internal.codegen.base.RequestKinds;
import dagger.internal.codegen.binding.InjectionAnnotations;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.model.RequestKind;
+import dagger.spi.model.RequestKind;
import java.util.Optional;
import javax.inject.Inject;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
/** Validation for dependency requests. */
final class DependencyRequestValidator {
+ private final XProcessingEnv processingEnv;
private final MembersInjectionValidator membersInjectionValidator;
private final InjectionAnnotations injectionAnnotations;
private final KotlinMetadataUtil metadataUtil;
- private final DaggerElements elements;
@Inject
DependencyRequestValidator(
+ XProcessingEnv processingEnv,
MembersInjectionValidator membersInjectionValidator,
InjectionAnnotations injectionAnnotations,
- KotlinMetadataUtil metadataUtil,
- DaggerElements elements) {
+ KotlinMetadataUtil metadataUtil) {
+ this.processingEnv = processingEnv;
this.membersInjectionValidator = membersInjectionValidator;
this.injectionAnnotations = injectionAnnotations;
this.metadataUtil = metadataUtil;
- this.elements = elements;
}
/**
@@ -72,15 +71,16 @@ final class DependencyRequestValidator {
* non-instance request with a wildcard type.
*/
void validateDependencyRequest(
- ValidationReport.Builder<?> report, Element requestElement, TypeMirror requestType) {
- if (MoreElements.isAnnotationPresent(requestElement, Assisted.class)) {
+ ValidationReport.Builder report, XElement requestElement, XType requestType) {
+ if (requestElement.hasAnnotation(TypeNames.ASSISTED)) {
// Don't validate assisted parameters. These are not dependency requests.
return;
}
if (missingQualifierMetadata(requestElement)) {
report.addError(
- "Unable to read annotations on an injected Kotlin property. The Dagger compiler must"
- + " also be applied to any project containing @Inject properties.",
+ "Unable to read annotations on an injected Kotlin property. "
+ + "The Dagger compiler must also be applied to any project containing @Inject "
+ + "properties.",
requestElement);
// Skip any further validation if we don't have valid metadata for a type that needs it.
@@ -91,36 +91,36 @@ final class DependencyRequestValidator {
}
/** Returns {@code true} if a kotlin inject field is missing metadata about its qualifiers. */
- private boolean missingQualifierMetadata(Element requestElement) {
- if (requestElement.getKind() == ElementKind.FIELD
- // static injected fields are not supported, no need to get qualifier from kotlin metadata
- && !requestElement.getModifiers().contains(STATIC)
- && metadataUtil.hasMetadata(requestElement)
- && metadataUtil.isMissingSyntheticPropertyForAnnotations(asVariable(requestElement))) {
- Optional<TypeElement> membersInjector =
- Optional.ofNullable(
- elements.getTypeElement(
- membersInjectorNameForType(asType(requestElement.getEnclosingElement()))));
- return !membersInjector.isPresent();
+ private boolean missingQualifierMetadata(XElement requestElement) {
+ if (isField(requestElement)) {
+ XFieldElement fieldElement = asField(requestElement);
+ // static/top-level injected fields are not supported,
+ // so no need to get qualifier from kotlin metadata
+ if ((!fieldElement.isStatic() || !isTypeElement(fieldElement.getEnclosingElement()))
+ && metadataUtil.hasMetadata(toJavac(fieldElement))
+ && metadataUtil.isMissingSyntheticPropertyForAnnotations(toJavac(fieldElement))) {
+ Optional<XTypeElement> membersInjector =
+ Optional.ofNullable(
+ processingEnv.findTypeElement(
+ membersInjectorNameForType(asTypeElement(fieldElement.getEnclosingElement()))));
+ return !membersInjector.isPresent();
+ }
}
return false;
}
private final class Validator {
- private final ValidationReport.Builder<?> report;
- private final Element requestElement;
- private final TypeMirror requestType;
- private final TypeMirror keyType;
- private final RequestKind requestKind;
- private final ImmutableCollection<? extends AnnotationMirror> qualifiers;
-
+ private final ValidationReport.Builder report;
+ private final XElement requestElement;
+ private final XType requestType;
+ private final XType keyType;
+ private final ImmutableSet<XAnnotation> qualifiers;
- Validator(ValidationReport.Builder<?> report, Element requestElement, TypeMirror requestType) {
+ Validator(ValidationReport.Builder report, XElement requestElement, XType requestType) {
this.report = report;
this.requestElement = requestElement;
this.requestType = requestType;
this.keyType = extractKeyType(requestType);
- this.requestKind = RequestKinds.getRequestKind(requestType);
this.qualifiers = injectionAnnotations.getQualifiers(requestElement);
}
@@ -131,7 +131,7 @@ final class DependencyRequestValidator {
private void checkQualifiers() {
if (qualifiers.size() > 1) {
- for (AnnotationMirror qualifier : qualifiers) {
+ for (XAnnotation qualifier : qualifiers) {
report.addError(
"A single dependency request may not use more than one @Qualifier",
requestElement,
@@ -141,8 +141,8 @@ final class DependencyRequestValidator {
}
private void checkType() {
- if (qualifiers.isEmpty() && keyType.getKind() == TypeKind.DECLARED) {
- TypeElement typeElement = asTypeElement(keyType);
+ if (qualifiers.isEmpty() && isDeclared(keyType)) {
+ XTypeElement typeElement = keyType.getTypeElement();
if (isAssistedInjectionType(typeElement)) {
report.addError(
"Dagger does not support injecting @AssistedInject type, "
@@ -150,15 +150,17 @@ final class DependencyRequestValidator {
+ ". Did you mean to inject its assisted factory type instead?",
requestElement);
}
- if (requestKind != RequestKind.INSTANCE && isAssistedFactoryType(typeElement)) {
+ RequestKind requestKind = RequestKinds.getRequestKind(requestType);
+ if (!(requestKind == RequestKind.INSTANCE || requestKind == RequestKind.PROVIDER)
+ && isAssistedFactoryType(typeElement)) {
report.addError(
- "Dagger does not support injecting Provider<T>, Lazy<T>, Producer<T>, "
+ "Dagger does not support injecting Lazy<T>, Producer<T>, "
+ "or Produced<T> when T is an @AssistedFactory-annotated type such as "
+ keyType,
requestElement);
}
}
- if (keyType.getKind().equals(WILDCARD)) {
+ if (isWildcard(keyType)) {
// TODO(ronshapiro): Explore creating this message using RequestKinds.
report.addError(
"Dagger does not support injecting Provider<T>, Lazy<T>, Producer<T>, "
@@ -166,14 +168,13 @@ final class DependencyRequestValidator {
+ keyType,
requestElement);
}
- if (MoreTypes.isType(keyType) && MoreTypes.isTypeOf(MembersInjector.class, keyType)) {
- DeclaredType membersInjectorType = MoreTypes.asDeclared(keyType);
- if (membersInjectorType.getTypeArguments().isEmpty()) {
+ if (isTypeOf(keyType, TypeNames.MEMBERS_INJECTOR)) {
+ if (keyType.getTypeArguments().isEmpty()) {
report.addError("Cannot inject a raw MembersInjector", requestElement);
} else {
report.addSubreport(
membersInjectionValidator.validateMembersInjectionRequest(
- requestElement, membersInjectorType.getTypeArguments().get(0)));
+ requestElement, keyType.getTypeArguments().get(0)));
}
}
}
@@ -186,13 +187,13 @@ final class DependencyRequestValidator {
* <p>Only call this when processing a provision binding.
*/
// TODO(dpb): Should we disallow Producer entry points in non-production components?
- void checkNotProducer(ValidationReport.Builder<?> report, VariableElement requestElement) {
- TypeMirror requestType = requestElement.asType();
+ void checkNotProducer(ValidationReport.Builder report, XVariableElement requestElement) {
+ XType requestType = requestElement.getType();
if (FrameworkTypes.isProducerType(requestType)) {
report.addError(
String.format(
"%s may only be injected in @Produces methods",
- MoreTypes.asTypeElement(requestType).getSimpleName()),
+ getSimpleName(requestType.getTypeElement())),
requestElement);
}
}
diff --git a/java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java b/java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java
index 7d7b9e3a9..dca74a68f 100644
--- a/java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java
+++ b/java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java
@@ -48,12 +48,14 @@ import dagger.internal.codegen.base.ElementFormatter;
import dagger.internal.codegen.base.Formatter;
import dagger.internal.codegen.binding.DependencyRequestFormatter;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.Edge;
-import dagger.model.BindingGraph.MaybeBinding;
-import dagger.model.BindingGraph.Node;
-import dagger.model.ComponentPath;
+import dagger.spi.model.Binding;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraph.DependencyEdge;
+import dagger.spi.model.BindingGraph.Edge;
+import dagger.spi.model.BindingGraph.MaybeBinding;
+import dagger.spi.model.BindingGraph.Node;
+import dagger.spi.model.ComponentPath;
+import dagger.spi.model.DaggerElement;
import java.util.Comparator;
import java.util.Set;
import java.util.function.Function;
@@ -149,7 +151,7 @@ public final class DiagnosticMessageGenerator {
dependencyTrace = ImmutableList.of(dependencyEdge);
} else {
// It's not an entry point, so it's part of a binding
- dagger.model.Binding binding = (dagger.model.Binding) source(dependencyEdge);
+ Binding binding = (Binding) source(dependencyEdge);
entryPoints = graph.entryPointEdgesDependingOnBinding(binding);
dependencyTrace =
ImmutableList.<DependencyEdge>builder()
@@ -178,7 +180,15 @@ public final class DiagnosticMessageGenerator {
appendComponentPathUnlessAtRoot(message, source(getLast(dependencyTrace)));
}
}
+ message.append(getRequestsNotInTrace(dependencyTrace, requests, entryPoints));
+ return message.toString();
+ }
+ public String getRequestsNotInTrace(
+ ImmutableList<DependencyEdge> dependencyTrace,
+ ImmutableSet<DependencyEdge> requests,
+ ImmutableSet<DependencyEdge> entryPoints) {
+ StringBuilder message = new StringBuilder();
// Print any dependency requests that aren't shown as part of the dependency trace.
ImmutableSet<Element> requestsToPrint =
requests.stream()
@@ -189,6 +199,7 @@ public final class DiagnosticMessageGenerator {
|| (!request.isEntryPoint() && !isTracedRequest(dependencyTrace, request)))
.map(request -> request.dependencyRequest().requestElement())
.flatMap(presentValues())
+ .map(DaggerElement::java)
.collect(toImmutableSet());
if (!requestsToPrint.isEmpty()) {
message
@@ -229,14 +240,14 @@ public final class DiagnosticMessageGenerator {
new Formatter<DependencyEdge>() {
@Override
public String format(DependencyEdge object) {
- Element requestElement = object.dependencyRequest().requestElement().get();
+ Element requestElement = object.dependencyRequest().requestElement().get().java();
StringBuilder element = new StringBuilder(elementToString(requestElement));
// For entry points declared in subcomponents or supertypes of the root component,
// append the component path to make clear to the user which component it's in.
ComponentPath componentPath = source(object).componentPath();
if (!componentPath.atRoot()
- || !requestElement.getEnclosingElement().equals(componentPath.rootComponent())) {
+ || !requestElement.getEnclosingElement().equals(componentPath.rootComponent().java())) {
element.append(String.format(" [%s]", componentPath));
}
return element.toString();
@@ -252,9 +263,9 @@ public final class DiagnosticMessageGenerator {
* Returns the dependency trace from one of the {@code entryPoints} to {@code binding} to {@code
* message} as a list <i>ending with</i> the entry point.
*/
- // TODO(ronshapiro): Adding a DependencyPath type to dagger.model could be useful, i.e.
+ // TODO(ronshapiro): Adding a DependencyPath type to dagger.spi.model could be useful, i.e.
// bindingGraph.shortestPathFromEntryPoint(DependencyEdge, MaybeBindingNode)
- ImmutableList<DependencyEdge> dependencyTrace(
+ public ImmutableList<DependencyEdge> dependencyTrace(
MaybeBinding binding, ImmutableSet<DependencyEdge> entryPoints) {
// Module binding graphs may have bindings unreachable from any entry points. If there are
// no entry points for this DiagnosticInfo, don't try to print a dependency trace.
@@ -299,7 +310,7 @@ public final class DiagnosticMessageGenerator {
}
/** Returns all the nonsynthetic dependency requests for a binding. */
- ImmutableSet<DependencyEdge> requests(MaybeBinding binding) {
+ public ImmutableSet<DependencyEdge> requests(MaybeBinding binding) {
return graph.network().inEdges(binding).stream()
.flatMap(instancesOf(DependencyEdge.class))
.filter(edge -> edge.dependencyRequest().requestElement().isPresent())
@@ -353,12 +364,12 @@ public final class DiagnosticMessageGenerator {
}
TypeElement componentContainingEntryPoint(DependencyEdge entryPoint) {
- return source(entryPoint).componentPath().currentComponent();
+ return source(entryPoint).componentPath().currentComponent().java();
}
TypeElement typeDeclaringEntryPoint(DependencyEdge entryPoint) {
return MoreElements.asType(
- entryPoint.dependencyRequest().requestElement().get().getEnclosingElement());
+ entryPoint.dependencyRequest().requestElement().get().java().getEnclosingElement());
}
/**
@@ -368,7 +379,7 @@ public final class DiagnosticMessageGenerator {
Comparator<DependencyEdge> requestEnclosingTypeName() {
return comparing(
edge ->
- closestEnclosingTypeElement(edge.dependencyRequest().requestElement().get())
+ closestEnclosingTypeElement(edge.dependencyRequest().requestElement().get().java())
.getQualifiedName()
.toString());
}
@@ -380,7 +391,8 @@ public final class DiagnosticMessageGenerator {
* <p>Only useful to compare edges whose request elements were declared in the same type.
*/
Comparator<DependencyEdge> requestElementDeclarationOrder() {
- return comparing(edge -> edge.dependencyRequest().requestElement().get(), DECLARATION_ORDER);
+ return comparing(
+ edge -> edge.dependencyRequest().requestElement().get().java(), DECLARATION_ORDER);
}
private Node source(Edge edge) {
diff --git a/java/dagger/internal/codegen/validation/DiagnosticReporterFactory.java b/java/dagger/internal/codegen/validation/DiagnosticReporterFactory.java
index 35ae7c728..32cbf183e 100644
--- a/java/dagger/internal/codegen/validation/DiagnosticReporterFactory.java
+++ b/java/dagger/internal/codegen/validation/DiagnosticReporterFactory.java
@@ -18,22 +18,21 @@ package dagger.internal.codegen.validation;
import static com.google.common.collect.Lists.asList;
import static dagger.internal.codegen.base.ElementFormatter.elementToString;
-import static dagger.internal.codegen.langmodel.DaggerElements.elementEncloses;
+import static dagger.internal.codegen.langmodel.DaggerElements.transitivelyEncloses;
import static javax.tools.Diagnostic.Kind.ERROR;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.FormatMethod;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ChildFactoryMethodEdge;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.MaybeBinding;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import javax.annotation.processing.Messager;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.spi.model.BindingGraph.ComponentNode;
+import dagger.spi.model.BindingGraph.DependencyEdge;
+import dagger.spi.model.BindingGraph.MaybeBinding;
+import dagger.spi.model.DiagnosticReporter;
import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;
@@ -41,20 +40,20 @@ import org.checkerframework.checker.nullness.compatqual.NullableDecl;
// TODO(ronshapiro): If multiple plugins print errors on the same node/edge, should we condense the
// messages and only print the dependency trace once?
final class DiagnosticReporterFactory {
- private final Messager messager;
+ private final XMessager messager;
private final DiagnosticMessageGenerator.Factory diagnosticMessageGeneratorFactory;
@Inject
DiagnosticReporterFactory(
- Messager messager, DiagnosticMessageGenerator.Factory diagnosticMessageGeneratorFactory) {
+ XMessager messager, DiagnosticMessageGenerator.Factory diagnosticMessageGeneratorFactory) {
this.messager = messager;
this.diagnosticMessageGeneratorFactory = diagnosticMessageGeneratorFactory;
}
/** Creates a reporter for a binding graph and a plugin. */
DiagnosticReporterImpl reporter(
- BindingGraph graph, BindingGraphPlugin plugin, boolean reportErrorsAsWarnings) {
- return new DiagnosticReporterImpl(graph, plugin.pluginName(), reportErrorsAsWarnings);
+ BindingGraph graph, String pluginName, boolean reportErrorsAsWarnings) {
+ return new DiagnosticReporterImpl(graph, pluginName, reportErrorsAsWarnings);
}
/**
@@ -63,7 +62,7 @@ final class DiagnosticReporterFactory {
*/
final class DiagnosticReporterImpl implements DiagnosticReporter {
private final String plugin;
- private final TypeElement rootComponent;
+ private final XTypeElement rootComponent;
private final boolean reportErrorsAsWarnings;
private final ImmutableSet.Builder<Diagnostic.Kind> reportedDiagnosticKinds =
ImmutableSet.builder();
@@ -72,7 +71,8 @@ final class DiagnosticReporterFactory {
DiagnosticReporterImpl(BindingGraph graph, String plugin, boolean reportErrorsAsWarnings) {
this.plugin = plugin;
this.reportErrorsAsWarnings = reportErrorsAsWarnings;
- this.rootComponent = graph.rootComponentNode().componentPath().currentComponent();
+ this.rootComponent =
+ graph.rootComponentNode().componentPath().currentComponent().xprocessing();
this.diagnosticMessageGenerator = diagnosticMessageGeneratorFactory.create(graph);
}
@@ -145,7 +145,7 @@ final class DiagnosticReporterFactory {
Diagnostic.Kind diagnosticKind,
ChildFactoryMethodEdge childFactoryMethodEdge,
String message) {
- printMessage(diagnosticKind, message, childFactoryMethodEdge.factoryMethod());
+ printMessage(diagnosticKind, message, childFactoryMethodEdge.factoryMethod().xprocessing());
}
@Override
@@ -163,10 +163,10 @@ final class DiagnosticReporterFactory {
return String.format(messageFormat, asList(firstArg, moreArgs).toArray());
}
- void printMessage(
+ private void printMessage(
Diagnostic.Kind diagnosticKind,
CharSequence message,
- @NullableDecl Element elementToReport) {
+ @NullableDecl XElement elementToReport) {
if (diagnosticKind.equals(ERROR) && reportErrorsAsWarnings) {
diagnosticKind = Diagnostic.Kind.WARNING;
}
@@ -174,14 +174,16 @@ final class DiagnosticReporterFactory {
StringBuilder fullMessage = new StringBuilder();
appendBracketPrefix(fullMessage, plugin);
- // TODO(ronshapiro): should we create a HashSet out of elementEncloses() so we don't
- // need to do an O(n) contains() each time?
- if (elementToReport != null && !elementEncloses(rootComponent, elementToReport)) {
- appendBracketPrefix(fullMessage, elementToString(elementToReport));
- elementToReport = rootComponent;
+ if (elementToReport == null) {
+ messager.printMessage(diagnosticKind, fullMessage.append(message).toString());
+ } else {
+ if (!transitivelyEncloses(rootComponent, elementToReport)) {
+ appendBracketPrefix(fullMessage, elementToString(elementToReport));
+ elementToReport = rootComponent;
+ }
+ messager.printMessage(
+ diagnosticKind, fullMessage.append(message).toString(), elementToReport);
}
-
- messager.printMessage(diagnosticKind, fullMessage.append(message), elementToReport);
}
private void appendBracketPrefix(StringBuilder message, String prefix) {
diff --git a/java/dagger/internal/codegen/validation/ExternalBindingGraphConverter.java b/java/dagger/internal/codegen/validation/ExternalBindingGraphConverter.java
new file mode 100644
index 000000000..e2618cc48
--- /dev/null
+++ b/java/dagger/internal/codegen/validation/ExternalBindingGraphConverter.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.validation;
+
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.graph.EndpointPair;
+import com.google.common.graph.ImmutableNetwork;
+import com.google.common.graph.MutableNetwork;
+import com.google.common.graph.Network;
+import com.google.common.graph.NetworkBuilder;
+import com.google.errorprone.annotations.FormatMethod;
+import dagger.model.Binding;
+import dagger.model.BindingGraph;
+import dagger.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.model.BindingGraph.ComponentNode;
+import dagger.model.BindingGraph.DependencyEdge;
+import dagger.model.BindingGraph.Edge;
+import dagger.model.BindingGraph.MaybeBinding;
+import dagger.model.BindingGraph.MissingBinding;
+import dagger.model.BindingGraph.Node;
+import dagger.model.BindingGraph.SubcomponentCreatorBindingEdge;
+import dagger.model.BindingKind;
+import dagger.model.ComponentPath;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.model.Key.MultibindingContributionIdentifier;
+import dagger.model.RequestKind;
+import dagger.model.Scope;
+import dagger.spi.DiagnosticReporter;
+import dagger.spi.model.DaggerAnnotation;
+import dagger.spi.model.DaggerElement;
+import dagger.spi.model.DaggerTypeElement;
+import java.util.Optional;
+import javax.tools.Diagnostic;
+
+/** A Utility class for converting to the {@link BindingGraph} used by external plugins. */
+public final class ExternalBindingGraphConverter {
+ private ExternalBindingGraphConverter() {}
+
+ /** Returns a {@link DiagnosticReporter} from a {@link dagger.spi.DiagnosticReporter}. */
+ public static DiagnosticReporter fromSpiModel(dagger.spi.model.DiagnosticReporter reporter) {
+ return DiagnosticReporterImpl.create(reporter);
+ }
+
+ /** Returns a {@link BindingGraph} from a {@link dagger.spi.model.BindingGraph}. */
+ public static BindingGraph fromSpiModel(dagger.spi.model.BindingGraph graph) {
+ return BindingGraphImpl.create(graph);
+ }
+
+ private static ImmutableNetwork<Node, Edge> fromSpiModel(
+ Network<dagger.spi.model.BindingGraph.Node, dagger.spi.model.BindingGraph.Edge> spiNetwork) {
+ MutableNetwork<Node, Edge> network =
+ NetworkBuilder.directed().allowsParallelEdges(true).allowsSelfLoops(true).build();
+
+ ImmutableMap<dagger.spi.model.BindingGraph.Node, Node> fromSpiNodes =
+ spiNetwork.nodes().stream()
+ .collect(
+ toImmutableMap(
+ spiNode -> spiNode,
+ ExternalBindingGraphConverter::fromSpiModel));
+
+ for (Node node : fromSpiNodes.values()) {
+ network.addNode(node);
+ }
+ for (dagger.spi.model.BindingGraph.Edge edge : spiNetwork.edges()) {
+ EndpointPair<dagger.spi.model.BindingGraph.Node> edgePair = spiNetwork.incidentNodes(edge);
+ network.addEdge(
+ fromSpiNodes.get(edgePair.source()),
+ fromSpiNodes.get(edgePair.target()),
+ fromSpiModel(edge));
+ }
+ return ImmutableNetwork.copyOf(network);
+ }
+
+ private static Node fromSpiModel(dagger.spi.model.BindingGraph.Node node) {
+ if (node instanceof dagger.spi.model.Binding) {
+ return BindingNodeImpl.create((dagger.spi.model.Binding) node);
+ } else if (node instanceof dagger.spi.model.BindingGraph.ComponentNode) {
+ return ComponentNodeImpl.create((dagger.spi.model.BindingGraph.ComponentNode) node);
+ } else if (node instanceof dagger.spi.model.BindingGraph.MissingBinding) {
+ return MissingBindingImpl.create((dagger.spi.model.BindingGraph.MissingBinding) node);
+ } else {
+ throw new IllegalStateException("Unhandled node type: " + node.getClass());
+ }
+ }
+
+ private static Edge fromSpiModel(dagger.spi.model.BindingGraph.Edge edge) {
+ if (edge instanceof dagger.spi.model.BindingGraph.DependencyEdge) {
+ return DependencyEdgeImpl.create((dagger.spi.model.BindingGraph.DependencyEdge) edge);
+ } else if (edge instanceof dagger.spi.model.BindingGraph.ChildFactoryMethodEdge) {
+ return ChildFactoryMethodEdgeImpl.create(
+ (dagger.spi.model.BindingGraph.ChildFactoryMethodEdge) edge);
+ } else if (edge instanceof dagger.spi.model.BindingGraph.SubcomponentCreatorBindingEdge) {
+ return SubcomponentCreatorBindingEdgeImpl.create(
+ (dagger.spi.model.BindingGraph.SubcomponentCreatorBindingEdge) edge);
+ } else {
+ throw new IllegalStateException("Unhandled edge type: " + edge.getClass());
+ }
+ }
+
+ private static MultibindingContributionIdentifier fromSpiModel(
+ dagger.spi.model.Key.MultibindingContributionIdentifier identifier) {
+ return new MultibindingContributionIdentifier(identifier.bindingElement(), identifier.module());
+ }
+
+ private static Key fromSpiModel(dagger.spi.model.Key key) {
+ return Key.builder(key.type().java())
+ .qualifier(key.qualifier().map(DaggerAnnotation::java))
+ .multibindingContributionIdentifier(
+ key.multibindingContributionIdentifier().isPresent()
+ ? Optional.of(fromSpiModel(key.multibindingContributionIdentifier().get()))
+ : Optional.empty())
+ .build();
+ }
+
+ private static BindingKind fromSpiModel(dagger.spi.model.BindingKind bindingKind) {
+ return BindingKind.valueOf(bindingKind.name());
+ }
+
+ private static RequestKind fromSpiModel(dagger.spi.model.RequestKind requestKind) {
+ return RequestKind.valueOf(requestKind.name());
+ }
+
+ private static DependencyRequest fromSpiModel(dagger.spi.model.DependencyRequest request) {
+ DependencyRequest.Builder builder =
+ DependencyRequest.builder()
+ .kind(fromSpiModel(request.kind()))
+ .key(fromSpiModel(request.key()))
+ .isNullable(request.isNullable());
+
+ request.requestElement().ifPresent(e -> builder.requestElement(e.java()));
+ return builder.build();
+ }
+
+ private static Scope fromSpiModel(dagger.spi.model.Scope scope) {
+ return Scope.scope(scope.scopeAnnotation().java());
+ }
+
+ private static ComponentPath fromSpiModel(dagger.spi.model.ComponentPath path) {
+ return ComponentPath.create(
+ path.components().stream().map(DaggerTypeElement::java).collect(toImmutableList()));
+ }
+
+ private static dagger.spi.model.BindingGraph.ComponentNode toSpiModel(
+ ComponentNode componentNode) {
+ return ((ComponentNodeImpl) componentNode).spiDelegate();
+ }
+
+ private static dagger.spi.model.BindingGraph.MaybeBinding toSpiModel(MaybeBinding maybeBinding) {
+ if (maybeBinding instanceof MissingBindingImpl) {
+ return ((MissingBindingImpl) maybeBinding).spiDelegate();
+ } else if (maybeBinding instanceof BindingNodeImpl) {
+ return ((BindingNodeImpl) maybeBinding).spiDelegate();
+ } else {
+ throw new IllegalStateException("Unhandled binding type: " + maybeBinding.getClass());
+ }
+ }
+
+ private static dagger.spi.model.BindingGraph.DependencyEdge toSpiModel(
+ DependencyEdge dependencyEdge) {
+ return ((DependencyEdgeImpl) dependencyEdge).spiDelegate();
+ }
+
+ private static dagger.spi.model.BindingGraph.ChildFactoryMethodEdge toSpiModel(
+ ChildFactoryMethodEdge childFactoryMethodEdge) {
+ return ((ChildFactoryMethodEdgeImpl) childFactoryMethodEdge).spiDelegate();
+ }
+
+ @AutoValue
+ abstract static class ComponentNodeImpl implements ComponentNode {
+ static ComponentNode create(dagger.spi.model.BindingGraph.ComponentNode componentNode) {
+ return new AutoValue_ExternalBindingGraphConverter_ComponentNodeImpl(
+ fromSpiModel(componentNode.componentPath()),
+ componentNode.isSubcomponent(),
+ componentNode.isRealComponent(),
+ componentNode.entryPoints().stream()
+ .map(ExternalBindingGraphConverter::fromSpiModel)
+ .collect(toImmutableSet()),
+ componentNode.scopes().stream()
+ .map(ExternalBindingGraphConverter::fromSpiModel)
+ .collect(toImmutableSet()),
+ componentNode);
+ }
+
+ abstract dagger.spi.model.BindingGraph.ComponentNode spiDelegate();
+
+ @Override
+ public final String toString() {
+ return spiDelegate().toString();
+ }
+ }
+
+ @AutoValue
+ abstract static class BindingNodeImpl implements Binding {
+ static Binding create(dagger.spi.model.Binding binding) {
+ return new AutoValue_ExternalBindingGraphConverter_BindingNodeImpl(
+ fromSpiModel(binding.key()),
+ fromSpiModel(binding.componentPath()),
+ binding.dependencies().stream()
+ .map(ExternalBindingGraphConverter::fromSpiModel)
+ .collect(toImmutableSet()),
+ binding.bindingElement().map(DaggerElement::java),
+ binding.contributingModule().map(DaggerTypeElement::java),
+ binding.requiresModuleInstance(),
+ binding.scope().map(ExternalBindingGraphConverter::fromSpiModel),
+ binding.isNullable(),
+ binding.isProduction(),
+ fromSpiModel(binding.kind()),
+ binding);
+ }
+
+ abstract dagger.spi.model.Binding spiDelegate();
+
+ @Override
+ public final String toString() {
+ return spiDelegate().toString();
+ }
+ }
+
+ @AutoValue
+ abstract static class MissingBindingImpl extends MissingBinding {
+ static MissingBinding create(dagger.spi.model.BindingGraph.MissingBinding missingBinding) {
+ return new AutoValue_ExternalBindingGraphConverter_MissingBindingImpl(
+ fromSpiModel(missingBinding.componentPath()),
+ fromSpiModel(missingBinding.key()),
+ missingBinding);
+ }
+
+ abstract dagger.spi.model.BindingGraph.MissingBinding spiDelegate();
+
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ @Override
+ public abstract boolean equals(Object o);
+ }
+
+ @AutoValue
+ abstract static class DependencyEdgeImpl implements DependencyEdge {
+ static DependencyEdge create(dagger.spi.model.BindingGraph.DependencyEdge dependencyEdge) {
+ return new AutoValue_ExternalBindingGraphConverter_DependencyEdgeImpl(
+ fromSpiModel(dependencyEdge.dependencyRequest()),
+ dependencyEdge.isEntryPoint(),
+ dependencyEdge);
+ }
+
+ abstract dagger.spi.model.BindingGraph.DependencyEdge spiDelegate();
+
+ @Override
+ public final String toString() {
+ return spiDelegate().toString();
+ }
+ }
+
+ @AutoValue
+ abstract static class ChildFactoryMethodEdgeImpl implements ChildFactoryMethodEdge {
+ static ChildFactoryMethodEdge create(
+ dagger.spi.model.BindingGraph.ChildFactoryMethodEdge childFactoryMethodEdge) {
+ return new AutoValue_ExternalBindingGraphConverter_ChildFactoryMethodEdgeImpl(
+ childFactoryMethodEdge.factoryMethod().java(), childFactoryMethodEdge);
+ }
+
+ abstract dagger.spi.model.BindingGraph.ChildFactoryMethodEdge spiDelegate();
+
+ @Override
+ public final String toString() {
+ return spiDelegate().toString();
+ }
+ }
+
+ @AutoValue
+ abstract static class SubcomponentCreatorBindingEdgeImpl
+ implements SubcomponentCreatorBindingEdge {
+ static SubcomponentCreatorBindingEdge create(
+ dagger.spi.model.BindingGraph.SubcomponentCreatorBindingEdge
+ subcomponentCreatorBindingEdge) {
+ return new AutoValue_ExternalBindingGraphConverter_SubcomponentCreatorBindingEdgeImpl(
+ subcomponentCreatorBindingEdge.declaringModules().stream()
+ .map(DaggerTypeElement::java)
+ .collect(toImmutableSet()),
+ subcomponentCreatorBindingEdge);
+ }
+
+ abstract dagger.spi.model.BindingGraph.SubcomponentCreatorBindingEdge spiDelegate();
+
+ @Override
+ public final String toString() {
+ return spiDelegate().toString();
+ }
+ }
+
+ @AutoValue
+ abstract static class BindingGraphImpl extends BindingGraph {
+ static BindingGraph create(dagger.spi.model.BindingGraph bindingGraph) {
+ BindingGraphImpl bindingGraphImpl =
+ new AutoValue_ExternalBindingGraphConverter_BindingGraphImpl(
+ fromSpiModel(bindingGraph.network()), bindingGraph.isFullBindingGraph());
+
+ bindingGraphImpl.componentNodesByPath =
+ bindingGraphImpl.componentNodes().stream()
+ .collect(toImmutableMap(ComponentNode::componentPath, node -> node));
+
+ return bindingGraphImpl;
+ }
+
+ private ImmutableMap<ComponentPath, ComponentNode> componentNodesByPath;
+
+ // This overrides dagger.model.BindingGraph with a more efficient implementation.
+ @Override
+ public Optional<ComponentNode> componentNode(ComponentPath componentPath) {
+ return componentNodesByPath.containsKey(componentPath)
+ ? Optional.of(componentNodesByPath.get(componentPath))
+ : Optional.empty();
+ }
+
+ // This overrides dagger.model.BindingGraph to memoize the output.
+ @Override
+ @Memoized
+ public ImmutableSetMultimap<Class<? extends Node>, ? extends Node> nodesByClass() {
+ return super.nodesByClass();
+ }
+ }
+
+ private static final class DiagnosticReporterImpl implements DiagnosticReporter {
+ static DiagnosticReporterImpl create(dagger.spi.model.DiagnosticReporter reporter) {
+ return new DiagnosticReporterImpl(reporter);
+ }
+
+ private final dagger.spi.model.DiagnosticReporter delegate;
+
+ DiagnosticReporterImpl(dagger.spi.model.DiagnosticReporter delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void reportComponent(
+ Diagnostic.Kind diagnosticKind, ComponentNode componentNode, String message) {
+ delegate.reportComponent(diagnosticKind, toSpiModel(componentNode), message);
+ }
+
+ @Override
+ @FormatMethod
+ public void reportComponent(
+ Diagnostic.Kind diagnosticKind,
+ ComponentNode componentNode,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs) {
+ delegate.reportComponent(
+ diagnosticKind, toSpiModel(componentNode), messageFormat, firstArg, moreArgs);
+ }
+
+ @Override
+ public void reportBinding(
+ Diagnostic.Kind diagnosticKind, MaybeBinding binding, String message) {
+ delegate.reportBinding(diagnosticKind, toSpiModel(binding), message);
+ }
+
+ @Override
+ @FormatMethod
+ public void reportBinding(
+ Diagnostic.Kind diagnosticKind,
+ MaybeBinding binding,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs) {
+ delegate.reportBinding(
+ diagnosticKind, toSpiModel(binding), messageFormat, firstArg, moreArgs);
+ }
+
+ @Override
+ public void reportDependency(
+ Diagnostic.Kind diagnosticKind, DependencyEdge dependencyEdge, String message) {
+ delegate.reportDependency(diagnosticKind, toSpiModel(dependencyEdge), message);
+ }
+
+ @Override
+ @FormatMethod
+ public void reportDependency(
+ Diagnostic.Kind diagnosticKind,
+ DependencyEdge dependencyEdge,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs) {
+ delegate.reportDependency(
+ diagnosticKind, toSpiModel(dependencyEdge), messageFormat, firstArg, moreArgs);
+ }
+
+ @Override
+ public void reportSubcomponentFactoryMethod(
+ Diagnostic.Kind diagnosticKind,
+ ChildFactoryMethodEdge childFactoryMethodEdge,
+ String message) {
+ delegate.reportSubcomponentFactoryMethod(
+ diagnosticKind, toSpiModel(childFactoryMethodEdge), message);
+ }
+
+ @Override
+ @FormatMethod
+ public void reportSubcomponentFactoryMethod(
+ Diagnostic.Kind diagnosticKind,
+ ChildFactoryMethodEdge childFactoryMethodEdge,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs) {
+ delegate.reportSubcomponentFactoryMethod(
+ diagnosticKind, toSpiModel(childFactoryMethodEdge), messageFormat, firstArg, moreArgs);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/validation/BindingGraphPlugins.java b/java/dagger/internal/codegen/validation/ExternalBindingGraphPlugins.java
index 16ef78f79..9021790be 100644
--- a/java/dagger/internal/codegen/validation/BindingGraphPlugins.java
+++ b/java/dagger/internal/codegen/validation/ExternalBindingGraphPlugins.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Dagger Authors.
+ * Copyright (C) 2021 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,36 +17,42 @@
package dagger.internal.codegen.validation;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static javax.tools.Diagnostic.Kind.ERROR;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.compat.XConverters;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
import dagger.internal.codegen.compileroption.ProcessingOptions;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.validation.DiagnosticReporterFactory.DiagnosticReporterImpl;
+import dagger.model.BindingGraph;
import dagger.spi.BindingGraphPlugin;
+import dagger.spi.DiagnosticReporter;
import java.util.Map;
import java.util.Set;
-import javax.annotation.processing.Filer;
import javax.inject.Inject;
/** Initializes {@link BindingGraphPlugin}s. */
-public final class BindingGraphPlugins {
+public final class ExternalBindingGraphPlugins {
private final ImmutableSet<BindingGraphPlugin> plugins;
- private final Filer filer;
+ private final DiagnosticReporterFactory diagnosticReporterFactory;
+ private final XFiler filer;
private final DaggerTypes types;
private final DaggerElements elements;
private final Map<String, String> processingOptions;
@Inject
- BindingGraphPlugins(
- @Validation ImmutableSet<BindingGraphPlugin> validationPlugins,
- ImmutableSet<BindingGraphPlugin> externalPlugins,
- Filer filer,
+ ExternalBindingGraphPlugins(
+ ImmutableSet<BindingGraphPlugin> plugins,
+ DiagnosticReporterFactory diagnosticReporterFactory,
+ XFiler filer,
DaggerTypes types,
DaggerElements elements,
@ProcessingOptions Map<String, String> processingOptions) {
- this.plugins = Sets.union(validationPlugins, externalPlugins).immutableCopy();
+ this.plugins = plugins;
+ this.diagnosticReporterFactory = diagnosticReporterFactory;
this.filer = filer;
this.types = types;
this.elements = elements;
@@ -67,7 +73,7 @@ public final class BindingGraphPlugins {
}
private void initializePlugin(BindingGraphPlugin plugin) {
- plugin.initFiler(filer);
+ plugin.initFiler(XConverters.toJavac(filer));
plugin.initTypes(types);
plugin.initElements(elements);
Set<String> supportedOptions = plugin.supportedOptions();
@@ -75,4 +81,21 @@ public final class BindingGraphPlugins {
plugin.initOptions(Maps.filterKeys(processingOptions, supportedOptions::contains));
}
}
+
+ /** Returns {@code false} if any of the plugins reported an error. */
+ boolean visit(dagger.spi.model.BindingGraph spiGraph) {
+ BindingGraph graph = ExternalBindingGraphConverter.fromSpiModel(spiGraph);
+ boolean isClean = true;
+ for (BindingGraphPlugin plugin : plugins) {
+ DiagnosticReporterImpl spiReporter =
+ diagnosticReporterFactory.reporter(
+ spiGraph, plugin.pluginName(), /* reportErrorsAsWarnings= */ false);
+ DiagnosticReporter reporter = ExternalBindingGraphConverter.fromSpiModel(spiReporter);
+ plugin.visitGraph(graph, reporter);
+ if (spiReporter.reportedDiagnosticKinds().contains(ERROR)) {
+ isClean = false;
+ }
+ }
+ return isClean;
+ }
}
diff --git a/java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java b/java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java
index 9787f4f37..7aa95ae00 100644
--- a/java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java
+++ b/java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java
@@ -16,6 +16,9 @@
package dagger.internal.codegen.validation;
+import static androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static androidx.room.compiler.processing.compat.XConverters.toXProcessing;
+import static com.google.auto.common.MoreTypes.asTypeElement;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
@@ -24,17 +27,23 @@ import static dagger.internal.codegen.base.Keys.isValidMembersInjectionKey;
import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedInjectedConstructors;
import static dagger.internal.codegen.binding.InjectionAnnotations.injectedConstructors;
import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
+import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
import static dagger.internal.codegen.langmodel.DaggerTypes.unwrapType;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+import static javax.lang.model.type.TypeKind.DECLARED;
+
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XFieldElement;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import com.squareup.javapoet.ClassName;
import dagger.Component;
-import dagger.MembersInjector;
import dagger.Provides;
import dagger.internal.codegen.base.SourceFileGenerationException;
import dagger.internal.codegen.base.SourceFileGenerator;
@@ -45,20 +54,18 @@ import dagger.internal.codegen.binding.KeyFactory;
import dagger.internal.codegen.binding.MembersInjectionBinding;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
+import dagger.spi.model.Key;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
-import javax.annotation.processing.Messager;
+import java.util.stream.Stream;
import javax.inject.Inject;
-import javax.inject.Provider;
import javax.inject.Singleton;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic.Kind;
@@ -71,9 +78,10 @@ import javax.tools.Diagnostic.Kind;
*/
@Singleton
final class InjectBindingRegistryImpl implements InjectBindingRegistry {
+ private final XProcessingEnv processingEnv;
private final DaggerElements elements;
private final DaggerTypes types;
- private final Messager messager;
+ private final XMessager messager;
private final InjectValidator injectValidator;
private final InjectValidator injectValidatorWhenGeneratingCode;
private final KeyFactory keyFactory;
@@ -81,12 +89,12 @@ final class InjectBindingRegistryImpl implements InjectBindingRegistry {
private final CompilerOptions compilerOptions;
final class BindingsCollection<B extends Binding> {
- private final Class<?> factoryClass;
+ private final ClassName factoryClass;
private final Map<Key, B> bindingsByKey = Maps.newLinkedHashMap();
private final Deque<B> bindingsRequiringGeneration = new ArrayDeque<>();
private final Set<Key> materializedBindingKeys = Sets.newLinkedHashSet();
- BindingsCollection(Class<?> factoryClass) {
+ BindingsCollection(ClassName factoryClass) {
this.factoryClass = factoryClass;
}
@@ -95,7 +103,11 @@ final class InjectBindingRegistryImpl implements InjectBindingRegistry {
binding != null;
binding = bindingsRequiringGeneration.poll()) {
checkState(!binding.unresolved().isPresent());
- if (injectValidatorWhenGeneratingCode.isValidType(binding.key().type())) {
+ TypeMirror type = binding.key().type().java();
+ if (!type.getKind().equals(DECLARED)
+ || injectValidatorWhenGeneratingCode
+ .validate(toXProcessing(asTypeElement(type), processingEnv))
+ .isClean()) {
generator.generate(binding);
}
materializedBindingKeys.add(binding.key());
@@ -134,8 +146,8 @@ final class InjectBindingRegistryImpl implements InjectBindingRegistry {
String.format(
"Generating a %s for %s. "
+ "Prefer to run the dagger processor over that class instead.",
- factoryClass.getSimpleName(),
- types.erasure(binding.key().type()))); // erasure to strip <T> from msgs.
+ factoryClass.simpleName(),
+ types.erasure(binding.key().type().java()))); // erasure to strip <T> from msgs.
}
}
}
@@ -153,7 +165,7 @@ final class InjectBindingRegistryImpl implements InjectBindingRegistry {
// We only cache resolved bindings or unresolved bindings w/o type arguments.
// Unresolved bindings w/ type arguments aren't valid for the object graph.
if (binding.unresolved().isPresent()
- || binding.bindingTypeElement().get().getTypeParameters().isEmpty()) {
+ || binding.bindingTypeElement().get().getType().getTypeArguments().isEmpty()) {
Key key = binding.key();
Binding previousValue = bindingsByKey.put(key, binding);
checkState(previousValue == null || binding.equals(previousValue),
@@ -164,19 +176,21 @@ final class InjectBindingRegistryImpl implements InjectBindingRegistry {
}
private final BindingsCollection<ProvisionBinding> provisionBindings =
- new BindingsCollection<>(Provider.class);
+ new BindingsCollection<>(TypeNames.PROVIDER);
private final BindingsCollection<MembersInjectionBinding> membersInjectionBindings =
- new BindingsCollection<>(MembersInjector.class);
+ new BindingsCollection<>(TypeNames.MEMBERS_INJECTOR);
@Inject
InjectBindingRegistryImpl(
+ XProcessingEnv processingEnv,
DaggerElements elements,
DaggerTypes types,
- Messager messager,
+ XMessager messager,
InjectValidator injectValidator,
KeyFactory keyFactory,
BindingFactory bindingFactory,
CompilerOptions compilerOptions) {
+ this.processingEnv = processingEnv;
this.elements = elements;
this.types = types;
this.messager = messager;
@@ -187,7 +201,6 @@ final class InjectBindingRegistryImpl implements InjectBindingRegistry {
this.compilerOptions = compilerOptions;
}
-
// TODO(dpb): make the SourceFileGenerators fields so they don't have to be passed in
@Override
public void generateSourcesForRequiredBindings(
@@ -234,29 +247,32 @@ final class InjectBindingRegistryImpl implements InjectBindingRegistry {
}
@Override
- public Optional<ProvisionBinding> tryRegisterConstructor(ExecutableElement constructorElement) {
+ public Optional<ProvisionBinding> tryRegisterInjectConstructor(
+ XConstructorElement constructorElement) {
return tryRegisterConstructor(constructorElement, Optional.empty(), false);
}
@CanIgnoreReturnValue
private Optional<ProvisionBinding> tryRegisterConstructor(
- ExecutableElement constructorElement,
- Optional<TypeMirror> resolvedType,
+ XConstructorElement constructorElement,
+ Optional<XType> resolvedType,
boolean warnIfNotAlreadyGenerated) {
- TypeElement typeElement = MoreElements.asType(constructorElement.getEnclosingElement());
- DeclaredType type = MoreTypes.asDeclared(typeElement.asType());
- Key key = keyFactory.forInjectConstructorWithResolvedType(type);
- ProvisionBinding cachedBinding = provisionBindings.getBinding(key);
- if (cachedBinding != null) {
- return Optional.of(cachedBinding);
- }
+ XTypeElement typeElement = constructorElement.getEnclosingElement();
- ValidationReport<TypeElement> report = injectValidator.validateConstructor(constructorElement);
+ // Validating here shouldn't have a performance penalty because the validator caches its reports
+ ValidationReport report = injectValidator.validate(typeElement);
report.printMessagesTo(messager);
if (!report.isClean()) {
return Optional.empty();
}
+ XType type = typeElement.getType();
+ Key key = keyFactory.forInjectConstructorWithResolvedType(type);
+ ProvisionBinding cachedBinding = provisionBindings.getBinding(key);
+ if (cachedBinding != null) {
+ return Optional.of(cachedBinding);
+ }
+
ProvisionBinding binding = bindingFactory.injectionBinding(constructorElement, resolvedType);
registerBinding(binding, warnIfNotAlreadyGenerated);
if (!binding.injectionSites().isEmpty()) {
@@ -266,29 +282,50 @@ final class InjectBindingRegistryImpl implements InjectBindingRegistry {
}
@Override
- public Optional<MembersInjectionBinding> tryRegisterMembersInjectedType(TypeElement typeElement) {
- return tryRegisterMembersInjectedType(typeElement, Optional.empty(), false);
+ public Optional<MembersInjectionBinding> tryRegisterInjectField(XFieldElement fieldElement) {
+ // TODO(b/204116636): Add a test for this once we're able to test kotlin sources.
+ // TODO(b/204208307): Add validation for KAPT to test if this came from a top-level field.
+ if (!isTypeElement(fieldElement.getEnclosingElement())) {
+ messager.printMessage(
+ Kind.ERROR,
+ "@Inject fields must be enclosed in a type.",
+ fieldElement);
+ }
+ return tryRegisterMembersInjectedType(
+ asTypeElement(fieldElement.getEnclosingElement()), Optional.empty(), false);
+ }
+
+ @Override
+ public Optional<MembersInjectionBinding> tryRegisterInjectMethod(XMethodElement methodElement) {
+ // TODO(b/204116636): Add a test for this once we're able to test kotlin sources.
+ // TODO(b/204208307): Add validation for KAPT to test if this came from a top-level method.
+ if (!isTypeElement(methodElement.getEnclosingElement())) {
+ messager.printMessage(
+ Kind.ERROR,
+ "@Inject methods must be enclosed in a type.",
+ methodElement);
+ }
+ return tryRegisterMembersInjectedType(
+ asTypeElement(methodElement.getEnclosingElement()), Optional.empty(), false);
}
@CanIgnoreReturnValue
private Optional<MembersInjectionBinding> tryRegisterMembersInjectedType(
- TypeElement typeElement,
- Optional<TypeMirror> resolvedType,
- boolean warnIfNotAlreadyGenerated) {
- DeclaredType type = MoreTypes.asDeclared(typeElement.asType());
+ XTypeElement typeElement, Optional<XType> resolvedType, boolean warnIfNotAlreadyGenerated) {
+ // Validating here shouldn't have a performance penalty because the validator caches its reports
+ ValidationReport report = injectValidator.validateForMembersInjection(typeElement);
+ report.printMessagesTo(messager);
+ if (!report.isClean()) {
+ return Optional.empty();
+ }
+
+ XType type = typeElement.getType();
Key key = keyFactory.forInjectConstructorWithResolvedType(type);
MembersInjectionBinding cachedBinding = membersInjectionBindings.getBinding(key);
if (cachedBinding != null) {
return Optional.of(cachedBinding);
}
- ValidationReport<TypeElement> report =
- injectValidator.validateMembersInjectionType(typeElement);
- report.printMessagesTo(messager);
- if (!report.isClean()) {
- return Optional.empty();
- }
-
MembersInjectionBinding binding = bindingFactory.membersInjectionBinding(type, resolvedType);
registerBinding(binding, warnIfNotAlreadyGenerated);
for (Optional<DeclaredType> supertype = types.nonObjectSuperclass(type);
@@ -303,7 +340,7 @@ final class InjectBindingRegistryImpl implements InjectBindingRegistry {
@Override
public Optional<ProvisionBinding> getOrFindProvisionBinding(Key key) {
checkNotNull(key);
- if (!isValidImplicitProvisionKey(key, types)) {
+ if (!isValidImplicitProvisionKey(key)) {
return Optional.empty();
}
ProvisionBinding binding = provisionBindings.getBinding(key);
@@ -311,24 +348,21 @@ final class InjectBindingRegistryImpl implements InjectBindingRegistry {
return Optional.of(binding);
}
- // ok, let's see if we can find an @Inject constructor
- TypeElement element = MoreElements.asType(types.asElement(key.type()));
- ImmutableSet<ExecutableElement> injectConstructors =
- ImmutableSet.<ExecutableElement>builder()
- .addAll(injectedConstructors(element))
- .addAll(assistedInjectedConstructors(element))
- .build();
- switch (injectConstructors.size()) {
- case 0:
- // No constructor found.
- return Optional.empty();
- case 1:
- return tryRegisterConstructor(
- Iterables.getOnlyElement(injectConstructors), Optional.of(key.type()), true);
- default:
- throw new IllegalStateException("Found multiple @Inject constructors: "
- + injectConstructors);
+ XType type = key.type().xprocessing();
+ XTypeElement element = type.getTypeElement();
+
+ ValidationReport report = injectValidator.validate(element);
+ report.printMessagesTo(messager);
+ if (!report.isClean()) {
+ return Optional.empty();
}
+
+ return Stream.concat(
+ injectedConstructors(element).stream(),
+ assistedInjectedConstructors(element).stream())
+ // We're guaranteed that there's at most 1 @Inject constructors from above validation.
+ .collect(toOptional())
+ .flatMap(constructor -> tryRegisterConstructor(constructor, Optional.of(type), true));
}
@CanIgnoreReturnValue
@@ -341,10 +375,8 @@ final class InjectBindingRegistryImpl implements InjectBindingRegistry {
if (binding != null) {
return Optional.of(binding);
}
- Optional<MembersInjectionBinding> newBinding =
- tryRegisterMembersInjectedType(
- MoreTypes.asTypeElement(key.type()), Optional.of(key.type()), true);
- return newBinding;
+ return tryRegisterMembersInjectedType(
+ key.type().xprocessing().getTypeElement(), Optional.of(key.type().xprocessing()), true);
}
@Override
@@ -352,7 +384,7 @@ final class InjectBindingRegistryImpl implements InjectBindingRegistry {
if (!isValidMembersInjectionKey(key)) {
return Optional.empty();
}
- Key membersInjectionKey = keyFactory.forMembersInjectedType(unwrapType(key.type()));
+ Key membersInjectionKey = keyFactory.forMembersInjectedType(unwrapType(key.type().java()));
return getOrFindMembersInjectionBinding(membersInjectionKey)
.map(binding -> bindingFactory.membersInjectorBinding(key, binding));
}
diff --git a/java/dagger/internal/codegen/validation/InjectValidator.java b/java/dagger/internal/codegen/validation/InjectValidator.java
index 240f9d099..4758d32dc 100644
--- a/java/dagger/internal/codegen/validation/InjectValidator.java
+++ b/java/dagger/internal/codegen/validation/InjectValidator.java
@@ -16,45 +16,43 @@
package dagger.internal.codegen.validation;
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static dagger.internal.codegen.base.Scopes.scopesOf;
+import static androidx.room.compiler.processing.compat.XConverters.toXProcessing;
+import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedInjectedConstructors;
import static dagger.internal.codegen.binding.InjectionAnnotations.injectedConstructors;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.STATIC;
-import static javax.lang.model.type.TypeKind.DECLARED;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
+import static dagger.internal.codegen.binding.SourceFiles.factoryNameForElement;
+import static dagger.internal.codegen.binding.SourceFiles.membersInjectorNameForType;
+import static dagger.internal.codegen.xprocessing.XElements.closestEnclosingTypeElement;
+import static dagger.internal.codegen.xprocessing.XElements.getAnyAnnotation;
+import static dagger.internal.codegen.xprocessing.XMethodElements.hasTypeParameters;
+
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XExecutableParameterElement;
+import androidx.room.compiler.processing.XFieldElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.XVariableElement;
import com.google.common.collect.ImmutableSet;
-import dagger.assisted.AssistedInject;
+import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.base.ClearableCache;
+import dagger.internal.codegen.base.DaggerSuperficialValidation;
import dagger.internal.codegen.binding.InjectionAnnotations;
import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.Accessibility;
-import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Scope;
+import dagger.internal.codegen.xprocessing.XAnnotations;
+import dagger.spi.model.Scope;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
-import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementFilter;
import javax.tools.Diagnostic;
import javax.tools.Diagnostic.Kind;
@@ -64,53 +62,55 @@ import javax.tools.Diagnostic.Kind;
*/
@Singleton
public final class InjectValidator implements ClearableCache {
+ private final XProcessingEnv processingEnv;
private final DaggerTypes types;
- private final DaggerElements elements;
private final CompilerOptions compilerOptions;
private final DependencyRequestValidator dependencyRequestValidator;
private final Optional<Diagnostic.Kind> privateAndStaticInjectionDiagnosticKind;
private final InjectionAnnotations injectionAnnotations;
- private final KotlinMetadataUtil metadataUtil;
- private final Map<ExecutableElement, ValidationReport<TypeElement>> reports = new HashMap<>();
+ private final DaggerSuperficialValidation superficialValidation;
+ private final Map<XTypeElement, ValidationReport> provisionReports = new HashMap<>();
+ private final Map<XTypeElement, ValidationReport> membersInjectionReports = new HashMap<>();
@Inject
InjectValidator(
+ XProcessingEnv processingEnv,
DaggerTypes types,
- DaggerElements elements,
DependencyRequestValidator dependencyRequestValidator,
CompilerOptions compilerOptions,
InjectionAnnotations injectionAnnotations,
- KotlinMetadataUtil metadataUtil) {
+ DaggerSuperficialValidation superficialValidation) {
this(
+ processingEnv,
types,
- elements,
compilerOptions,
dependencyRequestValidator,
Optional.empty(),
injectionAnnotations,
- metadataUtil);
+ superficialValidation);
}
private InjectValidator(
+ XProcessingEnv processingEnv,
DaggerTypes types,
- DaggerElements elements,
CompilerOptions compilerOptions,
DependencyRequestValidator dependencyRequestValidator,
Optional<Kind> privateAndStaticInjectionDiagnosticKind,
InjectionAnnotations injectionAnnotations,
- KotlinMetadataUtil metadataUtil) {
+ DaggerSuperficialValidation superficialValidation) {
+ this.processingEnv = processingEnv;
this.types = types;
- this.elements = elements;
this.compilerOptions = compilerOptions;
this.dependencyRequestValidator = dependencyRequestValidator;
this.privateAndStaticInjectionDiagnosticKind = privateAndStaticInjectionDiagnosticKind;
this.injectionAnnotations = injectionAnnotations;
- this.metadataUtil = metadataUtil;
+ this.superficialValidation = superficialValidation;
}
@Override
public void clearCache() {
- reports.clear();
+ provisionReports.clear();
+ membersInjectionReports.clear();
}
/**
@@ -122,60 +122,104 @@ public final class InjectValidator implements ClearableCache {
return compilerOptions.ignorePrivateAndStaticInjectionForComponent()
? this
: new InjectValidator(
+ processingEnv,
types,
- elements,
compilerOptions,
dependencyRequestValidator,
Optional.of(Diagnostic.Kind.ERROR),
injectionAnnotations,
- metadataUtil);
+ superficialValidation);
}
- public ValidationReport<TypeElement> validateConstructor(ExecutableElement constructorElement) {
- return reentrantComputeIfAbsent(reports, constructorElement, this::validateConstructorUncached);
+ public ValidationReport validate(XTypeElement typeElement) {
+ return reentrantComputeIfAbsent(provisionReports, typeElement, this::validateUncached);
}
- private ValidationReport<TypeElement> validateConstructorUncached(
- ExecutableElement constructorElement) {
- ValidationReport.Builder<TypeElement> builder =
- ValidationReport.about(asType(constructorElement.getEnclosingElement()));
+ private ValidationReport validateUncached(XTypeElement typeElement) {
+ ValidationReport.Builder builder = ValidationReport.about(typeElement);
+ builder.addSubreport(validateForMembersInjectionInternal(typeElement));
- if (isAnnotationPresent(constructorElement, Inject.class)
- && isAnnotationPresent(constructorElement, AssistedInject.class)) {
+ ImmutableSet<XConstructorElement> injectConstructors =
+ ImmutableSet.<XConstructorElement>builder()
+ .addAll(injectedConstructors(typeElement))
+ .addAll(assistedInjectedConstructors(typeElement))
+ .build();
+
+ switch (injectConstructors.size()) {
+ case 0:
+ break; // Nothing to validate.
+ case 1:
+ builder.addSubreport(validateConstructor(getOnlyElement(injectConstructors)));
+ break;
+ default:
+ builder.addError(
+ String.format(
+ "Type %s may only contain one injected constructor. Found: %s",
+ typeElement,
+ injectConstructors),
+ typeElement);
+ }
+
+ return builder.build();
+ }
+
+ private ValidationReport validateConstructor(XConstructorElement constructorElement) {
+ superficialValidation.validateTypeOf(constructorElement);
+ ValidationReport.Builder builder =
+ ValidationReport.about(constructorElement.getEnclosingElement());
+
+ if (InjectionAnnotations.hasInjectAnnotation(constructorElement)
+ && constructorElement.hasAnnotation(TypeNames.ASSISTED_INJECT)) {
builder.addError("Constructors cannot be annotated with both @Inject and @AssistedInject");
}
- Class<?> injectAnnotation =
- isAnnotationPresent(constructorElement, Inject.class) ? Inject.class : AssistedInject.class;
+ ClassName injectAnnotation =
+ getAnyAnnotation(
+ constructorElement,
+ TypeNames.INJECT,
+ TypeNames.INJECT_JAVAX,
+ TypeNames.ASSISTED_INJECT).map(XAnnotations::getClassName).get();
- if (constructorElement.getModifiers().contains(PRIVATE)) {
+ if (constructorElement.isPrivate()) {
builder.addError(
"Dagger does not support injection into private constructors", constructorElement);
}
- for (AnnotationMirror qualifier : injectionAnnotations.getQualifiers(constructorElement)) {
- builder.addError(
- String.format(
- "@Qualifier annotations are not allowed on @%s constructors",
- injectAnnotation.getSimpleName()),
- constructorElement,
- qualifier);
- }
+ // If this type has already been processed in a previous round or compilation unit then there
+ // is no reason to recheck for invalid scope annotations since it's already been checked.
+ // This allows us to skip superficial validation of constructor annotations in subsequent
+ // compilations where the annotation types may no longer be on the classpath.
+ if (!processedInPreviousRoundOrCompilationUnit(constructorElement)) {
+ superficialValidation.validateAnnotationsOf(constructorElement);
+ for (XAnnotation qualifier : injectionAnnotations.getQualifiers(constructorElement)) {
+ builder.addError(
+ String.format(
+ "@Qualifier annotations are not allowed on @%s constructors",
+ injectAnnotation.simpleName()),
+ constructorElement,
+ qualifier);
+ }
- String scopeErrorMsg =
- String.format(
- "@Scope annotations are not allowed on @%s constructors",
- injectAnnotation.getSimpleName());
+ String scopeErrorMsg =
+ String.format(
+ "@Scope annotations are not allowed on @%s constructors",
+ injectAnnotation.simpleName());
- if (injectAnnotation == Inject.class) {
- scopeErrorMsg += "; annotate the class instead";
- }
+ if (injectAnnotation.equals(TypeNames.INJECT)
+ || injectAnnotation.equals(TypeNames.INJECT_JAVAX)) {
+ scopeErrorMsg += "; annotate the class instead";
+ }
- for (Scope scope : scopesOf(constructorElement)) {
- builder.addError(scopeErrorMsg, constructorElement, scope.scopeAnnotation());
+ for (Scope scope : injectionAnnotations.getScopes(constructorElement)) {
+ builder.addError(
+ scopeErrorMsg,
+ constructorElement,
+ toXProcessing(scope.scopeAnnotation().java(), processingEnv));
+ }
}
- for (VariableElement parameter : constructorElement.getParameters()) {
+ for (XExecutableParameterElement parameter : constructorElement.getParameters()) {
+ superficialValidation.validateTypeOf(parameter);
validateDependencyRequest(builder, parameter);
}
@@ -183,81 +227,68 @@ public final class InjectValidator implements ClearableCache {
builder.addItem(
String.format(
"Dagger does not support checked exceptions on @%s constructors",
- injectAnnotation.getSimpleName()),
+ injectAnnotation.simpleName()),
privateMemberDiagnosticKind(),
constructorElement);
}
checkInjectIntoPrivateClass(constructorElement, builder);
- TypeElement enclosingElement =
- MoreElements.asType(constructorElement.getEnclosingElement());
-
- Set<Modifier> typeModifiers = enclosingElement.getModifiers();
- if (typeModifiers.contains(ABSTRACT)) {
+ XTypeElement enclosingElement = constructorElement.getEnclosingElement();
+ if (enclosingElement.isAbstract()) {
builder.addError(
String.format(
"@%s is nonsense on the constructor of an abstract class",
- injectAnnotation.getSimpleName()),
+ injectAnnotation.simpleName()),
constructorElement);
}
- if (enclosingElement.getNestingKind().isNested()
- && !typeModifiers.contains(STATIC)) {
+ if (enclosingElement.isNested() && !enclosingElement.isStatic()) {
builder.addError(
String.format(
"@%s constructors are invalid on inner classes. "
+ "Did you mean to make the class static?",
- injectAnnotation.getSimpleName()),
+ injectAnnotation.simpleName()),
constructorElement);
}
- // This is computationally expensive, but probably preferable to a giant index
- ImmutableSet<ExecutableElement> injectConstructors =
- ImmutableSet.<ExecutableElement>builder()
- .addAll(injectedConstructors(enclosingElement))
- .addAll(assistedInjectedConstructors(enclosingElement))
- .build();
-
- if (injectConstructors.size() > 1) {
- builder.addError("Types may only contain one injected constructor", constructorElement);
- }
-
- ImmutableSet<Scope> scopes = scopesOf(enclosingElement);
- if (injectAnnotation == AssistedInject.class) {
+ // Note: superficial validation of the annotations is done as part of getting the scopes.
+ ImmutableSet<Scope> scopes =
+ injectionAnnotations.getScopes(constructorElement.getEnclosingElement());
+ if (injectAnnotation.equals(TypeNames.ASSISTED_INJECT)) {
for (Scope scope : scopes) {
builder.addError(
"A type with an @AssistedInject-annotated constructor cannot be scoped",
enclosingElement,
- scope.scopeAnnotation());
+ toXProcessing(scope.scopeAnnotation().java(), processingEnv));
}
} else if (scopes.size() > 1) {
for (Scope scope : scopes) {
builder.addError(
"A single binding may not declare more than one @Scope",
enclosingElement,
- scope.scopeAnnotation());
+ toXProcessing(scope.scopeAnnotation().java(), processingEnv));
}
}
return builder.build();
}
- private ValidationReport<VariableElement> validateField(VariableElement fieldElement) {
- ValidationReport.Builder<VariableElement> builder = ValidationReport.about(fieldElement);
- Set<Modifier> modifiers = fieldElement.getModifiers();
- if (modifiers.contains(FINAL)) {
+ private ValidationReport validateField(XFieldElement fieldElement) {
+ superficialValidation.validateTypeOf(fieldElement);
+ ValidationReport.Builder builder = ValidationReport.about(fieldElement);
+ if (fieldElement.isFinal()) {
builder.addError("@Inject fields may not be final", fieldElement);
}
- if (modifiers.contains(PRIVATE)) {
+ if (fieldElement.isPrivate()) {
builder.addItem(
"Dagger does not support injection into private fields",
privateMemberDiagnosticKind(),
fieldElement);
}
- if (modifiers.contains(STATIC)) {
+ if (fieldElement.isStatic()) {
builder.addItem(
"Dagger does not support injection into static fields",
staticMemberDiagnosticKind(),
@@ -269,37 +300,40 @@ public final class InjectValidator implements ClearableCache {
return builder.build();
}
- private ValidationReport<ExecutableElement> validateMethod(ExecutableElement methodElement) {
- ValidationReport.Builder<ExecutableElement> builder = ValidationReport.about(methodElement);
- Set<Modifier> modifiers = methodElement.getModifiers();
- if (modifiers.contains(ABSTRACT)) {
+ private ValidationReport validateMethod(XMethodElement methodElement) {
+ superficialValidation.validateTypeOf(methodElement);
+ ValidationReport.Builder builder = ValidationReport.about(methodElement);
+ if (methodElement.isAbstract()) {
builder.addError("Methods with @Inject may not be abstract", methodElement);
}
- if (modifiers.contains(PRIVATE)) {
+ if (methodElement.isPrivate()) {
builder.addItem(
"Dagger does not support injection into private methods",
privateMemberDiagnosticKind(),
methodElement);
}
- if (modifiers.contains(STATIC)) {
+ if (methodElement.isStatic()) {
builder.addItem(
"Dagger does not support injection into static methods",
staticMemberDiagnosticKind(),
methodElement);
}
- if (!methodElement.getTypeParameters().isEmpty()) {
+ // No need to resolve type parameters since we're only checking existence.
+ if (hasTypeParameters(methodElement)) {
builder.addError("Methods with @Inject may not declare type parameters", methodElement);
}
+ // No need to resolve thrown types since we're only checking existence.
if (!methodElement.getThrownTypes().isEmpty()) {
builder.addError("Methods with @Inject may not throw checked exceptions. "
+ "Please wrap your exceptions in a RuntimeException instead.", methodElement);
}
- for (VariableElement parameter : methodElement.getParameters()) {
+ for (XExecutableParameterElement parameter : methodElement.getParameters()) {
+ superficialValidation.validateTypeOf(parameter);
validateDependencyRequest(builder, parameter);
}
@@ -307,29 +341,41 @@ public final class InjectValidator implements ClearableCache {
}
private void validateDependencyRequest(
- ValidationReport.Builder<?> builder, VariableElement parameter) {
- dependencyRequestValidator.validateDependencyRequest(builder, parameter, parameter.asType());
+ ValidationReport.Builder builder, XVariableElement parameter) {
+ dependencyRequestValidator.validateDependencyRequest(builder, parameter, parameter.getType());
dependencyRequestValidator.checkNotProducer(builder, parameter);
}
- public ValidationReport<TypeElement> validateMembersInjectionType(TypeElement typeElement) {
+ public ValidationReport validateForMembersInjection(XTypeElement typeElement) {
+ return !processedInPreviousRoundOrCompilationUnit(typeElement)
+ ? validate(typeElement) // validate everything
+ : validateForMembersInjectionInternal(typeElement); // validate only inject members
+ }
+
+ private ValidationReport validateForMembersInjectionInternal(XTypeElement typeElement) {
+ return reentrantComputeIfAbsent(
+ membersInjectionReports, typeElement, this::validateForMembersInjectionInternalUncached);
+ }
+
+ private ValidationReport validateForMembersInjectionInternalUncached(XTypeElement typeElement) {
+ superficialValidation.validateTypeOf(typeElement);
// TODO(beder): This element might not be currently compiled, so this error message could be
// left in limbo. Find an appropriate way to display the error message in that case.
- ValidationReport.Builder<TypeElement> builder = ValidationReport.about(typeElement);
+ ValidationReport.Builder builder = ValidationReport.about(typeElement);
boolean hasInjectedMembers = false;
- for (VariableElement element : ElementFilter.fieldsIn(typeElement.getEnclosedElements())) {
- if (MoreElements.isAnnotationPresent(element, Inject.class)) {
+ for (XFieldElement field : typeElement.getDeclaredFields()) {
+ if (InjectionAnnotations.hasInjectAnnotation(field)) {
hasInjectedMembers = true;
- ValidationReport<VariableElement> report = validateField(element);
+ ValidationReport report = validateField(field);
if (!report.isClean()) {
builder.addSubreport(report);
}
}
}
- for (ExecutableElement element : ElementFilter.methodsIn(typeElement.getEnclosedElements())) {
- if (MoreElements.isAnnotationPresent(element, Inject.class)) {
+ for (XMethodElement method : typeElement.getDeclaredMethods()) {
+ if (InjectionAnnotations.hasInjectAnnotation(method)) {
hasInjectedMembers = true;
- ValidationReport<ExecutableElement> report = validateMethod(element);
+ ValidationReport report = validateMethod(method);
if (!report.isClean()) {
builder.addSubreport(report);
}
@@ -340,9 +386,10 @@ public final class InjectValidator implements ClearableCache {
checkInjectIntoPrivateClass(typeElement, builder);
checkInjectIntoKotlinObject(typeElement, builder);
}
- TypeMirror superclass = typeElement.getSuperclass();
- if (!superclass.getKind().equals(TypeKind.NONE)) {
- ValidationReport<TypeElement> report = validateType(MoreTypes.asTypeElement(superclass));
+ if (typeElement.getSuperType() != null) {
+ superficialValidation.validateSuperTypeOf(typeElement);
+ ValidationReport report =
+ validateForMembersInjection(typeElement.getSuperType().getTypeElement());
if (!report.isClean()) {
builder.addSubreport(report);
}
@@ -350,50 +397,17 @@ public final class InjectValidator implements ClearableCache {
return builder.build();
}
- public ValidationReport<TypeElement> validateType(TypeElement typeElement) {
- ValidationReport.Builder<TypeElement> builder = ValidationReport.about(typeElement);
- ValidationReport<TypeElement> membersInjectionReport =
- validateMembersInjectionType(typeElement);
- if (!membersInjectionReport.isClean()) {
- builder.addSubreport(membersInjectionReport);
- }
- for (ExecutableElement element :
- ElementFilter.constructorsIn(typeElement.getEnclosedElements())) {
- if (isAnnotationPresent(element, Inject.class)
- || isAnnotationPresent(element, AssistedInject.class)) {
- ValidationReport<TypeElement> report = validateConstructor(element);
- if (!report.isClean()) {
- builder.addSubreport(report);
- }
- }
- }
- return builder.build();
- }
-
- public boolean isValidType(TypeMirror type) {
- if (!type.getKind().equals(DECLARED)) {
- return true;
- }
- return validateType(MoreTypes.asTypeElement(type)).isClean();
- }
-
/** Returns true if the given method element declares a checked exception. */
- private boolean throwsCheckedExceptions(ExecutableElement methodElement) {
- TypeMirror runtimeExceptionType = elements.getTypeElement(RuntimeException.class).asType();
- TypeMirror errorType = elements.getTypeElement(Error.class).asType();
- for (TypeMirror thrownType : methodElement.getThrownTypes()) {
- if (!types.isSubtype(thrownType, runtimeExceptionType)
- && !types.isSubtype(thrownType, errorType)) {
- return true;
- }
- }
- return false;
+ private boolean throwsCheckedExceptions(XConstructorElement constructorElement) {
+ XType runtimeException = processingEnv.findType(TypeNames.RUNTIME_EXCEPTION);
+ XType error = processingEnv.findType(TypeNames.ERROR);
+ superficialValidation.validateThrownTypesOf(constructorElement);
+ return !constructorElement.getThrownTypes().stream()
+ .allMatch(type -> types.isSubtype(type, runtimeException) || types.isSubtype(type, error));
}
- private void checkInjectIntoPrivateClass(
- Element element, ValidationReport.Builder<TypeElement> builder) {
- if (!Accessibility.isElementAccessibleFromOwnPackage(
- DaggerElements.closestEnclosingTypeElement(element))) {
+ private void checkInjectIntoPrivateClass(XElement element, ValidationReport.Builder builder) {
+ if (!Accessibility.isElementAccessibleFromOwnPackage(closestEnclosingTypeElement(element))) {
builder.addItem(
"Dagger does not support injection into private classes",
privateMemberDiagnosticKind(),
@@ -401,9 +415,8 @@ public final class InjectValidator implements ClearableCache {
}
}
- private void checkInjectIntoKotlinObject(
- TypeElement element, ValidationReport.Builder<TypeElement> builder) {
- if (metadataUtil.isObjectClass(element) || metadataUtil.isCompanionObjectClass(element)) {
+ private void checkInjectIntoKotlinObject(XTypeElement element, ValidationReport.Builder builder) {
+ if (element.isKotlinObject() || element.isCompanionObject()) {
builder.addError("Dagger does not support injection into Kotlin objects", element);
}
}
@@ -417,4 +430,12 @@ public final class InjectValidator implements ClearableCache {
return privateAndStaticInjectionDiagnosticKind.orElse(
compilerOptions.staticMemberValidationKind());
}
+
+ private boolean processedInPreviousRoundOrCompilationUnit(XConstructorElement injectConstructor) {
+ return processingEnv.findTypeElement(factoryNameForElement(injectConstructor)) != null;
+ }
+
+ private boolean processedInPreviousRoundOrCompilationUnit(XTypeElement membersInjectedType) {
+ return processingEnv.findTypeElement(membersInjectorNameForType(membersInjectedType)) != null;
+ }
}
diff --git a/java/dagger/internal/codegen/validation/MapKeyValidator.java b/java/dagger/internal/codegen/validation/MapKeyValidator.java
index 6aa514710..1ec64959b 100644
--- a/java/dagger/internal/codegen/validation/MapKeyValidator.java
+++ b/java/dagger/internal/codegen/validation/MapKeyValidator.java
@@ -16,20 +16,17 @@
package dagger.internal.codegen.validation;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
+import androidx.room.compiler.processing.XAnnotationKt;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.XTypeKt;
import dagger.MapKey;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerElements;
import java.util.List;
import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeKind;
-/**
- * A validator for {@link MapKey} annotations.
- */
+/** A validator for {@link MapKey} annotations. */
// TODO(dpb,gak): Should unwrapped MapKeys be required to have their single member be named "value"?
public final class MapKeyValidator {
private final DaggerElements elements;
@@ -39,22 +36,26 @@ public final class MapKeyValidator {
this.elements = elements;
}
- public ValidationReport<Element> validate(Element element) {
- ValidationReport.Builder<Element> builder = ValidationReport.about(element);
- List<ExecutableElement> members = methodsIn(((TypeElement) element).getEnclosedElements());
+ public ValidationReport validate(XTypeElement element) {
+ ValidationReport.Builder builder = ValidationReport.about(element);
+ List<XMethodElement> members = element.getDeclaredMethods();
if (members.isEmpty()) {
builder.addError("Map key annotations must have members", element);
- } else if (element.getAnnotation(MapKey.class).unwrapValue()) {
+ } else if (XAnnotationKt.get(
+ element.getAnnotation(TypeNames.MAP_KEY), "unwrapValue", Boolean.class)) {
if (members.size() > 1) {
builder.addError(
"Map key annotations with unwrapped values must have exactly one member", element);
- } else if (members.get(0).getReturnType().getKind() == TypeKind.ARRAY) {
+ } else if (XTypeKt.isArray(members.get(0).getReturnType())) {
builder.addError("Map key annotations with unwrapped values cannot use arrays", element);
}
} else if (autoAnnotationIsMissing()) {
builder.addError(
"@AutoAnnotation is a necessary dependency if @MapKey(unwrapValue = false). Add a "
- + "dependency on com.google.auto.value:auto-value:<current version>");
+ + "dependency for the annotation, "
+ + "\"com.google.auto.value:auto-value-annotations:<current version>\", "
+ + "and the annotation processor, "
+ + "\"com.google.auto.value:auto-value:<current version>\"");
}
return builder.build();
}
diff --git a/java/dagger/internal/codegen/validation/MembersInjectionValidator.java b/java/dagger/internal/codegen/validation/MembersInjectionValidator.java
index afa6270f4..0ff11b893 100644
--- a/java/dagger/internal/codegen/validation/MembersInjectionValidator.java
+++ b/java/dagger/internal/codegen/validation/MembersInjectionValidator.java
@@ -16,20 +16,19 @@
package dagger.internal.codegen.validation;
+import static androidx.room.compiler.processing.XTypeKt.isArray;
import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.codegen.xprocessing.XTypes.asArray;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
+import static dagger.internal.codegen.xprocessing.XTypes.isPrimitive;
+import static dagger.internal.codegen.xprocessing.XTypes.isRawParameterizedType;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
import dagger.internal.codegen.binding.InjectionAnnotations;
import javax.inject.Inject;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.PrimitiveType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVisitor;
-import javax.lang.model.util.SimpleTypeVisitor8;
/**
* Validates members injection requests (members injection methods on components and requests for
@@ -44,11 +43,11 @@ final class MembersInjectionValidator {
}
/** Reports errors if a request for a {@code MembersInjector<Foo>}) is invalid. */
- ValidationReport<Element> validateMembersInjectionRequest(
- Element requestElement, TypeMirror membersInjectedType) {
- ValidationReport.Builder<Element> report = ValidationReport.about(requestElement);
+ ValidationReport validateMembersInjectionRequest(
+ XElement requestElement, XType membersInjectedType) {
+ ValidationReport.Builder report = ValidationReport.about(requestElement);
checkQualifiers(report, requestElement);
- membersInjectedType.accept(VALIDATE_MEMBERS_INJECTED_TYPE, report);
+ checkMembersInjectedType(report, membersInjectedType);
return report.build();
}
@@ -57,96 +56,61 @@ final class MembersInjectionValidator {
*
* @throws IllegalArgumentException if the method doesn't have exactly one parameter
*/
- ValidationReport<ExecutableElement> validateMembersInjectionMethod(
- ExecutableElement method, TypeMirror membersInjectedType) {
+ ValidationReport validateMembersInjectionMethod(
+ XMethodElement method, XType membersInjectedType) {
checkArgument(
method.getParameters().size() == 1, "expected a method with one parameter: %s", method);
- ValidationReport.Builder<ExecutableElement> report = ValidationReport.about(method);
+ ValidationReport.Builder report = ValidationReport.about(method);
checkQualifiers(report, method);
checkQualifiers(report, method.getParameters().get(0));
- membersInjectedType.accept(VALIDATE_MEMBERS_INJECTED_TYPE, report);
+ checkMembersInjectedType(report, membersInjectedType);
return report.build();
}
- private void checkQualifiers(ValidationReport.Builder<?> report, Element element) {
- for (AnnotationMirror qualifier : injectionAnnotations.getQualifiers(element)) {
+ private void checkQualifiers(ValidationReport.Builder report, XElement element) {
+ for (XAnnotation qualifier : injectionAnnotations.getQualifiers(element)) {
report.addError("Cannot inject members into qualified types", element, qualifier);
break; // just report on the first qualifier, in case there is more than one
}
}
- private static final TypeVisitor<Void, ValidationReport.Builder<?>>
- VALIDATE_MEMBERS_INJECTED_TYPE =
- new SimpleTypeVisitor8<Void, ValidationReport.Builder<?>>() {
- // Only declared types can be members-injected.
- @Override
- protected Void defaultAction(TypeMirror type, ValidationReport.Builder<?> report) {
- report.addError("Cannot inject members into " + type);
- return null;
- }
+ private void checkMembersInjectedType(ValidationReport.Builder report, XType type) {
+ // Only declared types can be members-injected.
+ if (!isDeclared(type)) {
+ report.addError("Cannot inject members into " + type);
+ return;
+ }
+
+ // If the type is the erasure of a generic type, that means the user referred to
+ // Foo<T> as just 'Foo', which we don't allow. (This is a judgement call; we
+ // *could* allow it and instantiate the type bounds, but we don't.)
+ if (isRawParameterizedType(type)) {
+ report.addError("Cannot inject members into raw type " + type);
+ return;
+ }
- @Override
- public Void visitDeclared(DeclaredType type, ValidationReport.Builder<?> report) {
- if (type.getTypeArguments().isEmpty()) {
- // If the type is the erasure of a generic type, that means the user referred to
- // Foo<T> as just 'Foo', which we don't allow. (This is a judgement call; we
- // *could* allow it and instantiate the type bounds, but we don't.)
- if (!MoreElements.asType(type.asElement()).getTypeParameters().isEmpty()) {
- report.addError("Cannot inject members into raw type " + type);
- }
- } else {
- // If the type has arguments, validate that each type argument is declared.
- // Otherwise the type argument may be a wildcard (or other type), and we can't
- // resolve that to actual types. For array type arguments, validate the type of the
- // array.
- for (TypeMirror arg : type.getTypeArguments()) {
- if (!arg.accept(DECLARED_OR_ARRAY, null)) {
- report.addError(
- "Cannot inject members into types with unbounded type arguments: " + type);
- }
- }
- }
- return null;
- }
- };
+ // If the type has arguments, validate that each type argument is declared.
+ // Otherwise the type argument may be a wildcard (or other type), and we can't
+ // resolve that to actual types. For array type arguments, validate the type of the array.
+ if (!type.getTypeArguments().stream().allMatch(this::isResolvableTypeArgument)) {
+ report.addError("Cannot inject members into types with unbounded type arguments: " + type);
+ }
+ }
// TODO(dpb): Can this be inverted so it explicitly rejects wildcards or type variables?
// This logic is hard to describe.
- private static final TypeVisitor<Boolean, Void> DECLARED_OR_ARRAY =
- new SimpleTypeVisitor8<Boolean, Void>(false) {
- @Override
- public Boolean visitArray(ArrayType arrayType, Void p) {
- return arrayType
- .getComponentType()
- .accept(
- new SimpleTypeVisitor8<Boolean, Void>(false) {
- @Override
- public Boolean visitDeclared(DeclaredType declaredType, Void p) {
- for (TypeMirror arg : declaredType.getTypeArguments()) {
- if (!arg.accept(this, null)) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public Boolean visitArray(ArrayType arrayType, Void p) {
- return arrayType.getComponentType().accept(this, null);
- }
-
- @Override
- public Boolean visitPrimitive(PrimitiveType primitiveType, Void p) {
- return true;
- }
- },
- null);
- }
+ private boolean isResolvableTypeArgument(XType type) {
+ return isDeclared(type)
+ || (isArray(type) && isResolvableArrayComponentType(asArray(type).getComponentType()));
+ }
- @Override
- public Boolean visitDeclared(DeclaredType t, Void p) {
- return true;
- }
- };
+ private boolean isResolvableArrayComponentType(XType type) {
+ if (isDeclared(type)) {
+ return type.getTypeArguments().stream().allMatch(this::isResolvableTypeArgument);
+ } else if (isArray(type)) {
+ return isResolvableArrayComponentType(asArray(type).getComponentType());
+ }
+ return isPrimitive(type);
+ }
}
diff --git a/java/dagger/internal/codegen/validation/ModuleValidator.java b/java/dagger/internal/codegen/validation/ModuleValidator.java
index 02ac06a25..4d3ea3b00 100644
--- a/java/dagger/internal/codegen/validation/ModuleValidator.java
+++ b/java/dagger/internal/codegen/validation/ModuleValidator.java
@@ -16,35 +16,32 @@
package dagger.internal.codegen.validation;
-import static com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.auto.common.MoreTypes.asTypeElement;
-import static com.google.auto.common.Visibility.PRIVATE;
-import static com.google.auto.common.Visibility.PUBLIC;
-import static com.google.auto.common.Visibility.effectiveVisibilityOfElement;
-import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.base.ComponentAnnotation.componentAnnotation;
import static dagger.internal.codegen.base.ComponentAnnotation.isComponentAnnotation;
import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotation;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.getCreatorAnnotations;
import static dagger.internal.codegen.base.ModuleAnnotation.isModuleAnnotation;
-import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
-import static dagger.internal.codegen.base.MoreAnnotationMirrors.simpleName;
-import static dagger.internal.codegen.base.MoreAnnotationValues.asType;
import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.getCreatorAnnotations;
import static dagger.internal.codegen.binding.ConfigurationAnnotations.getSubcomponentCreator;
+import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
-import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
+import static dagger.internal.codegen.xprocessing.XAnnotations.getClassName;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static dagger.internal.codegen.xprocessing.XElements.hasAnyAnnotation;
+import static dagger.internal.codegen.xprocessing.XTypeElements.hasTypeParameters;
+import static dagger.internal.codegen.xprocessing.XTypeElements.isEffectivelyPrivate;
+import static dagger.internal.codegen.xprocessing.XTypeElements.isEffectivelyPublic;
+import static dagger.internal.codegen.xprocessing.XTypes.areEquivalentTypes;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
import static java.util.stream.Collectors.joining;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.STATIC;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.auto.common.Visibility;
+import static kotlin.streams.jdk8.StreamsKt.asStream;
+
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XAnnotationValue;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
@@ -53,22 +50,19 @@ import com.google.common.collect.ListMultimap;
import com.google.common.collect.MultimapBuilder;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
-import com.google.errorprone.annotations.FormatMethod;
-import dagger.Module;
-import dagger.Subcomponent;
-import dagger.internal.codegen.base.ModuleAnnotation;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.base.ComponentCreatorAnnotation;
+import dagger.internal.codegen.base.DaggerSuperficialValidation;
+import dagger.internal.codegen.base.ModuleKind;
import dagger.internal.codegen.binding.BindingGraphFactory;
-import dagger.internal.codegen.binding.ComponentCreatorAnnotation;
import dagger.internal.codegen.binding.ComponentDescriptorFactory;
+import dagger.internal.codegen.binding.InjectionAnnotations;
import dagger.internal.codegen.binding.MethodSignatureFormatter;
-import dagger.internal.codegen.binding.ModuleKind;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingGraph;
-import dagger.producers.ProducerModule;
-import dagger.producers.ProductionSubcomponent;
-import java.lang.annotation.Annotation;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.xprocessing.XElements;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.Scope;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
@@ -76,34 +70,25 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import javax.inject.Inject;
-import javax.inject.Scope;
import javax.inject.Singleton;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Name;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.SimpleAnnotationValueVisitor8;
-import javax.lang.model.util.SimpleTypeVisitor8;
-
-/** A {@linkplain ValidationReport validator} for {@link Module}s or {@link ProducerModule}s. */
+
+/**
+ * A {@linkplain ValidationReport validator} for {@link dagger.Module}s or {@link
+ * dagger.producers.ProducerModule}s.
+ */
@Singleton
public final class ModuleValidator {
- private static final ImmutableSet<Class<? extends Annotation>> SUBCOMPONENT_TYPES =
- ImmutableSet.of(Subcomponent.class, ProductionSubcomponent.class);
- private static final ImmutableSet<Class<? extends Annotation>> SUBCOMPONENT_CREATOR_TYPES =
+ private static final ImmutableSet<ClassName> SUBCOMPONENT_TYPES =
+ ImmutableSet.of(TypeNames.SUBCOMPONENT, TypeNames.PRODUCTION_SUBCOMPONENT);
+ private static final ImmutableSet<ClassName> SUBCOMPONENT_CREATOR_TYPES =
ImmutableSet.of(
- Subcomponent.Builder.class,
- Subcomponent.Factory.class,
- ProductionSubcomponent.Builder.class,
- ProductionSubcomponent.Factory.class);
+ TypeNames.SUBCOMPONENT_BUILDER,
+ TypeNames.SUBCOMPONENT_FACTORY,
+ TypeNames.PRODUCTION_SUBCOMPONENT_BUILDER,
+ TypeNames.PRODUCTION_SUBCOMPONENT_FACTORY);
private static final Optional<Class<?>> ANDROID_PROCESSOR;
private static final String CONTRIBUTES_ANDROID_INJECTOR_NAME =
"dagger.android.ContributesAndroidInjector";
@@ -119,35 +104,35 @@ public final class ModuleValidator {
ANDROID_PROCESSOR = Optional.ofNullable(clazz);
}
- private final DaggerTypes types;
- private final DaggerElements elements;
private final AnyBindingMethodValidator anyBindingMethodValidator;
private final MethodSignatureFormatter methodSignatureFormatter;
private final ComponentDescriptorFactory componentDescriptorFactory;
private final BindingGraphFactory bindingGraphFactory;
private final BindingGraphValidator bindingGraphValidator;
- private final KotlinMetadataUtil metadataUtil;
- private final Map<TypeElement, ValidationReport<TypeElement>> cache = new HashMap<>();
- private final Set<TypeElement> knownModules = new HashSet<>();
+ private final InjectionAnnotations injectionAnnotations;
+ private final DaggerSuperficialValidation superficialValidation;
+ private final XProcessingEnv processingEnv;
+ private final Map<XTypeElement, ValidationReport> cache = new HashMap<>();
+ private final Set<XTypeElement> knownModules = new HashSet<>();
@Inject
ModuleValidator(
- DaggerTypes types,
- DaggerElements elements,
AnyBindingMethodValidator anyBindingMethodValidator,
MethodSignatureFormatter methodSignatureFormatter,
ComponentDescriptorFactory componentDescriptorFactory,
BindingGraphFactory bindingGraphFactory,
BindingGraphValidator bindingGraphValidator,
- KotlinMetadataUtil metadataUtil) {
- this.types = types;
- this.elements = elements;
+ InjectionAnnotations injectionAnnotations,
+ DaggerSuperficialValidation superficialValidation,
+ XProcessingEnv processingEnv) {
this.anyBindingMethodValidator = anyBindingMethodValidator;
this.methodSignatureFormatter = methodSignatureFormatter;
this.componentDescriptorFactory = componentDescriptorFactory;
this.bindingGraphFactory = bindingGraphFactory;
this.bindingGraphValidator = bindingGraphValidator;
- this.metadataUtil = metadataUtil;
+ this.injectionAnnotations = injectionAnnotations;
+ this.superficialValidation = superficialValidation;
+ this.processingEnv = processingEnv;
}
/**
@@ -156,49 +141,44 @@ public final class ModuleValidator {
* is assumed to be valid because it was processed in a previous compilation step. If it were
* invalid, that previous compilation step would have failed and blocked this one.
*
- * <p>This logic depends on this method being called before {@linkplain #validate(TypeElement)
- * validating} any module or {@linkplain #validateReferencedModules(TypeElement, AnnotationMirror,
- * ImmutableSet, Set) component}.
+ * <p>This logic depends on this method being called before {@linkplain #validate(XTypeElement)
+ * validating} any module or {@linkplain #validateReferencedModules(XTypeElement, ModuleKind, Set,
+ * DiagnosticReporter.Builder) component}.
*/
- public void addKnownModules(Collection<TypeElement> modules) {
+ public void addKnownModules(Collection<XTypeElement> modules) {
knownModules.addAll(modules);
}
/** Returns a validation report for a module type. */
- public ValidationReport<TypeElement> validate(TypeElement module) {
+ public ValidationReport validate(XTypeElement module) {
return validate(module, new HashSet<>());
}
- private ValidationReport<TypeElement> validate(
- TypeElement module, Set<TypeElement> visitedModules) {
+ private ValidationReport validate(XTypeElement module, Set<XTypeElement> visitedModules) {
if (visitedModules.add(module)) {
return reentrantComputeIfAbsent(cache, module, m -> validateUncached(module, visitedModules));
}
return ValidationReport.about(module).build();
}
- private ValidationReport<TypeElement> validateUncached(
- TypeElement module, Set<TypeElement> visitedModules) {
- ValidationReport.Builder<TypeElement> builder = ValidationReport.about(module);
+ private ValidationReport validateUncached(XTypeElement module, Set<XTypeElement> visitedModules) {
+ ValidationReport.Builder builder = ValidationReport.about(module);
ModuleKind moduleKind = ModuleKind.forAnnotatedElement(module).get();
- TypeElement contributesAndroidInjectorElement =
- elements.getTypeElement(CONTRIBUTES_ANDROID_INJECTOR_NAME);
- TypeMirror contributesAndroidInjector =
- contributesAndroidInjectorElement != null
- ? contributesAndroidInjectorElement.asType()
- : null;
- List<ExecutableElement> moduleMethods = methodsIn(module.getEnclosedElements());
- List<ExecutableElement> bindingMethods = new ArrayList<>();
- for (ExecutableElement moduleMethod : moduleMethods) {
+ Optional<XType> contributesAndroidInjector =
+ Optional.ofNullable(processingEnv.findTypeElement(CONTRIBUTES_ANDROID_INJECTOR_NAME))
+ .map(XTypeElement::getType);
+ List<XMethodElement> moduleMethods = module.getDeclaredMethods();
+ List<XMethodElement> bindingMethods = new ArrayList<>();
+ for (XMethodElement moduleMethod : moduleMethods) {
if (anyBindingMethodValidator.isBindingMethod(moduleMethod)) {
builder.addSubreport(anyBindingMethodValidator.validate(moduleMethod));
bindingMethods.add(moduleMethod);
}
- for (AnnotationMirror annotation : moduleMethod.getAnnotationMirrors()) {
+ for (XAnnotation annotation : moduleMethod.getAllAnnotations()) {
if (!ANDROID_PROCESSOR.isPresent()
- && MoreTypes.equivalence()
- .equivalent(contributesAndroidInjector, annotation.getAnnotationType())) {
+ && contributesAndroidInjector.isPresent()
+ && areEquivalentTypes(contributesAndroidInjector.get(), annotation.getType())) {
builder.addSubreport(
ValidationReport.about(moduleMethod)
.addError(
@@ -219,30 +199,31 @@ public final class ModuleValidator {
builder.addError(
String.format(
"A @%s may not contain both non-static and abstract binding methods",
- moduleKind.annotation().getSimpleName()));
+ moduleKind.annotation().simpleName()));
}
validateModuleVisibility(module, moduleKind, builder);
- ImmutableListMultimap<Name, ExecutableElement> bindingMethodsByName =
- Multimaps.index(bindingMethods, ExecutableElement::getSimpleName);
+ ImmutableListMultimap<String, XMethodElement> bindingMethodsByName =
+ Multimaps.index(bindingMethods, XElements::getSimpleName);
validateMethodsWithSameName(builder, bindingMethodsByName);
- if (module.getKind() != ElementKind.INTERFACE) {
+ if (!module.isInterface()) {
validateBindingMethodOverrides(
module,
builder,
- Multimaps.index(moduleMethods, ExecutableElement::getSimpleName),
+ Multimaps.index(moduleMethods, XElements::getSimpleName),
bindingMethodsByName);
}
validateModifiers(module, builder);
validateReferencedModules(module, moduleKind, visitedModules, builder);
validateReferencedSubcomponents(module, moduleKind, builder);
validateNoScopeAnnotationsOnModuleElement(module, moduleKind, builder);
- validateSelfCycles(module, builder);
- if (metadataUtil.hasEnclosedCompanionObject(module)) {
- validateCompanionModule(module, builder);
- }
+ validateSelfCycles(module, moduleKind, builder);
+ module.getEnclosedTypeElements().stream()
+ .filter(XTypeElement::isCompanionObject)
+ .collect(toOptional())
+ .ifPresent(companionModule -> validateCompanionModule(companionModule, builder));
if (builder.build().isClean()
&& bindingGraphValidator.shouldDoFullBindingGraphValidation(module)) {
@@ -253,89 +234,74 @@ public final class ModuleValidator {
}
private void validateReferencedSubcomponents(
- final TypeElement subject,
- ModuleKind moduleKind,
- final ValidationReport.Builder<TypeElement> builder) {
- // TODO(ronshapiro): use validateTypesAreDeclared when it is checked in
- ModuleAnnotation moduleAnnotation = moduleAnnotation(moduleKind.getModuleAnnotation(subject));
- for (AnnotationValue subcomponentAttribute :
- moduleAnnotation.subcomponentsAsAnnotationValues()) {
- asType(subcomponentAttribute)
- .accept(
- new SimpleTypeVisitor8<Void, Void>() {
- @Override
- protected Void defaultAction(TypeMirror e, Void aVoid) {
- builder.addError(
- e + " is not a valid subcomponent type",
- subject,
- moduleAnnotation.annotation(),
- subcomponentAttribute);
- return null;
- }
-
- @Override
- public Void visitDeclared(DeclaredType declaredType, Void aVoid) {
- TypeElement attributeType = asTypeElement(declaredType);
- if (isAnyAnnotationPresent(attributeType, SUBCOMPONENT_TYPES)) {
- validateSubcomponentHasBuilder(
- attributeType, moduleAnnotation.annotation(), builder);
- } else {
- builder.addError(
- isAnyAnnotationPresent(attributeType, SUBCOMPONENT_CREATOR_TYPES)
- ? moduleSubcomponentsIncludesCreator(attributeType)
- : moduleSubcomponentsIncludesNonSubcomponent(attributeType),
- subject,
- moduleAnnotation.annotation(),
- subcomponentAttribute);
- }
-
- return null;
- }
- },
- null);
+ XTypeElement subject, ModuleKind moduleKind, ValidationReport.Builder builder) {
+ XAnnotation moduleAnnotation = moduleKind.getModuleAnnotation(subject);
+ for (XAnnotationValue subcomponentValue :
+ moduleAnnotation.getAsAnnotationValueList("subcomponents")) {
+ XType type = subcomponentValue.asType();
+ if (!isDeclared(type)) {
+ builder.addError(
+ type + " is not a valid subcomponent type",
+ subject,
+ moduleAnnotation,
+ subcomponentValue);
+ continue;
+ }
+
+ XTypeElement subcomponentElement = type.getTypeElement();
+ if (hasAnyAnnotation(subcomponentElement, SUBCOMPONENT_TYPES)) {
+ validateSubcomponentHasBuilder(subject, subcomponentElement, moduleAnnotation, builder);
+ } else {
+ builder.addError(
+ hasAnyAnnotation(subcomponentElement, SUBCOMPONENT_CREATOR_TYPES)
+ ? moduleSubcomponentsIncludesCreator(subcomponentElement)
+ : moduleSubcomponentsIncludesNonSubcomponent(subcomponentElement),
+ subject,
+ moduleAnnotation,
+ subcomponentValue);
+ }
}
}
- private static String moduleSubcomponentsIncludesNonSubcomponent(TypeElement notSubcomponent) {
+ private static String moduleSubcomponentsIncludesNonSubcomponent(XTypeElement notSubcomponent) {
return notSubcomponent.getQualifiedName()
+ " is not a @Subcomponent or @ProductionSubcomponent";
}
- private static String moduleSubcomponentsIncludesCreator(
- TypeElement moduleSubcomponentsAttribute) {
- TypeElement subcomponentType =
- MoreElements.asType(moduleSubcomponentsAttribute.getEnclosingElement());
+ private String moduleSubcomponentsIncludesCreator(XTypeElement moduleSubcomponentsAttribute) {
+ XTypeElement subcomponentType = moduleSubcomponentsAttribute.getEnclosingTypeElement();
ComponentCreatorAnnotation creatorAnnotation =
getOnlyElement(getCreatorAnnotations(moduleSubcomponentsAttribute));
return String.format(
"%s is a @%s.%s. Did you mean to use %s?",
moduleSubcomponentsAttribute.getQualifiedName(),
- subcomponentAnnotation(subcomponentType).get().simpleName(),
+ subcomponentAnnotation(subcomponentType, superficialValidation).get().simpleName(),
creatorAnnotation.creatorKind().typeName(),
subcomponentType.getQualifiedName());
}
- private static void validateSubcomponentHasBuilder(
- TypeElement subcomponentAttribute,
- AnnotationMirror moduleAnnotation,
- ValidationReport.Builder<TypeElement> builder) {
+ private void validateSubcomponentHasBuilder(
+ XTypeElement subject,
+ XTypeElement subcomponentAttribute,
+ XAnnotation moduleAnnotation,
+ ValidationReport.Builder builder) {
if (getSubcomponentCreator(subcomponentAttribute).isPresent()) {
return;
}
builder.addError(
moduleSubcomponentsDoesntHaveCreator(subcomponentAttribute, moduleAnnotation),
- builder.getSubject(),
+ subject,
moduleAnnotation);
}
- private static String moduleSubcomponentsDoesntHaveCreator(
- TypeElement subcomponent, AnnotationMirror moduleAnnotation) {
+ private String moduleSubcomponentsDoesntHaveCreator(
+ XTypeElement subcomponent, XAnnotation moduleAnnotation) {
return String.format(
"%1$s doesn't have a @%2$s.Builder or @%2$s.Factory, which is required when used with "
+ "@%3$s.subcomponents",
subcomponent.getQualifiedName(),
- subcomponentAnnotation(subcomponent).get().simpleName(),
- simpleName(moduleAnnotation));
+ subcomponentAnnotation(subcomponent, superficialValidation).get().simpleName(),
+ getClassName(moduleAnnotation).simpleName());
}
enum ModuleMethodKind {
@@ -344,10 +310,10 @@ public final class ModuleValidator {
STATIC_BINDING,
;
- static ModuleMethodKind ofMethod(ExecutableElement moduleMethod) {
- if (moduleMethod.getModifiers().contains(STATIC)) {
+ static ModuleMethodKind ofMethod(XMethodElement moduleMethod) {
+ if (moduleMethod.isStatic()) {
return STATIC_BINDING;
- } else if (moduleMethod.getModifiers().contains(ABSTRACT)) {
+ } else if (moduleMethod.isAbstract()) {
return ABSTRACT_DECLARATION;
} else {
return INSTANCE_BINDING;
@@ -355,38 +321,34 @@ public final class ModuleValidator {
}
}
- private void validateModifiers(
- TypeElement subject, ValidationReport.Builder<TypeElement> builder) {
+ private void validateModifiers(XTypeElement subject, ValidationReport.Builder builder) {
// This coupled with the check for abstract modules in ComponentValidator guarantees that
// only modules without type parameters are referenced from @Component(modules={...}).
- if (!subject.getTypeParameters().isEmpty() && !subject.getModifiers().contains(ABSTRACT)) {
+ if (hasTypeParameters(subject) && !subject.isAbstract()) {
builder.addError("Modules with type parameters must be abstract", subject);
}
}
private void validateMethodsWithSameName(
- ValidationReport.Builder<TypeElement> builder,
- ListMultimap<Name, ExecutableElement> bindingMethodsByName) {
- for (Entry<Name, Collection<ExecutableElement>> entry :
- bindingMethodsByName.asMap().entrySet()) {
- if (entry.getValue().size() > 1) {
- for (ExecutableElement offendingMethod : entry.getValue()) {
- builder.addError(
- String.format(
- "Cannot have more than one binding method with the same name in a single module"),
- offendingMethod);
- }
- }
- }
+ ValidationReport.Builder builder, ListMultimap<String, XMethodElement> bindingMethodsByName) {
+ bindingMethodsByName.asMap().values().stream()
+ .filter(methods -> methods.size() > 1)
+ .flatMap(Collection::stream)
+ .forEach(
+ duplicateMethod -> {
+ builder.addError(
+ "Cannot have more than one binding method with the same name in a single module",
+ duplicateMethod);
+ });
}
private void validateReferencedModules(
- TypeElement subject,
+ XTypeElement subject,
ModuleKind moduleKind,
- Set<TypeElement> visitedModules,
- ValidationReport.Builder<TypeElement> builder) {
+ Set<XTypeElement> visitedModules,
+ ValidationReport.Builder builder) {
// Validate that all the modules we include are valid for inclusion.
- AnnotationMirror mirror = moduleKind.getModuleAnnotation(subject);
+ XAnnotation mirror = moduleKind.getModuleAnnotation(subject);
builder.addSubreport(
validateReferencedModules(
subject, mirror, moduleKind.legalIncludedModuleKinds(), visitedModules));
@@ -407,80 +369,87 @@ public final class ModuleValidator {
* {@code @Module}, or {@code @ProducerModule})
* @param validModuleKinds the module kinds that the annotated type is permitted to include
*/
- ValidationReport<TypeElement> validateReferencedModules(
- TypeElement annotatedType,
- AnnotationMirror annotation,
+ ValidationReport validateReferencedModules(
+ XTypeElement annotatedType,
+ XAnnotation annotation,
ImmutableSet<ModuleKind> validModuleKinds,
- Set<TypeElement> visitedModules) {
- ValidationReport.Builder<TypeElement> subreport = ValidationReport.about(annotatedType);
- ImmutableSet<? extends Class<? extends Annotation>> validModuleAnnotations =
- validModuleKinds.stream().map(ModuleKind::annotation).collect(toImmutableSet());
-
- for (AnnotationValue includedModule : getModules(annotation)) {
- asType(includedModule)
- .accept(
- new SimpleTypeVisitor8<Void, Void>() {
- @Override
- protected Void defaultAction(TypeMirror mirror, Void p) {
- reportError("%s is not a valid module type.", mirror);
- return null;
- }
-
- @Override
- public Void visitDeclared(DeclaredType t, Void p) {
- TypeElement module = MoreElements.asType(t.asElement());
- if (!t.getTypeArguments().isEmpty()) {
- reportError(
- "%s is listed as a module, but has type parameters",
- module.getQualifiedName());
- }
- if (!isAnyAnnotationPresent(module, validModuleAnnotations)) {
- reportError(
- "%s is listed as a module, but is not annotated with %s",
- module.getQualifiedName(),
- (validModuleAnnotations.size() > 1 ? "one of " : "")
- + validModuleAnnotations.stream()
- .map(otherClass -> "@" + otherClass.getSimpleName())
- .collect(joining(", ")));
- } else if (knownModules.contains(module)
- && !validate(module, visitedModules).isClean()) {
- reportError("%s has errors", module.getQualifiedName());
- }
- if (metadataUtil.isCompanionObjectClass(module)) {
- reportError(
- "%s is listed as a module, but it is a companion object class. "
- + "Add @Module to the enclosing class and reference that instead.",
- module.getQualifiedName());
- }
- return null;
- }
-
- @FormatMethod
- private void reportError(String format, Object... args) {
- subreport.addError(
- String.format(format, args), annotatedType, annotation, includedModule);
- }
- },
- null);
+ Set<XTypeElement> visitedModules) {
+ superficialValidation.validateAnnotationOf(annotatedType, annotation);
+
+ ValidationReport.Builder subreport = ValidationReport.about(annotatedType);
+ // TODO(bcorso): Consider creating a DiagnosticLocation object to encapsulate the location in a
+ // single object to avoid duplication across all reported errors
+ for (XAnnotationValue includedModule : getModules(annotation)) {
+ XType type = includedModule.asType();
+ if (!isDeclared(type)) {
+ subreport.addError(
+ String.format("%s is not a valid module type.", type),
+ annotatedType,
+ annotation,
+ includedModule);
+ continue;
+ }
+
+ XTypeElement module = type.getTypeElement();
+ if (hasTypeParameters(module)) {
+ subreport.addError(
+ String.format(
+ "%s is listed as a module, but has type parameters", module.getQualifiedName()),
+ annotatedType,
+ annotation,
+ includedModule);
+ }
+
+ ImmutableSet<ClassName> validModuleAnnotations =
+ validModuleKinds.stream().map(ModuleKind::annotation).collect(toImmutableSet());
+ if (!hasAnyAnnotation(module, validModuleAnnotations)) {
+ subreport.addError(
+ String.format(
+ "%s is listed as a module, but is not annotated with %s",
+ module.getQualifiedName(),
+ (validModuleAnnotations.size() > 1 ? "one of " : "")
+ + validModuleAnnotations.stream()
+ .map(otherClass -> "@" + otherClass.simpleName())
+ .collect(joining(", "))),
+ annotatedType,
+ annotation,
+ includedModule);
+ } else if (knownModules.contains(module) && !validate(module, visitedModules).isClean()) {
+ subreport.addError(
+ String.format("%s has errors", module.getQualifiedName()),
+ annotatedType,
+ annotation,
+ includedModule);
+ }
+ if (module.isCompanionObject()) {
+ subreport.addError(
+ String.format(
+ "%s is listed as a module, but it is a companion object class. "
+ + "Add @Module to the enclosing class and reference that instead.",
+ module.getQualifiedName()),
+ annotatedType,
+ annotation,
+ includedModule);
+ }
}
return subreport.build();
}
- private static ImmutableList<AnnotationValue> getModules(AnnotationMirror annotation) {
+ private static ImmutableList<XAnnotationValue> getModules(XAnnotation annotation) {
if (isModuleAnnotation(annotation)) {
- return moduleAnnotation(annotation).includesAsAnnotationValues();
+ return ImmutableList.copyOf(annotation.getAsAnnotationValueList("includes"));
}
if (isComponentAnnotation(annotation)) {
- return componentAnnotation(annotation).moduleValues();
+ return ImmutableList.copyOf(annotation.getAsAnnotationValueList("modules"));
}
throw new IllegalArgumentException(String.format("unsupported annotation: %s", annotation));
}
private void validateBindingMethodOverrides(
- TypeElement subject,
- ValidationReport.Builder<TypeElement> builder,
- ImmutableListMultimap<Name, ExecutableElement> moduleMethodsByName,
- ImmutableListMultimap<Name, ExecutableElement> bindingMethodsByName) {
+ XTypeElement subject,
+ ValidationReport.Builder builder,
+ ImmutableListMultimap<String, XMethodElement> moduleMethodsByName,
+ ImmutableListMultimap<String, XMethodElement> bindingMethodsByName) {
// For every binding method, confirm it overrides nothing *and* nothing overrides it.
// Consider the following hierarchy:
// class Parent {
@@ -496,22 +465,22 @@ public final class ModuleValidator {
// In each of those cases, we want to fail. "a" is clear, "b" because Child is overriding
// a binding method in Parent, and "c" because Child is defining a binding method that overrides
// Parent.
- TypeElement currentClass = subject;
- TypeMirror objectType = elements.getTypeElement(Object.class).asType();
- // We keep track of methods that failed so we don't spam with multiple failures.
- Set<ExecutableElement> failedMethods = Sets.newHashSet();
- ListMultimap<Name, ExecutableElement> allMethodsByName =
+ XTypeElement currentClass = subject;
+ XType objectType = processingEnv.findType(TypeName.OBJECT);
+ // We keep track of visited methods so we don't spam with multiple failures.
+ Set<XMethodElement> visitedMethods = Sets.newHashSet();
+ ListMultimap<String, XMethodElement> allMethodsByName =
MultimapBuilder.hashKeys().arrayListValues().build(moduleMethodsByName);
- while (!types.isSameType(currentClass.getSuperclass(), objectType)) {
- currentClass = MoreElements.asType(types.asElement(currentClass.getSuperclass()));
- List<ExecutableElement> superclassMethods = methodsIn(currentClass.getEnclosedElements());
- for (ExecutableElement superclassMethod : superclassMethods) {
- Name name = superclassMethod.getSimpleName();
+ while (!currentClass.getSuperType().isSameType(objectType)) {
+ currentClass = currentClass.getSuperType().getTypeElement();
+ List<XMethodElement> superclassMethods = currentClass.getDeclaredMethods();
+ for (XMethodElement superclassMethod : superclassMethods) {
+ String name = getSimpleName(superclassMethod);
// For each method in the superclass, confirm our binding methods don't override it
- for (ExecutableElement bindingMethod : bindingMethodsByName.get(name)) {
- if (failedMethods.add(bindingMethod)
- && elements.overrides(bindingMethod, superclassMethod, subject)) {
+ for (XMethodElement bindingMethod : bindingMethodsByName.get(name)) {
+ if (visitedMethods.add(bindingMethod)
+ && bindingMethod.overrides(superclassMethod, subject)) {
builder.addError(
String.format(
"Binding methods may not override another method. Overrides: %s",
@@ -521,9 +490,8 @@ public final class ModuleValidator {
}
// For each binding method in superclass, confirm our methods don't override it.
if (anyBindingMethodValidator.isBindingMethod(superclassMethod)) {
- for (ExecutableElement method : allMethodsByName.get(name)) {
- if (failedMethods.add(method)
- && elements.overrides(method, superclassMethod, subject)) {
+ for (XMethodElement method : allMethodsByName.get(name)) {
+ if (visitedMethods.add(method) && method.overrides(superclassMethod, subject)) {
builder.addError(
String.format(
"Binding methods may not be overridden in modules. Overrides: %s",
@@ -532,54 +500,41 @@ public final class ModuleValidator {
}
}
}
- allMethodsByName.put(superclassMethod.getSimpleName(), superclassMethod);
+ // TODO(b/202521399): Add a test for cases that add to this map.
+ allMethodsByName.put(getSimpleName(superclassMethod), superclassMethod);
}
}
}
private void validateModuleVisibility(
- final TypeElement moduleElement,
- ModuleKind moduleKind,
- final ValidationReport.Builder<?> reportBuilder) {
- ModuleAnnotation moduleAnnotation =
- moduleAnnotation(getAnnotationMirror(moduleElement, moduleKind.annotation()).get());
- Visibility moduleVisibility = Visibility.ofElement(moduleElement);
- Visibility moduleEffectiveVisibility = effectiveVisibilityOfElement(moduleElement);
- if (moduleVisibility.equals(PRIVATE)) {
+ XTypeElement moduleElement, ModuleKind moduleKind, ValidationReport.Builder reportBuilder) {
+ if (moduleElement.isPrivate()) {
reportBuilder.addError("Modules cannot be private.", moduleElement);
- } else if (moduleEffectiveVisibility.equals(PRIVATE)) {
+ } else if (isEffectivelyPrivate(moduleElement)) {
reportBuilder.addError("Modules cannot be enclosed in private types.", moduleElement);
}
-
- switch (moduleElement.getNestingKind()) {
- case ANONYMOUS:
- throw new IllegalStateException("Can't apply @Module to an anonymous class");
- case LOCAL:
- throw new IllegalStateException("Local classes shouldn't show up in the processor");
- case MEMBER:
- case TOP_LEVEL:
- if (moduleEffectiveVisibility.equals(PUBLIC)) {
- ImmutableSet<TypeElement> invalidVisibilityIncludes =
- getModuleIncludesWithInvalidVisibility(moduleAnnotation);
- if (!invalidVisibilityIncludes.isEmpty()) {
- reportBuilder.addError(
- String.format(
- "This module is public, but it includes non-public (or effectively non-public) "
- + "modules (%s) that have non-static, non-abstract binding methods. Either "
- + "reduce the visibility of this module, make the included modules "
- + "public, or make all of the binding methods on the included modules "
- + "abstract or static.",
- formatListForErrorMessage(invalidVisibilityIncludes.asList())),
- moduleElement);
- }
- }
+ if (isEffectivelyPublic(moduleElement)) {
+ ImmutableSet<XTypeElement> invalidVisibilityIncludes =
+ getModuleIncludesWithInvalidVisibility(moduleKind.getModuleAnnotation(moduleElement));
+ if (!invalidVisibilityIncludes.isEmpty()) {
+ reportBuilder.addError(
+ String.format(
+ "This module is public, but it includes non-public (or effectively non-public) "
+ + "modules (%s) that have non-static, non-abstract binding methods. Either "
+ + "reduce the visibility of this module, make the included modules "
+ + "public, or make all of the binding methods on the included modules "
+ + "abstract or static.",
+ formatListForErrorMessage(invalidVisibilityIncludes.asList())),
+ moduleElement);
+ }
}
}
- private ImmutableSet<TypeElement> getModuleIncludesWithInvalidVisibility(
- ModuleAnnotation moduleAnnotation) {
- return moduleAnnotation.includes().stream()
- .filter(include -> !effectiveVisibilityOfElement(include).equals(PUBLIC))
+ private ImmutableSet<XTypeElement> getModuleIncludesWithInvalidVisibility(
+ XAnnotation moduleAnnotation) {
+ return moduleAnnotation.getAnnotationValue("includes").asTypeList().stream()
+ .map(XType::getTypeElement)
+ .filter(include -> !isEffectivelyPublic(include))
.filter(this::requiresModuleInstance)
.collect(toImmutableSet());
}
@@ -590,103 +545,82 @@ public final class ModuleValidator {
* {@code abstract} nor {@code static}. Alternatively, if the module is a Kotlin Object then the
* binding methods are considered {@code static}, requiring no module instance.
*/
- private boolean requiresModuleInstance(TypeElement module) {
- // Note elements.getAllMembers(module) rather than module.getEnclosedElements() here: we need to
- // include binding methods declared in supertypes because unlike most other validations being
- // done in this class, which assume that supertype binding methods will be validated in a
- // separate call to the validator since the supertype itself must be a @Module, we need to look
- // at all the binding methods in the module's type hierarchy here.
- boolean isKotlinObject =
- metadataUtil.isObjectClass(module) || metadataUtil.isCompanionObjectClass(module);
- if (isKotlinObject) {
- return false;
- }
- return methodsIn(elements.getAllMembers(module)).stream()
- .filter(anyBindingMethodValidator::isBindingMethod)
- .map(ExecutableElement::getModifiers)
- .anyMatch(modifiers -> !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC));
+ private boolean requiresModuleInstance(XTypeElement module) {
+ // Note: We use XTypeElement#getAllMethods() rather than XTypeElement#getDeclaredMethods() here
+ // because we need to include binding methods declared in supertypes because unlike most other
+ // validations being done in this class, which assume that supertype binding methods will be
+ // validated in a separate call to the validator since the supertype itself must be a @Module,
+ // we need to look at all the binding methods in the module's type hierarchy here.
+ return !(module.isKotlinObject() || module.isCompanionObject())
+ && !asStream(module.getAllMethods())
+ .filter(anyBindingMethodValidator::isBindingMethod)
+ .allMatch(method -> method.isAbstract() || method.isStatic());
}
private void validateNoScopeAnnotationsOnModuleElement(
- TypeElement module, ModuleKind moduleKind, ValidationReport.Builder<TypeElement> report) {
- for (AnnotationMirror scope : getAnnotatedAnnotations(module, Scope.class)) {
+ XTypeElement module, ModuleKind moduleKind, ValidationReport.Builder report) {
+ for (Scope scope : injectionAnnotations.getScopes(module)) {
report.addError(
String.format(
"@%ss cannot be scoped. Did you mean to scope a method instead?",
- moduleKind.annotation().getSimpleName()),
+ moduleKind.annotation().simpleName()),
module,
- scope);
+ scope.scopeAnnotation().xprocessing());
}
}
private void validateSelfCycles(
- TypeElement module, ValidationReport.Builder<TypeElement> builder) {
- ModuleAnnotation moduleAnnotation = moduleAnnotation(module).get();
- moduleAnnotation
- .includesAsAnnotationValues()
+ XTypeElement module, ModuleKind moduleKind, ValidationReport.Builder builder) {
+ XAnnotation moduleAnnotation = moduleKind.getModuleAnnotation(module);
+ moduleAnnotation.getAsAnnotationValueList("includes").stream()
+ .filter(includedModule -> areEquivalentTypes(module.getType(), includedModule.asType()))
.forEach(
- value ->
- value.accept(
- new SimpleAnnotationValueVisitor8<Void, Void>() {
- @Override
- public Void visitType(TypeMirror includedModule, Void aVoid) {
- if (MoreTypes.equivalence().equivalent(module.asType(), includedModule)) {
- String moduleKind = moduleAnnotation.annotationName();
- builder.addError(
- String.format("@%s cannot include themselves.", moduleKind),
- module,
- moduleAnnotation.annotation(),
- value);
- }
- return null;
- }
- },
- null));
+ includedModule ->
+ builder.addError(
+ String.format(
+ "@%s cannot include themselves.", moduleKind.annotation().simpleName()),
+ module,
+ moduleAnnotation,
+ includedModule));
}
private void validateCompanionModule(
- TypeElement module, ValidationReport.Builder<TypeElement> builder) {
- checkArgument(metadataUtil.hasEnclosedCompanionObject(module));
- TypeElement companionModule = metadataUtil.getEnclosedCompanionObject(module);
- List<ExecutableElement> companionModuleMethods =
- methodsIn(companionModule.getEnclosedElements());
- List<ExecutableElement> companionBindingMethods = new ArrayList<>();
- for (ExecutableElement companionModuleMethod : companionModuleMethods) {
- if (anyBindingMethodValidator.isBindingMethod(companionModuleMethod)) {
- builder.addSubreport(anyBindingMethodValidator.validate(companionModuleMethod));
- companionBindingMethods.add(companionModuleMethod);
+ XTypeElement companionModule, ValidationReport.Builder builder) {
+ List<XMethodElement> companionBindingMethods = new ArrayList<>();
+ for (XMethodElement companionMethod : companionModule.getDeclaredMethods()) {
+ if (anyBindingMethodValidator.isBindingMethod(companionMethod)) {
+ builder.addSubreport(anyBindingMethodValidator.validate(companionMethod));
+ companionBindingMethods.add(companionMethod);
}
// On normal modules only overriding other binding methods is disallowed, but for companion
// objects we are prohibiting any override. For this can rely on checking the @Override
// annotation since the Kotlin compiler will always produce them for overriding methods.
- if (isAnnotationPresent(companionModuleMethod, Override.class)) {
+ if (companionMethod.hasAnnotation(TypeNames.OVERRIDE)) {
builder.addError(
- "Binding method in companion object may not override another method.",
- companionModuleMethod);
+ "Binding method in companion object may not override another method.", companionMethod);
}
// TODO(danysantiago): Be strict about the usage of @JvmStatic, i.e. tell user to remove it.
}
- ImmutableListMultimap<Name, ExecutableElement> bindingMethodsByName =
- Multimaps.index(companionBindingMethods, ExecutableElement::getSimpleName);
+ ImmutableListMultimap<String, XMethodElement> bindingMethodsByName =
+ Multimaps.index(companionBindingMethods, XElements::getSimpleName);
validateMethodsWithSameName(builder, bindingMethodsByName);
// If there are provision methods, then check the visibility. Companion objects are composed by
// an inner class and a static field, it is not enough to check the visibility on the type
// element or the field, therefore we check the metadata.
- if (!companionBindingMethods.isEmpty() && metadataUtil.isVisibilityPrivate(companionModule)) {
+ if (!companionBindingMethods.isEmpty() && companionModule.isPrivate()) {
builder.addError(
"A Companion Module with binding methods cannot be private.", companionModule);
}
}
- private void validateModuleBindings(
- TypeElement module, ValidationReport.Builder<TypeElement> report) {
+ private void validateModuleBindings(XTypeElement module, ValidationReport.Builder report) {
BindingGraph bindingGraph =
- bindingGraphFactory.create(
- componentDescriptorFactory.moduleComponentDescriptor(module), true)
+ bindingGraphFactory
+ .create(componentDescriptorFactory.moduleComponentDescriptor(module), true)
.topLevelBindingGraph();
if (!bindingGraphValidator.isValid(bindingGraph)) {
// Since the validator uses a DiagnosticReporter to report errors, the ValdiationReport won't
diff --git a/java/dagger/internal/codegen/validation/MonitoringModuleGenerator.java b/java/dagger/internal/codegen/validation/MonitoringModuleGenerator.java
index 1c2eb1c9a..fbbd18f32 100644
--- a/java/dagger/internal/codegen/validation/MonitoringModuleGenerator.java
+++ b/java/dagger/internal/codegen/validation/MonitoringModuleGenerator.java
@@ -26,40 +26,36 @@ import static javax.lang.model.element.Modifier.ABSTRACT;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.STATIC;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableList;
-import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import dagger.Module;
-import dagger.Provides;
import dagger.internal.codegen.base.SourceFileGenerator;
import dagger.internal.codegen.binding.SourceFiles;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.multibindings.Multibinds;
-import dagger.producers.ProductionScope;
-import dagger.producers.monitoring.ProductionComponentMonitor;
-import dagger.producers.monitoring.internal.Monitors;
-import javax.annotation.processing.Filer;
import javax.inject.Inject;
import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
/** Generates a monitoring module for use with production components. */
-final class MonitoringModuleGenerator extends SourceFileGenerator<TypeElement> {
+final class MonitoringModuleGenerator extends SourceFileGenerator<XTypeElement> {
@Inject
- MonitoringModuleGenerator(Filer filer, DaggerElements elements, SourceVersion sourceVersion) {
+ MonitoringModuleGenerator(XFiler filer, DaggerElements elements, SourceVersion sourceVersion) {
super(filer, elements, sourceVersion);
}
@Override
- public Element originatingElement(TypeElement componentElement) {
+ public XElement originatingElement(XTypeElement componentElement) {
return componentElement;
}
@Override
- public ImmutableList<TypeSpec.Builder> topLevelTypes(TypeElement componentElement) {
+ public ImmutableList<TypeSpec.Builder> topLevelTypes(XTypeElement componentElement) {
return ImmutableList.of(
classBuilder(SourceFiles.generatedMonitoringModuleName(componentElement))
.addAnnotation(Module.class)
@@ -81,17 +77,16 @@ final class MonitoringModuleGenerator extends SourceFileGenerator<TypeElement> {
.build();
}
- private MethodSpec monitor(TypeElement componentElement) {
+ private MethodSpec monitor(XTypeElement componentElement) {
return methodBuilder("monitor")
- .returns(ProductionComponentMonitor.class)
+ .returns(TypeNames.PRODUCTION_COMPONENT_MONITOR)
.addModifiers(STATIC)
- .addAnnotation(Provides.class)
- .addAnnotation(ProductionScope.class)
- .addParameter(providerOf(ClassName.get(componentElement.asType())), "component")
- .addParameter(
- providerOf(setOf(PRODUCTION_COMPONENT_MONITOR_FACTORY)), "factories")
+ .addAnnotation(TypeNames.PROVIDES)
+ .addAnnotation(TypeNames.PRODUCTION_SCOPE)
+ .addParameter(providerOf(componentElement.getType().getTypeName()), "component")
+ .addParameter(providerOf(setOf(PRODUCTION_COMPONENT_MONITOR_FACTORY)), "factories")
.addStatement(
- "return $T.createMonitorForComponent(component, factories)", Monitors.class)
+ "return $T.createMonitorForComponent(component, factories)", TypeNames.MONITORS)
.build();
}
}
diff --git a/java/dagger/internal/codegen/validation/MonitoringModuleProcessingStep.java b/java/dagger/internal/codegen/validation/MonitoringModuleProcessingStep.java
index 5d4c64e39..e7ba8fd3e 100644
--- a/java/dagger/internal/codegen/validation/MonitoringModuleProcessingStep.java
+++ b/java/dagger/internal/codegen/validation/MonitoringModuleProcessingStep.java
@@ -16,40 +16,35 @@
package dagger.internal.codegen.validation;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-import java.lang.annotation.Annotation;
-import java.util.Set;
-import javax.annotation.processing.Messager;
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.javapoet.TypeNames;
import javax.inject.Inject;
-import javax.lang.model.element.TypeElement;
/**
* A processing step that is responsible for generating a special module for a {@link
- * ProductionComponent} or {@link ProductionSubcomponent}.
+ * dagger.producers.ProductionComponent} or {@link dagger.producers.ProductionSubcomponent}.
*/
-public final class MonitoringModuleProcessingStep extends TypeCheckingProcessingStep<TypeElement> {
- private final Messager messager;
+public final class MonitoringModuleProcessingStep extends TypeCheckingProcessingStep<XTypeElement> {
+ private final XMessager messager;
private final MonitoringModuleGenerator monitoringModuleGenerator;
@Inject
MonitoringModuleProcessingStep(
- Messager messager, MonitoringModuleGenerator monitoringModuleGenerator) {
- super(MoreElements::asType);
+ XMessager messager, MonitoringModuleGenerator monitoringModuleGenerator) {
this.messager = messager;
this.monitoringModuleGenerator = monitoringModuleGenerator;
}
@Override
- public Set<? extends Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(ProductionComponent.class, ProductionSubcomponent.class);
+ public ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(TypeNames.PRODUCTION_COMPONENT, TypeNames.PRODUCTION_SUBCOMPONENT);
}
@Override
- protected void process(
- TypeElement element, ImmutableSet<Class<? extends Annotation>> annotations) {
- monitoringModuleGenerator.generate(MoreElements.asType(element), messager);
+ protected void process(XTypeElement productionComponent, ImmutableSet<ClassName> annotations) {
+ monitoringModuleGenerator.generate(productionComponent, messager);
}
}
diff --git a/java/dagger/internal/codegen/validation/MultibindingAnnotationsProcessingStep.java b/java/dagger/internal/codegen/validation/MultibindingAnnotationsProcessingStep.java
index fd75eac24..4771de20c 100644
--- a/java/dagger/internal/codegen/validation/MultibindingAnnotationsProcessingStep.java
+++ b/java/dagger/internal/codegen/validation/MultibindingAnnotationsProcessingStep.java
@@ -16,45 +16,39 @@
package dagger.internal.codegen.validation;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
import static javax.tools.Diagnostic.Kind.ERROR;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XMessager;
import com.google.common.collect.ImmutableSet;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.IntoSet;
-import java.lang.annotation.Annotation;
-import java.util.Set;
-import javax.annotation.processing.Messager;
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.javapoet.TypeNames;
import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
/**
- * Processing step that verifies that {@link IntoSet}, {@link ElementsIntoSet} and {@link IntoMap}
- * are not present on non-binding methods.
+ * Processing step that verifies that {@link dagger.multibindings.IntoSet}, {@link
+ * dagger.multibindings.ElementsIntoSet} and {@link dagger.multibindings.IntoMap} are not present on
+ * non-binding methods.
*/
public final class MultibindingAnnotationsProcessingStep
- extends TypeCheckingProcessingStep<ExecutableElement> {
+ extends TypeCheckingProcessingStep<XExecutableElement> {
private final AnyBindingMethodValidator anyBindingMethodValidator;
- private final Messager messager;
+ private final XMessager messager;
@Inject
MultibindingAnnotationsProcessingStep(
- AnyBindingMethodValidator anyBindingMethodValidator, Messager messager) {
- super(MoreElements::asExecutable);
+ AnyBindingMethodValidator anyBindingMethodValidator, XMessager messager) {
this.anyBindingMethodValidator = anyBindingMethodValidator;
this.messager = messager;
}
@Override
- public Set<? extends Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(IntoSet.class, ElementsIntoSet.class, IntoMap.class);
+ public ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(TypeNames.INTO_SET, TypeNames.ELEMENTS_INTO_SET, TypeNames.INTO_MAP);
}
@Override
- protected void process(
- ExecutableElement method, ImmutableSet<Class<? extends Annotation>> annotations) {
+ protected void process(XExecutableElement method, ImmutableSet<ClassName> annotations) {
if (!anyBindingMethodValidator.isBindingMethod(method)) {
annotations.forEach(
annotation ->
@@ -62,7 +56,7 @@ public final class MultibindingAnnotationsProcessingStep
ERROR,
"Multibinding annotations may only be on @Provides, @Produces, or @Binds methods",
method,
- getAnnotationMirror(method, annotation).get()));
+ method.getAnnotation(annotation)));
}
}
}
diff --git a/java/dagger/internal/codegen/validation/MultibindsMethodValidator.java b/java/dagger/internal/codegen/validation/MultibindsMethodValidator.java
index 8829667b2..de54141d9 100644
--- a/java/dagger/internal/codegen/validation/MultibindsMethodValidator.java
+++ b/java/dagger/internal/codegen/validation/MultibindsMethodValidator.java
@@ -21,39 +21,31 @@ import static dagger.internal.codegen.validation.BindingElementValidator.AllowsM
import static dagger.internal.codegen.validation.BindingElementValidator.AllowsScoping.NO_SCOPING;
import static dagger.internal.codegen.validation.BindingMethodValidator.Abstractness.MUST_BE_ABSTRACT;
import static dagger.internal.codegen.validation.BindingMethodValidator.ExceptionSuperclass.NO_EXCEPTIONS;
+import static dagger.internal.codegen.xprocessing.XTypes.isWildcard;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
import com.google.common.collect.ImmutableSet;
-import dagger.Module;
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.SetType;
import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.multibindings.Multibinds;
-import dagger.producers.ProducerModule;
import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.TypeMirror;
-/** A validator for {@link Multibinds} methods. */
+/** A validator for {@link dagger.multibindings.Multibinds} methods. */
class MultibindsMethodValidator extends BindingMethodValidator {
- /** Creates a validator for {@link Multibinds @Multibinds} methods. */
+ /** Creates a validator for {@link dagger.multibindings.Multibinds @Multibinds} methods. */
@Inject
MultibindsMethodValidator(
- DaggerElements elements,
DaggerTypes types,
- KotlinMetadataUtil kotlinMetadataUtil,
DependencyRequestValidator dependencyRequestValidator,
InjectionAnnotations injectionAnnotations) {
super(
- elements,
types,
- kotlinMetadataUtil,
- Multibinds.class,
- ImmutableSet.of(Module.class, ProducerModule.class),
+ TypeNames.MULTIBINDS,
+ ImmutableSet.of(TypeNames.MODULE, TypeNames.PRODUCER_MODULE),
dependencyRequestValidator,
MUST_BE_ABSTRACT,
NO_EXCEPTIONS,
@@ -63,18 +55,21 @@ class MultibindsMethodValidator extends BindingMethodValidator {
}
@Override
- protected ElementValidator elementValidator(ExecutableElement element) {
- return new Validator(element);
+ protected ElementValidator elementValidator(XMethodElement method) {
+ return new Validator(method);
}
private class Validator extends MethodValidator {
- Validator(ExecutableElement element) {
- super(element);
+ private final XMethodElement method;
+
+ Validator(XMethodElement method) {
+ super(method);
+ this.method = method;
}
@Override
protected void checkParameters() {
- if (!element.getParameters().isEmpty()) {
+ if (!method.getParameters().isEmpty()) {
report.addError(bindingMethods("cannot have parameters"));
}
}
@@ -82,29 +77,28 @@ class MultibindsMethodValidator extends BindingMethodValidator {
/** Adds an error unless the method returns a {@code Map<K, V>} or {@code Set<T>}. */
@Override
protected void checkType() {
- if (!isPlainMap(element.getReturnType())
- && !isPlainSet(element.getReturnType())) {
+ if (!isPlainMap(method.getReturnType()) && !isPlainSet(method.getReturnType())) {
report.addError(bindingMethods("must return Map<K, V> or Set<T>"));
}
}
- private boolean isPlainMap(TypeMirror returnType) {
+ private boolean isPlainMap(XType returnType) {
if (!MapType.isMap(returnType)) {
return false;
}
MapType mapType = MapType.from(returnType);
return !mapType.isRawType()
- && MoreTypes.isType(mapType.valueType()) // No wildcards.
+ && !isWildcard(mapType.valueType())
&& !isFrameworkType(mapType.valueType());
}
- private boolean isPlainSet(TypeMirror returnType) {
+ private boolean isPlainSet(XType returnType) {
if (!SetType.isSet(returnType)) {
return false;
}
SetType setType = SetType.from(returnType);
return !setType.isRawType()
- && MoreTypes.isType(setType.elementType()) // No wildcards.
+ && !isWildcard(setType.elementType())
&& !isFrameworkType(setType.elementType());
}
}
diff --git a/java/dagger/internal/codegen/validation/ProducesMethodValidator.java b/java/dagger/internal/codegen/validation/ProducesMethodValidator.java
index 1606ebec0..ed7108627 100644
--- a/java/dagger/internal/codegen/validation/ProducesMethodValidator.java
+++ b/java/dagger/internal/codegen/validation/ProducesMethodValidator.java
@@ -17,45 +17,36 @@
package dagger.internal.codegen.validation;
import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.binding.ConfigurationAnnotations.getNullableAnnotation;
import static dagger.internal.codegen.validation.BindingElementValidator.AllowsMultibindings.ALLOWS_MULTIBINDINGS;
import static dagger.internal.codegen.validation.BindingElementValidator.AllowsScoping.NO_SCOPING;
import static dagger.internal.codegen.validation.BindingMethodValidator.Abstractness.MUST_BE_CONCRETE;
import static dagger.internal.codegen.validation.BindingMethodValidator.ExceptionSuperclass.EXCEPTION;
+import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
import com.google.common.util.concurrent.ListenableFuture;
-import dagger.internal.codegen.binding.ConfigurationAnnotations;
import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
import java.util.Optional;
import java.util.Set;
import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-/** A validator for {@link Produces} methods. */
+/** A validator for {@link dagger.producers.Produces} methods. */
final class ProducesMethodValidator extends BindingMethodValidator {
@Inject
ProducesMethodValidator(
- DaggerElements elements,
DaggerTypes types,
- KotlinMetadataUtil kotlinMetadataUtil,
DependencyRequestValidator dependencyRequestValidator,
InjectionAnnotations injectionAnnotations) {
super(
- elements,
types,
- kotlinMetadataUtil,
dependencyRequestValidator,
- Produces.class,
- ProducerModule.class,
+ TypeNames.PRODUCES,
+ TypeNames.PRODUCER_MODULE,
MUST_BE_CONCRETE,
EXCEPTION,
ALLOWS_MULTIBINDINGS,
@@ -75,13 +66,16 @@ final class ProducesMethodValidator extends BindingMethodValidator {
}
@Override
- protected ElementValidator elementValidator(ExecutableElement element) {
- return new Validator(element);
+ protected ElementValidator elementValidator(XMethodElement method) {
+ return new Validator(method);
}
private class Validator extends MethodValidator {
- Validator(ExecutableElement element) {
- super(element);
+ private final XMethodElement method;
+
+ Validator(XMethodElement method) {
+ super(method);
+ this.method = method;
}
@Override
@@ -89,10 +83,12 @@ final class ProducesMethodValidator extends BindingMethodValidator {
checkNullable();
}
- /** Adds a warning if a {@link Produces @Produces} method is declared nullable. */
+ /**
+ * Adds a warning if a {@link dagger.producers.Produces @Produces} method is declared nullable.
+ */
// TODO(beder): Properly handle nullable with producer methods.
private void checkNullable() {
- if (ConfigurationAnnotations.getNullableType(element).isPresent()) {
+ if (getNullableAnnotation(method).isPresent()) {
report.addWarning("@Nullable on @Produces methods does not do anything");
}
}
@@ -103,35 +99,28 @@ final class ProducesMethodValidator extends BindingMethodValidator {
* <p>Allows {@code keyType} to be a {@link ListenableFuture} of an otherwise-valid key type.
*/
@Override
- protected void checkKeyType(TypeMirror keyType) {
- Optional<TypeMirror> typeToCheck = unwrapListenableFuture(keyType);
- if (typeToCheck.isPresent()) {
- super.checkKeyType(typeToCheck.get());
- }
+ protected void checkKeyType(XType keyType) {
+ unwrapListenableFuture(keyType).ifPresent(super::checkKeyType);
}
/**
* {@inheritDoc}
*
- * <p>Allows an {@link ElementsIntoSet @ElementsIntoSet} or {@code SET_VALUES} method to return
- * a {@link ListenableFuture} of a {@link Set} as well.
+ * <p>Allows an {@link dagger.multibindings.ElementsIntoSet @ElementsIntoSet} or {@code
+ * SET_VALUES} method to return a {@link ListenableFuture} of a {@link Set} as well.
*/
@Override
protected void checkSetValuesType() {
- Optional<TypeMirror> typeToCheck = unwrapListenableFuture(element.getReturnType());
- if (typeToCheck.isPresent()) {
- checkSetValuesType(typeToCheck.get());
- }
+ unwrapListenableFuture(method.getReturnType()).ifPresent(this::checkSetValuesType);
}
- private Optional<TypeMirror> unwrapListenableFuture(TypeMirror type) {
- if (MoreTypes.isType(type) && MoreTypes.isTypeOf(ListenableFuture.class, type)) {
- DeclaredType declaredType = MoreTypes.asDeclared(type);
- if (declaredType.getTypeArguments().isEmpty()) {
+ private Optional<XType> unwrapListenableFuture(XType type) {
+ if (isTypeOf(type, TypeNames.LISTENABLE_FUTURE)) {
+ if (type.getTypeArguments().isEmpty()) {
report.addError("@Produces methods cannot return a raw ListenableFuture");
return Optional.empty();
} else {
- return Optional.of((TypeMirror) getOnlyElement(declaredType.getTypeArguments()));
+ return Optional.of(getOnlyElement(type.getTypeArguments()));
}
}
return Optional.of(type);
diff --git a/java/dagger/internal/codegen/validation/ProvidesMethodValidator.java b/java/dagger/internal/codegen/validation/ProvidesMethodValidator.java
index 6b4f30387..509932317 100644
--- a/java/dagger/internal/codegen/validation/ProvidesMethodValidator.java
+++ b/java/dagger/internal/codegen/validation/ProvidesMethodValidator.java
@@ -21,36 +21,28 @@ import static dagger.internal.codegen.validation.BindingElementValidator.AllowsS
import static dagger.internal.codegen.validation.BindingMethodValidator.Abstractness.MUST_BE_CONCRETE;
import static dagger.internal.codegen.validation.BindingMethodValidator.ExceptionSuperclass.RUNTIME_EXCEPTION;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XVariableElement;
import com.google.common.collect.ImmutableSet;
-import dagger.Module;
-import dagger.Provides;
import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.producers.ProducerModule;
import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.VariableElement;
-/** A validator for {@link Provides} methods. */
+/** A validator for {@link dagger.Provides} methods. */
final class ProvidesMethodValidator extends BindingMethodValidator {
private final DependencyRequestValidator dependencyRequestValidator;
@Inject
ProvidesMethodValidator(
- DaggerElements elements,
DaggerTypes types,
- KotlinMetadataUtil kotlinMetadataUtil,
DependencyRequestValidator dependencyRequestValidator,
InjectionAnnotations injectionAnnotations) {
super(
- elements,
types,
- kotlinMetadataUtil,
- Provides.class,
- ImmutableSet.of(Module.class, ProducerModule.class),
+ TypeNames.PROVIDES,
+ ImmutableSet.of(TypeNames.MODULE, TypeNames.PRODUCER_MODULE),
dependencyRequestValidator,
MUST_BE_CONCRETE,
RUNTIME_EXCEPTION,
@@ -61,22 +53,18 @@ final class ProvidesMethodValidator extends BindingMethodValidator {
}
@Override
- protected ElementValidator elementValidator(ExecutableElement element) {
- return new Validator(element);
+ protected ElementValidator elementValidator(XMethodElement method) {
+ return new Validator(method);
}
private class Validator extends MethodValidator {
- Validator(ExecutableElement element) {
- super(element);
+ Validator(XMethodElement method) {
+ super(method);
}
+ /** Adds an error if a {@link dagger.Provides @Provides} method depends on a producer type. */
@Override
- protected void checkAdditionalMethodProperties() {
- }
-
- /** Adds an error if a {@link Provides @Provides} method depends on a producer type. */
- @Override
- protected void checkParameter(VariableElement parameter) {
+ protected void checkParameter(XVariableElement parameter) {
super.checkParameter(parameter);
dependencyRequestValidator.checkNotProducer(report, parameter);
}
diff --git a/java/dagger/internal/codegen/validation/SuperficialValidator.java b/java/dagger/internal/codegen/validation/SuperficialValidator.java
new file mode 100644
index 000000000..6684407e5
--- /dev/null
+++ b/java/dagger/internal/codegen/validation/SuperficialValidator.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.validation;
+
+import static dagger.internal.codegen.xprocessing.XElements.closestEnclosingTypeElement;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XTypeElement;
+import dagger.internal.codegen.base.ClearableCache;
+import dagger.internal.codegen.base.DaggerSuperficialValidation;
+import dagger.internal.codegen.base.DaggerSuperficialValidation.ValidationException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** Validates enclosing type elements in a round. */
+@Singleton
+public final class SuperficialValidator implements ClearableCache {
+
+ private final DaggerSuperficialValidation superficialValidation;
+ private final Map<XTypeElement, Optional<ValidationException>> validationExceptions =
+ new HashMap<>();
+
+ @Inject
+ SuperficialValidator(DaggerSuperficialValidation superficialValidation) {
+ this.superficialValidation = superficialValidation;
+ }
+
+ public void throwIfNearestEnclosingTypeNotValid(XElement element) {
+ Optional<ValidationException> validationException =
+ validationExceptions.computeIfAbsent(
+ closestEnclosingTypeElement(element),
+ this::validationExceptionsUncached);
+
+ if (validationException.isPresent()) {
+ throw validationException.get();
+ }
+ }
+
+ private Optional<ValidationException> validationExceptionsUncached(XTypeElement element) {
+ try {
+ superficialValidation.validateElement(element);
+ } catch (ValidationException validationException) {
+ return Optional.of(validationException);
+ }
+ return Optional.empty();
+ }
+
+ @Override
+ public void clearCache() {
+ validationExceptions.clear();
+ }
+}
diff --git a/java/dagger/internal/codegen/validation/TypeCheckingProcessingStep.java b/java/dagger/internal/codegen/validation/TypeCheckingProcessingStep.java
index 57867f13b..5b14135eb 100644
--- a/java/dagger/internal/codegen/validation/TypeCheckingProcessingStep.java
+++ b/java/dagger/internal/codegen/validation/TypeCheckingProcessingStep.java
@@ -16,52 +16,175 @@
package dagger.internal.codegen.validation;
-import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Throwables.getStackTraceAsString;
+import static com.google.common.collect.Sets.difference;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static javax.tools.Diagnostic.Kind.ERROR;
-import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XProcessingStep;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.SetMultimap;
-import java.lang.annotation.Annotation;
-import java.util.function.Function;
-import javax.lang.model.element.Element;
+import com.google.common.collect.Maps;
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.base.DaggerSuperficialValidation.ValidationException;
+import dagger.internal.codegen.compileroption.CompilerOptions;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Inject;
/**
- * A {@link ProcessingStep} that processes one element at a time and defers any for which {@link
+ * A {@link XProcessingStep} that processes one element at a time and defers any for which {@link
* TypeNotPresentException} is thrown.
*/
-// TODO(dpb): Contribute to auto-common.
-public abstract class TypeCheckingProcessingStep<E extends Element> implements ProcessingStep {
- private final Function<Element, E> downcaster;
+public abstract class TypeCheckingProcessingStep<E extends XElement> implements XProcessingStep {
- protected TypeCheckingProcessingStep(Function<Element, E> downcaster) {
- this.downcaster = checkNotNull(downcaster);
+ private final List<String> lastDeferredErrorMessages = new ArrayList<>();
+ @Inject XMessager messager;
+ @Inject CompilerOptions compilerOptions;
+ @Inject SuperficialValidator superficialValidator;
+
+ @Override
+ public final ImmutableSet<String> annotations() {
+ return annotationClassNames().stream().map(ClassName::canonicalName).collect(toImmutableSet());
}
+ @SuppressWarnings("unchecked") // Subclass must ensure all annotated targets are of valid type.
@Override
- public ImmutableSet<Element> process(
- SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
- ImmutableSet.Builder<Element> deferredElements = ImmutableSet.builder();
- ImmutableSetMultimap.copyOf(elementsByAnnotation)
- .inverse()
- .asMap()
+ public ImmutableSet<XElement> process(
+ XProcessingEnv env, Map<String, ? extends Set<? extends XElement>> elementsByAnnotation) {
+ // We only really care about the deferred error messages from the final round of processing.
+ // Thus, we can clear the values stored from the previous processing round since that clearly
+ // wasn't the final round, and we replace it with any deferred error messages from this round.
+ lastDeferredErrorMessages.clear();
+ ImmutableSet.Builder<XElement> deferredElements = ImmutableSet.builder();
+ inverse(elementsByAnnotation)
.forEach(
(element, annotations) -> {
try {
- process(downcaster.apply(element), ImmutableSet.copyOf(annotations));
+ // The XBasicAnnotationProcessor only validates the element itself. However, we
+ // validate the enclosing type here to keep the previous behavior of
+ // BasicAnnotationProcessor, since Dagger still relies on this behavior.
+ // TODO(b/201479062): It's inefficient to require validation of the entire enclosing
+ // type, we should try to remove this and handle any additional validation into the
+ // steps that need it.
+ superficialValidator.throwIfNearestEnclosingTypeNotValid(element);
+ process((E) element, annotations);
} catch (TypeNotPresentException e) {
+ // TODO(bcorso): We should be able to remove this once we replace all calls to
+ // SuperficialValidation with DaggerSuperficialValidation.
+ deferredElements.add(element);
+ cacheErrorMessage(typeNotPresentErrorMessage(element, e), e);
+ } catch (ValidationException.UnexpectedException unexpectedException) {
+ // Rethrow since the exception was created from an unexpected throwable so
+ // deferring to another round is unlikely to help.
+ throw unexpectedException;
+ } catch (ValidationException.KnownErrorType e) {
deferredElements.add(element);
+ cacheErrorMessage(knownErrorTypeErrorMessage(element, e), e);
+ } catch (ValidationException.UnknownErrorType e) {
+ deferredElements.add(element);
+ cacheErrorMessage(unknownErrorTypeErrorMessage(element, e), e);
}
});
return deferredElements.build();
}
+ @Override
+ public void processOver(
+ XProcessingEnv env, Map<String, ? extends Set<? extends XElement>> elementsByAnnotation) {
+ // We avoid doing any actual processing here since this is run in the same round as the last
+ // call to process(). Instead, we just report the last deferred error messages, if any.
+ lastDeferredErrorMessages.forEach(errorMessage -> messager.printMessage(ERROR, errorMessage));
+ lastDeferredErrorMessages.clear();
+ }
+
+ private void cacheErrorMessage(String errorMessage, Exception exception) {
+ lastDeferredErrorMessages.add(
+ compilerOptions.includeStacktraceWithDeferredErrorMessages()
+ ? String.format("%s\n\n%s", errorMessage, getStackTraceAsString(exception))
+ : errorMessage);
+ }
+
+ private String typeNotPresentErrorMessage(XElement element, TypeNotPresentException exception) {
+ return String.format(
+ "%1$s was unable to process '%2$s' because '%3$s' could not be resolved."
+ + "\n"
+ + "\nIf type '%3$s' is a generated type, check above for compilation errors that may "
+ + "have prevented the type from being generated. Otherwise, ensure that type '%3$s' is "
+ + "on your classpath.",
+ this.getClass().getSimpleName(),
+ element,
+ exception.typeName());
+ }
+
+ private String knownErrorTypeErrorMessage(
+ XElement element, ValidationException.KnownErrorType exception) {
+ return String.format(
+ "%1$s was unable to process '%2$s' because '%3$s' could not be resolved."
+ + "\n"
+ + "\nDependency trace:"
+ + "\n => %4$s"
+ + "\n"
+ + "\nIf type '%3$s' is a generated type, check above for compilation errors that may "
+ + "have prevented the type from being generated. Otherwise, ensure that type '%3$s' is "
+ + "on your classpath.",
+ this.getClass().getSimpleName(),
+ element,
+ exception.getErrorTypeName(),
+ exception.getTrace());
+ }
+
+ private String unknownErrorTypeErrorMessage(
+ XElement element, ValidationException.UnknownErrorType exception) {
+ return String.format(
+ "%1$s was unable to process '%2$s' because one of its dependencies could not be resolved."
+ + "\n"
+ + "\nDependency trace:"
+ + "\n => %3$s"
+ + "\n"
+ + "\nIf the dependency is a generated type, check above for compilation errors that may"
+ + " have prevented the type from being generated. Otherwise, ensure that the dependency"
+ + " is on your classpath.",
+ this.getClass().getSimpleName(), element, exception.getTrace());
+ }
+
/**
* Processes one element. If this method throws {@link TypeNotPresentException}, the element will
* be deferred until the next round of processing.
*
- * @param annotations the subset of {@link ProcessingStep#annotations()} that annotate {@code
+ * @param annotations the subset of {@link XProcessingStep#annotations()} that annotate {@code
* element}
*/
- protected abstract void process(E element, ImmutableSet<Class<? extends Annotation>> annotations);
+ protected abstract void process(E element, ImmutableSet<ClassName> annotations);
+
+ private ImmutableMap<XElement, ImmutableSet<ClassName>> inverse(
+ Map<String, ? extends Set<? extends XElement>> elementsByAnnotation) {
+ ImmutableMap<String, ClassName> annotationClassNames =
+ annotationClassNames().stream()
+ .collect(toImmutableMap(ClassName::canonicalName, className -> className));
+ checkState(
+ annotationClassNames.keySet().containsAll(elementsByAnnotation.keySet()),
+ "Unexpected annotations for %s: %s",
+ this.getClass().getCanonicalName(),
+ difference(elementsByAnnotation.keySet(), annotationClassNames.keySet()));
+
+ ImmutableSetMultimap.Builder<XElement, ClassName> builder = ImmutableSetMultimap.builder();
+ elementsByAnnotation.forEach(
+ (annotationName, elementSet) ->
+ elementSet.forEach(
+ element -> builder.put(element, annotationClassNames.get(annotationName))));
+
+ return ImmutableMap.copyOf(Maps.transformValues(builder.build().asMap(), ImmutableSet::copyOf));
+ }
+
+ /** Returns the set of annotations processed by this processing step. */
+ protected abstract Set<ClassName> annotationClassNames();
}
diff --git a/java/dagger/internal/codegen/validation/TypeHierarchyValidator.java b/java/dagger/internal/codegen/validation/TypeHierarchyValidator.java
deleted file mode 100644
index 5fa02707a..000000000
--- a/java/dagger/internal/codegen/validation/TypeHierarchyValidator.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.validation;
-
-import com.google.auto.common.MoreTypes;
-import com.google.auto.common.SuperficialValidation;
-import com.google.common.base.Equivalence;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.util.ArrayDeque;
-import java.util.HashSet;
-import java.util.Queue;
-import java.util.Set;
-import javax.lang.model.type.TypeMirror;
-
-/** Utility methods for validating the type hierarchy of a given type. */
-final class TypeHierarchyValidator {
- private TypeHierarchyValidator() {}
-
- /**
- * Validate the type hierarchy of the given type including all super classes, interfaces, and
- * type parameters.
- *
- * @throws TypeNotPresentException if an type in the hierarchy is not valid.
- */
- public static void validateTypeHierarchy(TypeMirror type, DaggerTypes types) {
- Queue<TypeMirror> queue = new ArrayDeque<>();
- Set<Equivalence.Wrapper<TypeMirror>> queued = new HashSet<>();
- queue.add(type);
- queued.add(MoreTypes.equivalence().wrap(type));
- while (!queue.isEmpty()) {
- TypeMirror currType = queue.remove();
- if (!SuperficialValidation.validateType(currType)) {
- throw new TypeNotPresentException(currType.toString(), null);
- }
- for (TypeMirror superType : types.directSupertypes(currType)) {
- if (queued.add(MoreTypes.equivalence().wrap(superType))) {
- queue.add(superType);
- }
- }
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/Validation.java b/java/dagger/internal/codegen/validation/Validation.java
index 620b0f041..6d7315109 100644
--- a/java/dagger/internal/codegen/validation/Validation.java
+++ b/java/dagger/internal/codegen/validation/Validation.java
@@ -22,8 +22,8 @@ import java.lang.annotation.RetentionPolicy;
import javax.inject.Qualifier;
/**
- * Qualifier annotation for the {@link dagger.spi.BindingGraphPlugin}s that are used to implement
- * core Dagger validation.
+ * Qualifier annotation for the {@link dagger.spi.model.BindingGraphPlugin}s that are used to
+ * implement core Dagger validation.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/java/dagger/internal/codegen/validation/ValidationBindingGraphPlugins.java b/java/dagger/internal/codegen/validation/ValidationBindingGraphPlugins.java
new file mode 100644
index 000000000..0a43d874a
--- /dev/null
+++ b/java/dagger/internal/codegen/validation/ValidationBindingGraphPlugins.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.validation;
+
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.compat.XConverters;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.compileroption.ProcessingOptions;
+import dagger.internal.codegen.compileroption.ValidationType;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.validation.DiagnosticReporterFactory.DiagnosticReporterImpl;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraphPlugin;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Inject;
+
+/** Initializes {@link BindingGraphPlugin}s. */
+public final class ValidationBindingGraphPlugins {
+ private final ImmutableSet<BindingGraphPlugin> plugins;
+ private final DiagnosticReporterFactory diagnosticReporterFactory;
+ private final XFiler filer;
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+ private final CompilerOptions compilerOptions;
+ private final Map<String, String> processingOptions;
+
+ @Inject
+ ValidationBindingGraphPlugins(
+ @Validation ImmutableSet<BindingGraphPlugin> plugins,
+ DiagnosticReporterFactory diagnosticReporterFactory,
+ XFiler filer,
+ DaggerTypes types,
+ DaggerElements elements,
+ CompilerOptions compilerOptions,
+ @ProcessingOptions Map<String, String> processingOptions) {
+ this.plugins = plugins;
+ this.diagnosticReporterFactory = diagnosticReporterFactory;
+ this.filer = filer;
+ this.types = types;
+ this.elements = elements;
+ this.compilerOptions = compilerOptions;
+ this.processingOptions = processingOptions;
+ }
+
+ /** Returns {@link BindingGraphPlugin#supportedOptions()} from all the plugins. */
+ public ImmutableSet<String> allSupportedOptions() {
+ return plugins.stream()
+ .flatMap(plugin -> plugin.supportedOptions().stream())
+ .collect(toImmutableSet());
+ }
+
+ /** Initializes the plugins. */
+ // TODO(ronshapiro): Should we validate the uniqueness of plugin names?
+ public void initializePlugins() {
+ plugins.forEach(this::initializePlugin);
+ }
+
+ private void initializePlugin(BindingGraphPlugin plugin) {
+ plugin.initFiler(XConverters.toJavac(filer));
+ plugin.initTypes(types);
+ plugin.initElements(elements);
+ Set<String> supportedOptions = plugin.supportedOptions();
+ if (!supportedOptions.isEmpty()) {
+ plugin.initOptions(Maps.filterKeys(processingOptions, supportedOptions::contains));
+ }
+ }
+
+ /** Returns {@code false} if any of the plugins reported an error. */
+ boolean visit(BindingGraph graph) {
+ boolean errorsAsWarnings =
+ graph.isFullBindingGraph()
+ && compilerOptions.fullBindingGraphValidationType().equals(ValidationType.WARNING);
+
+ boolean isClean = true;
+ for (BindingGraphPlugin plugin : plugins) {
+ DiagnosticReporterImpl reporter =
+ diagnosticReporterFactory.reporter(graph, plugin.pluginName(), errorsAsWarnings);
+ plugin.visitGraph(graph, reporter);
+ if (reporter.reportedDiagnosticKinds().contains(ERROR)) {
+ isClean = false;
+ }
+ }
+ return isClean;
+ }
+}
diff --git a/java/dagger/internal/codegen/validation/ValidationReport.java b/java/dagger/internal/codegen/validation/ValidationReport.java
index 7f3737595..f9049cd50 100644
--- a/java/dagger/internal/codegen/validation/ValidationReport.java
+++ b/java/dagger/internal/codegen/validation/ValidationReport.java
@@ -18,38 +18,39 @@ package dagger.internal.codegen.validation;
import static dagger.internal.codegen.base.ElementFormatter.elementToString;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.langmodel.DaggerElements.transitivelyEncloses;
import static javax.tools.Diagnostic.Kind.ERROR;
import static javax.tools.Diagnostic.Kind.NOTE;
import static javax.tools.Diagnostic.Kind.WARNING;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XAnnotationValue;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XMessager;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableSet;
import com.google.common.graph.Traverser;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.CheckReturnValue;
import java.util.Optional;
-import javax.annotation.processing.Messager;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.Element;
import javax.tools.Diagnostic;
import javax.tools.Diagnostic.Kind;
/** A collection of issues to report for source code. */
-public final class ValidationReport<T extends Element> {
- private static final Traverser<ValidationReport<?>> SUBREPORTS =
+public final class ValidationReport {
+ private static final Traverser<ValidationReport> SUBREPORTS =
Traverser.forTree(report -> report.subreports);
- private final T subject;
+ private final XElement subject;
private final ImmutableSet<Item> items;
- private final ImmutableSet<ValidationReport<?>> subreports;
+ private final ImmutableSet<ValidationReport> subreports;
private final boolean markedDirty;
private boolean hasPrintedErrors;
private ValidationReport(
- T subject,
+ XElement subject,
ImmutableSet<Item> items,
- ImmutableSet<ValidationReport<?>> subreports,
+ ImmutableSet<ValidationReport> subreports,
boolean markedDirty) {
this.subject = subject;
this.items = items;
@@ -81,7 +82,7 @@ public final class ValidationReport<T extends Element> {
break;
}
}
- for (ValidationReport<?> subreport : subreports) {
+ for (ValidationReport subreport : subreports) {
if (!subreport.isClean()) {
return false;
}
@@ -90,20 +91,20 @@ public final class ValidationReport<T extends Element> {
}
/**
- * Prints all messages to {@code messager} (and recurs for subreports). If a
- * message's {@linkplain Item#element() element} is contained within the report's subject,
- * associates the message with the message's element. Otherwise, since {@link Diagnostic}
- * reporting is expected to be associated with elements that are currently being compiled,
- * associates the message with the subject itself and prepends a reference to the item's element.
+ * Prints all messages to {@code messager} (and recurs for subreports). If a message's {@linkplain
+ * Item#element() element} is contained within the report's subject, associates the message with
+ * the message's element. Otherwise, since {@link Diagnostic} reporting is expected to be
+ * associated with elements that are currently being compiled, associates the message with the
+ * subject itself and prepends a reference to the item's element.
*/
- public void printMessagesTo(Messager messager) {
+ public void printMessagesTo(XMessager messager) {
if (hasPrintedErrors) {
// Avoid printing the errors from this validation report more than once.
return;
}
hasPrintedErrors = true;
for (Item item : items) {
- if (isEnclosedIn(subject, item.element())) {
+ if (transitivelyEncloses(subject, item.element())) {
if (item.annotation().isPresent()) {
if (item.annotationValue().isPresent()) {
messager.printMessage(
@@ -124,143 +125,132 @@ public final class ValidationReport<T extends Element> {
messager.printMessage(item.kind(), message, subject);
}
}
- for (ValidationReport<?> subreport : subreports) {
+ for (ValidationReport subreport : subreports) {
subreport.printMessagesTo(messager);
}
}
- private static boolean isEnclosedIn(Element parent, Element child) {
- Element current = child;
- while (current != null) {
- if (current.equals(parent)) {
- return true;
- }
- current = current.getEnclosingElement();
- }
- return false;
- }
-
/** Metadata about a {@link ValidationReport} item. */
@AutoValue
public abstract static class Item {
public abstract String message();
public abstract Kind kind();
- public abstract Element element();
- public abstract Optional<AnnotationMirror> annotation();
- abstract Optional<AnnotationValue> annotationValue();
+ public abstract XElement element();
+ public abstract Optional<XAnnotation> annotation();
+ abstract Optional<XAnnotationValue> annotationValue();
}
- public static <T extends Element> Builder<T> about(T subject) {
- return new Builder<>(subject);
+ public static Builder about(XElement subject) {
+ return new Builder(subject);
}
/** A {@link ValidationReport} builder. */
@CanIgnoreReturnValue
- public static final class Builder<T extends Element> {
- private final T subject;
+ public static final class Builder {
+ private final XElement subject;
private final ImmutableSet.Builder<Item> items = ImmutableSet.builder();
- private final ImmutableSet.Builder<ValidationReport<?>> subreports = ImmutableSet.builder();
+ private final ImmutableSet.Builder<ValidationReport> subreports = ImmutableSet.builder();
private boolean markedDirty;
- private Builder(T subject) {
+ private Builder(XElement subject) {
this.subject = subject;
}
- @CheckReturnValue
- T getSubject() {
- return subject;
- }
-
- Builder<T> addItems(Iterable<Item> newItems) {
+ Builder addItems(Iterable<Item> newItems) {
items.addAll(newItems);
return this;
}
- public Builder<T> addError(String message) {
+ public Builder addError(String message) {
return addError(message, subject);
}
- public Builder<T> addError(String message, Element element) {
+ public Builder addError(String message, XElement element) {
return addItem(message, ERROR, element);
}
- public Builder<T> addError(String message, Element element, AnnotationMirror annotation) {
+ public Builder addError(String message, XElement element, XAnnotation annotation) {
return addItem(message, ERROR, element, annotation);
}
- public Builder<T> addError(
+ public Builder addError(
String message,
- Element element,
- AnnotationMirror annotation,
- AnnotationValue annotationValue) {
+ XElement element,
+ XAnnotation annotation,
+ XAnnotationValue annotationValue) {
return addItem(message, ERROR, element, annotation, annotationValue);
}
- Builder<T> addWarning(String message) {
+ Builder addWarning(String message) {
return addWarning(message, subject);
}
- Builder<T> addWarning(String message, Element element) {
+ Builder addWarning(String message, XElement element) {
return addItem(message, WARNING, element);
}
- Builder<T> addWarning(String message, Element element, AnnotationMirror annotation) {
+ Builder addWarning(String message, XElement element, XAnnotation annotation) {
return addItem(message, WARNING, element, annotation);
}
- Builder<T> addWarning(
+ Builder addWarning(
String message,
- Element element,
- AnnotationMirror annotation,
- AnnotationValue annotationValue) {
+ XElement element,
+ XAnnotation annotation,
+ XAnnotationValue annotationValue) {
return addItem(message, WARNING, element, annotation, annotationValue);
}
- Builder<T> addNote(String message) {
+ Builder addNote(String message) {
return addNote(message, subject);
}
- Builder<T> addNote(String message, Element element) {
+ Builder addNote(String message, XElement element) {
return addItem(message, NOTE, element);
}
- Builder<T> addNote(String message, Element element, AnnotationMirror annotation) {
+ Builder addNote(String message, XElement element, XAnnotation annotation) {
return addItem(message, NOTE, element, annotation);
}
- Builder<T> addNote(
+ Builder addNote(
String message,
- Element element,
- AnnotationMirror annotation,
- AnnotationValue annotationValue) {
+ XElement element,
+ XAnnotation annotation,
+ XAnnotationValue annotationValue) {
return addItem(message, NOTE, element, annotation, annotationValue);
}
- Builder<T> addItem(String message, Kind kind, Element element) {
+ Builder addItem(String message, Kind kind, XElement element) {
return addItem(message, kind, element, Optional.empty(), Optional.empty());
}
- Builder<T> addItem(String message, Kind kind, Element element, AnnotationMirror annotation) {
+ Builder addItem(String message, Kind kind, XElement element, XAnnotation annotation) {
return addItem(message, kind, element, Optional.of(annotation), Optional.empty());
}
- Builder<T> addItem(
+ Builder addItem(
String message,
Kind kind,
- Element element,
- AnnotationMirror annotation,
- AnnotationValue annotationValue) {
+ XElement element,
+ XAnnotation annotation,
+ XAnnotationValue annotationValue) {
return addItem(message, kind, element, Optional.of(annotation), Optional.of(annotationValue));
}
- private Builder<T> addItem(
+ private Builder addItem(
String message,
Kind kind,
- Element element,
- Optional<AnnotationMirror> annotation,
- Optional<AnnotationValue> annotationValue) {
+ XElement element,
+ Optional<XAnnotation> annotation,
+ Optional<XAnnotationValue> annotationValue) {
items.add(
- new AutoValue_ValidationReport_Item(message, kind, element, annotation, annotationValue));
+ new AutoValue_ValidationReport_Item(
+ message,
+ kind,
+ element,
+ annotation,
+ annotationValue));
return this;
}
@@ -272,14 +262,14 @@ public final class ValidationReport<T extends Element> {
this.markedDirty = true;
}
- public Builder<T> addSubreport(ValidationReport<?> subreport) {
+ public Builder addSubreport(ValidationReport subreport) {
subreports.add(subreport);
return this;
}
@CheckReturnValue
- public ValidationReport<T> build() {
- return new ValidationReport<>(subject, items.build(), subreports.build(), markedDirty);
+ public ValidationReport build() {
+ return new ValidationReport(subject, items.build(), subreports.build(), markedDirty);
}
}
}
diff --git a/java/dagger/internal/codegen/writing/AnnotationCreatorGenerator.java b/java/dagger/internal/codegen/writing/AnnotationCreatorGenerator.java
index fa3a16cac..a0699f19f 100644
--- a/java/dagger/internal/codegen/writing/AnnotationCreatorGenerator.java
+++ b/java/dagger/internal/codegen/writing/AnnotationCreatorGenerator.java
@@ -22,13 +22,17 @@ import static com.squareup.javapoet.TypeSpec.classBuilder;
import static dagger.internal.codegen.binding.AnnotationExpression.createMethodName;
import static dagger.internal.codegen.binding.AnnotationExpression.getAnnotationCreatorClassName;
import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.compat.XConverters;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.squareup.javapoet.ClassName;
@@ -40,15 +44,8 @@ import dagger.internal.codegen.base.SourceFileGenerator;
import dagger.internal.codegen.langmodel.DaggerElements;
import java.util.LinkedHashSet;
import java.util.Set;
-import javax.annotation.processing.Filer;
import javax.inject.Inject;
import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.util.SimpleTypeVisitor6;
/**
* Generates classes that create annotation instances for an annotation type. The generated class
@@ -77,47 +74,49 @@ import javax.lang.model.util.SimpleTypeVisitor6;
* }
* </pre>
*/
-public class AnnotationCreatorGenerator extends SourceFileGenerator<TypeElement> {
+public class AnnotationCreatorGenerator extends SourceFileGenerator<XTypeElement> {
private static final ClassName AUTO_ANNOTATION =
ClassName.get("com.google.auto.value", "AutoAnnotation");
@Inject
- AnnotationCreatorGenerator(Filer filer, DaggerElements elements, SourceVersion sourceVersion) {
+ AnnotationCreatorGenerator(XFiler filer, DaggerElements elements, SourceVersion sourceVersion) {
super(filer, elements, sourceVersion);
}
@Override
- public Element originatingElement(TypeElement annotationType) {
+ public XElement originatingElement(XTypeElement annotationType) {
return annotationType;
}
@Override
- public ImmutableList<TypeSpec.Builder> topLevelTypes(TypeElement annotationType) {
- ClassName generatedTypeName = getAnnotationCreatorClassName(annotationType);
+ public ImmutableList<TypeSpec.Builder> topLevelTypes(XTypeElement annotationType) {
+ ClassName generatedTypeName =
+ getAnnotationCreatorClassName(XConverters.toJavac(annotationType));
TypeSpec.Builder annotationCreatorBuilder =
classBuilder(generatedTypeName)
.addModifiers(PUBLIC, FINAL)
.addMethod(constructorBuilder().addModifiers(PRIVATE).build());
- for (TypeElement annotationElement : annotationsToCreate(annotationType)) {
+ for (XTypeElement annotationElement : annotationsToCreate(annotationType)) {
annotationCreatorBuilder.addMethod(buildCreateMethod(generatedTypeName, annotationElement));
}
return ImmutableList.of(annotationCreatorBuilder);
}
- private MethodSpec buildCreateMethod(ClassName generatedTypeName, TypeElement annotationElement) {
- String createMethodName = createMethodName(annotationElement);
+ private MethodSpec buildCreateMethod(
+ ClassName generatedTypeName, XTypeElement annotationElement) {
+ String createMethodName = createMethodName(XConverters.toJavac(annotationElement));
MethodSpec.Builder createMethod =
methodBuilder(createMethodName)
.addAnnotation(AUTO_ANNOTATION)
.addModifiers(PUBLIC, STATIC)
- .returns(TypeName.get(annotationElement.asType()));
+ .returns(annotationElement.getType().getTypeName());
ImmutableList.Builder<CodeBlock> parameters = ImmutableList.builder();
- for (ExecutableElement annotationMember : methodsIn(annotationElement.getEnclosedElements())) {
- String parameterName = annotationMember.getSimpleName().toString();
- TypeName parameterType = TypeName.get(annotationMember.getReturnType());
+ for (XMethodElement annotationMember : annotationElement.getDeclaredMethods()) {
+ String parameterName = getSimpleName(annotationMember);
+ TypeName parameterType = annotationMember.getReturnType().getTypeName();
createMethod.addParameter(parameterType, parameterName);
parameters.add(CodeBlock.of("$L", parameterName));
}
@@ -134,30 +133,23 @@ public class AnnotationCreatorGenerator extends SourceFileGenerator<TypeElement>
* Returns the annotation types for which {@code @AutoAnnotation static Foo createFoo(…)} methods
* should be written.
*/
- protected Set<TypeElement> annotationsToCreate(TypeElement annotationElement) {
+ protected Set<XTypeElement> annotationsToCreate(XTypeElement annotationElement) {
return nestedAnnotationElements(annotationElement, new LinkedHashSet<>());
}
@CanIgnoreReturnValue
- private static Set<TypeElement> nestedAnnotationElements(
- TypeElement annotationElement, Set<TypeElement> annotationElements) {
+ private static Set<XTypeElement> nestedAnnotationElements(
+ XTypeElement annotationElement, Set<XTypeElement> annotationElements) {
if (annotationElements.add(annotationElement)) {
- for (ExecutableElement method : methodsIn(annotationElement.getEnclosedElements())) {
- TRAVERSE_NESTED_ANNOTATIONS.visit(method.getReturnType(), annotationElements);
+ for (XMethodElement method : annotationElement.getDeclaredMethods()) {
+ XTypeElement returnType = method.getReturnType().getTypeElement();
+ // Return type may be null if it doesn't return a type or type is not known
+ if (returnType != null && returnType.isAnnotationClass()) {
+ // Ignore the return value since this method is just an accumulator method.
+ nestedAnnotationElements(returnType, annotationElements);
+ }
}
}
return annotationElements;
}
-
- private static final SimpleTypeVisitor6<Void, Set<TypeElement>> TRAVERSE_NESTED_ANNOTATIONS =
- new SimpleTypeVisitor6<Void, Set<TypeElement>>() {
- @Override
- public Void visitDeclared(DeclaredType t, Set<TypeElement> p) {
- TypeElement typeElement = MoreTypes.asTypeElement(t);
- if (typeElement.getKind() == ElementKind.ANNOTATION_TYPE) {
- nestedAnnotationElements(typeElement, p);
- }
- return null;
- }
- };
}
diff --git a/java/dagger/internal/codegen/writing/AnonymousProviderCreationExpression.java b/java/dagger/internal/codegen/writing/AnonymousProviderCreationExpression.java
index b1237ca75..7256fd6a6 100644
--- a/java/dagger/internal/codegen/writing/AnonymousProviderCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/AnonymousProviderCreationExpression.java
@@ -16,12 +16,16 @@
package dagger.internal.codegen.writing;
+import static com.google.common.base.Preconditions.checkNotNull;
import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import static dagger.internal.codegen.javapoet.CodeBlocks.anonymousProvider;
-import static dagger.model.RequestKind.INSTANCE;
+import static dagger.spi.model.RequestKind.INSTANCE;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.BindingRequest;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.javapoet.Expression;
@@ -34,27 +38,33 @@ import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstan
final class AnonymousProviderCreationExpression
implements FrameworkInstanceCreationExpression {
private final ContributionBinding binding;
- private final ComponentBindingExpressions componentBindingExpressions;
+ private final ComponentRequestRepresentations componentRequestRepresentations;
private final ClassName requestingClass;
+ @AssistedInject
AnonymousProviderCreationExpression(
- ContributionBinding binding,
- ComponentBindingExpressions componentBindingExpressions,
- ClassName requestingClass) {
- this.binding = binding;
- this.componentBindingExpressions = componentBindingExpressions;
- this.requestingClass = requestingClass;
+ @Assisted ContributionBinding binding,
+ ComponentRequestRepresentations componentRequestRepresentations,
+ ComponentImplementation componentImplementation) {
+ this.binding = checkNotNull(binding);
+ this.componentRequestRepresentations = componentRequestRepresentations;
+ this.requestingClass = componentImplementation.name();
}
@Override
public CodeBlock creationExpression() {
BindingRequest instanceExpressionRequest = bindingRequest(binding.key(), INSTANCE);
Expression instanceExpression =
- componentBindingExpressions.getDependencyExpression(
+ componentRequestRepresentations.getDependencyExpression(
instanceExpressionRequest,
// Not a real class name, but the actual requestingClass is an inner class within the
// given class, not that class itself.
requestingClass.nestedClass("Anonymous"));
return anonymousProvider(instanceExpression);
}
+
+ @AssistedFactory
+ static interface Factory {
+ AnonymousProviderCreationExpression create(ContributionBinding binding);
+ }
}
diff --git a/java/dagger/internal/codegen/writing/AssistedFactoryBindingExpression.java b/java/dagger/internal/codegen/writing/AssistedFactoryBindingExpression.java
deleted file mode 100644
index d90ab71f1..000000000
--- a/java/dagger/internal/codegen/writing/AssistedFactoryBindingExpression.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedFactoryMethod;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedFactoryParameterSpecs;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import dagger.model.RequestKind;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-
-/**
- * A {@link dagger.internal.codegen.writing.BindingExpression} for {@link
- * dagger.assisted.AssistedFactory} methods.
- */
-final class AssistedFactoryBindingExpression extends SimpleInvocationBindingExpression {
- private final ProvisionBinding binding;
- private final ComponentBindingExpressions componentBindingExpressions;
- private final DaggerElements elements;
- private final DaggerTypes types;
-
- AssistedFactoryBindingExpression(
- ProvisionBinding binding,
- ComponentBindingExpressions componentBindingExpressions,
- DaggerTypes types,
- DaggerElements elements) {
- super(binding);
- this.binding = checkNotNull(binding);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
- this.elements = checkNotNull(elements);
- this.types = checkNotNull(types);
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- // An assisted factory binding should have a single request for an assisted injection type.
- DependencyRequest assistedInjectionRequest = getOnlyElement(binding.provisionDependencies());
- Expression assistedInjectionExpression =
- componentBindingExpressions.getDependencyExpression(
- BindingRequest.bindingRequest(assistedInjectionRequest.key(), RequestKind.INSTANCE),
- // This is kind of gross because the anonymous class doesn't really have a name we can
- // reference. The requesting class name is really only needed to determine if we need to
- // append "OwningClass.this." to the method call or not.
- // TODO(bcorso): We should probably use a non-anonymous class here instead so that we
- // actually have a proper class name.
- requestingClass.peerClass(""));
- return Expression.create(
- assistedInjectionExpression.type(),
- CodeBlock.of("$L", anonymousfactoryImpl(assistedInjectionExpression)));
- }
-
- private TypeSpec anonymousfactoryImpl(Expression assistedInjectionExpression) {
- TypeElement factory = asType(binding.bindingElement().get());
- DeclaredType factoryType = asDeclared(binding.key().type());
- ExecutableElement factoryMethod = assistedFactoryMethod(factory, elements);
-
- // We can't use MethodSpec.overriding directly because we need to control the parameter names.
- MethodSpec factoryOverride = MethodSpec.overriding(factoryMethod, factoryType, types).build();
- TypeSpec.Builder builder =
- TypeSpec.anonymousClassBuilder("")
- .addMethod(
- MethodSpec.methodBuilder(factoryMethod.getSimpleName().toString())
- .addModifiers(factoryOverride.modifiers)
- .addTypeVariables(factoryOverride.typeVariables)
- .returns(factoryOverride.returnType)
- .addAnnotations(factoryOverride.annotations)
- .addExceptions(factoryOverride.exceptions)
- .addParameters(assistedFactoryParameterSpecs(binding, elements, types))
- .addStatement("return $L", assistedInjectionExpression.codeBlock())
- .build());
-
- if (factory.getKind() == ElementKind.INTERFACE) {
- builder.addSuperinterface(TypeName.get(factoryType));
- } else {
- builder.superclass(TypeName.get(factoryType));
- }
-
- return builder.build();
- }
-}
diff --git a/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java b/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java
new file mode 100644
index 000000000..485774ee8
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2020 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedFactoryMethod;
+import static dagger.internal.codegen.writing.AssistedInjectionParameters.assistedFactoryParameterSpecs;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeSpec;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.binding.Binding;
+import dagger.internal.codegen.binding.BindingGraph;
+import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.xprocessing.MethodSpecs;
+import dagger.spi.model.DependencyRequest;
+import java.util.Optional;
+
+/**
+ * A {@link dagger.internal.codegen.writing.RequestRepresentation} for {@link
+ * dagger.assisted.AssistedFactory} methods.
+ */
+final class AssistedFactoryRequestRepresentation extends RequestRepresentation {
+ private final ProvisionBinding binding;
+ private final BindingGraph graph;
+ private final SimpleMethodRequestRepresentation.Factory simpleMethodRequestRepresentationFactory;
+ private final ComponentImplementation componentImplementation;
+
+ @AssistedInject
+ AssistedFactoryRequestRepresentation(
+ @Assisted ProvisionBinding binding,
+ BindingGraph graph,
+ ComponentImplementation componentImplementation,
+ SimpleMethodRequestRepresentation.Factory simpleMethodRequestRepresentationFactory) {
+ this.binding = checkNotNull(binding);
+ this.graph = graph;
+ this.componentImplementation = componentImplementation;
+ this.simpleMethodRequestRepresentationFactory = simpleMethodRequestRepresentationFactory;
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ // An assisted factory binding should have a single request for an assisted injection type.
+ DependencyRequest assistedInjectionRequest = getOnlyElement(binding.provisionDependencies());
+ // Get corresponding assisted injection binding.
+ Optional<Binding> localBinding = graph.localContributionBinding(assistedInjectionRequest.key());
+ checkArgument(
+ localBinding.isPresent(),
+ "assisted factory should have a dependency on an assisted injection binding");
+ Expression assistedInjectionExpression =
+ simpleMethodRequestRepresentationFactory
+ .create((ProvisionBinding) localBinding.get())
+ .getDependencyExpression(requestingClass.peerClass(""));
+ return Expression.create(
+ assistedInjectionExpression.type(),
+ CodeBlock.of("$L", anonymousfactoryImpl(localBinding.get(), assistedInjectionExpression)));
+ }
+
+ private TypeSpec anonymousfactoryImpl(
+ Binding assistedBinding, Expression assistedInjectionExpression) {
+ XTypeElement factory = asTypeElement(binding.bindingElement().get());
+ XType factoryType = binding.key().type().xprocessing();
+ XMethodElement factoryMethod = assistedFactoryMethod(factory);
+
+ // We can't use MethodSpec.overriding directly because we need to control the parameter names.
+ MethodSpec factoryOverride = MethodSpecs.overriding(factoryMethod, factoryType).build();
+ TypeSpec.Builder builder =
+ TypeSpec.anonymousClassBuilder("")
+ .addMethod(
+ MethodSpec.methodBuilder(getSimpleName(factoryMethod))
+ .addModifiers(factoryOverride.modifiers)
+ .addTypeVariables(factoryOverride.typeVariables)
+ .returns(factoryOverride.returnType)
+ .addAnnotations(factoryOverride.annotations)
+ .addExceptions(factoryOverride.exceptions)
+ .addParameters(
+ assistedFactoryParameterSpecs(
+ binding, componentImplementation.shardImplementation(assistedBinding)))
+ .addStatement("return $L", assistedInjectionExpression.codeBlock())
+ .build());
+
+ if (factory.isInterface()) {
+ builder.addSuperinterface(factoryType.getTypeName());
+ } else {
+ builder.superclass(factoryType.getTypeName());
+ }
+
+ return builder.build();
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ AssistedFactoryRequestRepresentation create(ProvisionBinding binding);
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java b/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java
new file mode 100644
index 000000000..9e55e031d
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.xprocessing.XElements.asConstructor;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XConstructorType;
+import androidx.room.compiler.processing.XMethodType;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.XVariableElement;
+import com.google.common.collect.ImmutableList;
+import com.squareup.javapoet.ParameterSpec;
+import dagger.internal.codegen.binding.AssistedInjectionAnnotations;
+import dagger.internal.codegen.binding.AssistedInjectionAnnotations.AssistedFactoryMetadata;
+import dagger.internal.codegen.binding.Binding;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
+import dagger.spi.model.BindingKind;
+import java.util.List;
+
+/** Utility class for generating unique assisted parameter names for a component shard. */
+final class AssistedInjectionParameters {
+ /**
+ * Returns the list of assisted factory parameters as {@link ParameterSpec}s.
+ *
+ * <p>The type of each parameter will be the resolved type given by the binding key, and the name
+ * of each parameter will be the name given in the {@link
+ * dagger.assisted.AssistedInject}-annotated constructor.
+ */
+ public static ImmutableList<ParameterSpec> assistedFactoryParameterSpecs(
+ Binding binding, ShardImplementation shardImplementation) {
+ checkArgument(binding.kind() == BindingKind.ASSISTED_FACTORY);
+ XTypeElement factory = asTypeElement(binding.bindingElement().get());
+ AssistedFactoryMetadata metadata = AssistedFactoryMetadata.create(factory.getType());
+ XMethodType factoryMethodType =
+ metadata.factoryMethod().asMemberOf(binding.key().type().xprocessing());
+ return assistedParameterSpecs(
+ // Use the order of the parameters from the @AssistedFactory method but use the parameter
+ // names of the @AssistedInject constructor.
+ metadata.assistedFactoryAssistedParameters().stream()
+ .map(metadata.assistedInjectAssistedParametersMap()::get)
+ .collect(toImmutableList()),
+ factoryMethodType.getParameterTypes(),
+ shardImplementation);
+ }
+
+ /**
+ * Returns the list of assisted parameters as {@link ParameterSpec}s.
+ *
+ * <p>The type of each parameter will be the resolved type given by the binding key, and the name
+ * of each parameter will be the name given in the {@link
+ * dagger.assisted.AssistedInject}-annotated constructor.
+ */
+ public static ImmutableList<ParameterSpec> assistedParameterSpecs(
+ Binding binding, ShardImplementation shardImplementation) {
+ checkArgument(binding.kind() == BindingKind.ASSISTED_INJECTION);
+ XConstructorElement constructor = asConstructor(binding.bindingElement().get());
+ XConstructorType constructorType = constructor.asMemberOf(binding.key().type().xprocessing());
+ return assistedParameterSpecs(
+ constructor.getParameters(), constructorType.getParameterTypes(), shardImplementation);
+ }
+
+ private static ImmutableList<ParameterSpec> assistedParameterSpecs(
+ List<? extends XVariableElement> paramElements,
+ List<XType> paramTypes,
+ ShardImplementation shardImplementation) {
+ ImmutableList.Builder<ParameterSpec> assistedParameterSpecs = ImmutableList.builder();
+ for (int i = 0; i < paramElements.size(); i++) {
+ XVariableElement paramElement = paramElements.get(i);
+ XType paramType = paramTypes.get(i);
+ if (AssistedInjectionAnnotations.isAssistedParameter(paramElement)) {
+ assistedParameterSpecs.add(
+ ParameterSpec.builder(
+ paramType.getTypeName(),
+ shardImplementation.getUniqueFieldNameForAssistedParam(toJavac(paramElement)))
+ .build());
+ }
+ }
+ return assistedParameterSpecs.build();
+ }
+
+ private AssistedInjectionParameters() {}
+}
diff --git a/java/dagger/internal/codegen/writing/BUILD b/java/dagger/internal/codegen/writing/BUILD
index dcb88b387..c99a253ad 100644
--- a/java/dagger/internal/codegen/writing/BUILD
+++ b/java/dagger/internal/codegen/writing/BUILD
@@ -33,15 +33,16 @@ java_library(
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/kotlin",
"//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
+ "//java/dagger/internal/codegen/xprocessing",
"//java/dagger/producers",
"//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:value",
+ "//third_party/java/error_prone:annotations",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/util/concurrent",
+ "//third_party/java/javapoet",
+ "//third_party/java/jsr330_inject",
],
)
diff --git a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/BuildModule.java b/java/dagger/internal/codegen/writing/BindingRepresentation.java
index f6317c24d..cf01c5280 100644
--- a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/BuildModule.java
+++ b/java/dagger/internal/codegen/writing/BindingRepresentation.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Dagger Authors.
+ * Copyright (C) 2021 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,18 +14,11 @@
* limitations under the License.
*/
-package dagger.example.gradle.android.simple;
+package dagger.internal.codegen.writing;
-import static android.os.Build.MODEL;
+import dagger.internal.codegen.binding.BindingRequest;
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-final class BuildModule {
- @Provides
- @Model
- static String provideModel() {
- return MODEL;
- }
+/** A factory of code expressions to satisfy all kinds of requests for a binding in a component. */
+interface BindingRepresentation {
+ RequestRepresentation getRequestRepresentation(BindingRequest request);
}
diff --git a/java/dagger/internal/codegen/writing/BindingRepresentations.java b/java/dagger/internal/codegen/writing/BindingRepresentations.java
new file mode 100644
index 000000000..35584743c
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/BindingRepresentations.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static dagger.internal.codegen.javapoet.TypeNames.DOUBLE_CHECK;
+import static dagger.internal.codegen.javapoet.TypeNames.SINGLE_CHECK;
+
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.binding.Binding;
+import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+
+/** Holds common methods for BindingRepresentations. */
+final class BindingRepresentations {
+ static FrameworkInstanceCreationExpression scope(
+ Binding binding, FrameworkInstanceCreationExpression unscoped) {
+ return () ->
+ CodeBlock.of(
+ "$T.provider($L)",
+ binding.scope().get().isReusable() ? SINGLE_CHECK : DOUBLE_CHECK,
+ unscoped.creationExpression());
+ }
+
+ private BindingRepresentations() {}
+}
diff --git a/java/dagger/internal/codegen/writing/ComponentBindingExpressions.java b/java/dagger/internal/codegen/writing/ComponentBindingExpressions.java
deleted file mode 100644
index dc15c998b..000000000
--- a/java/dagger/internal/codegen/writing/ComponentBindingExpressions.java
+++ /dev/null
@@ -1,707 +0,0 @@
-/*
- * Copyright (C) 2016 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Verify.verify;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
-import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
-import static dagger.internal.codegen.javapoet.TypeNames.DOUBLE_CHECK;
-import static dagger.internal.codegen.javapoet.TypeNames.SINGLE_CHECK;
-import static dagger.internal.codegen.langmodel.Accessibility.isRawTypeAccessible;
-import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-import static dagger.internal.codegen.writing.DelegateBindingExpression.isBindsScopeStrongerThanDependencyScope;
-import static dagger.internal.codegen.writing.MemberSelect.staticFactoryCreation;
-import static dagger.model.BindingKind.DELEGATE;
-import static dagger.model.BindingKind.MULTIBOUND_MAP;
-import static dagger.model.BindingKind.MULTIBOUND_SET;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableList;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.MethodSpec;
-import dagger.internal.codegen.binding.Binding;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.BindingNode;
-import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.BindingType;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.binding.FrameworkTypeMapper;
-import dagger.internal.codegen.binding.MembersInjectionBinding;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import dagger.internal.codegen.writing.MethodBindingExpression.MethodImplementationStrategy;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.RequestKind;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.type.TypeMirror;
-
-/** A central repository of code expressions used to access any binding available to a component. */
-@PerComponentImplementation
-public final class ComponentBindingExpressions {
- // TODO(dpb,ronshapiro): refactor this and ComponentRequirementExpressions into a
- // HierarchicalComponentMap<K, V>, or perhaps this use a flattened ImmutableMap, built from its
- // parents? If so, maybe make BindingExpression.Factory create it.
-
- private final Optional<ComponentBindingExpressions> parent;
- private final BindingGraph graph;
- private final ComponentImplementation componentImplementation;
- private final ComponentImplementation topLevelComponentImplementation;
- private final ComponentRequirementExpressions componentRequirementExpressions;
- private final OptionalFactories optionalFactories;
- private final DaggerTypes types;
- private final DaggerElements elements;
- private final SourceVersion sourceVersion;
- private final CompilerOptions compilerOptions;
- private final MembersInjectionMethods membersInjectionMethods;
- private final InnerSwitchingProviders innerSwitchingProviders;
- private final Map<BindingRequest, BindingExpression> expressions = new HashMap<>();
- private final KotlinMetadataUtil metadataUtil;
-
- @Inject
- ComponentBindingExpressions(
- @ParentComponent Optional<ComponentBindingExpressions> parent,
- BindingGraph graph,
- ComponentImplementation componentImplementation,
- @TopLevel ComponentImplementation topLevelComponentImplementation,
- ComponentRequirementExpressions componentRequirementExpressions,
- OptionalFactories optionalFactories,
- DaggerTypes types,
- DaggerElements elements,
- SourceVersion sourceVersion,
- CompilerOptions compilerOptions,
- KotlinMetadataUtil metadataUtil) {
- this.parent = parent;
- this.graph = graph;
- this.componentImplementation = componentImplementation;
- this.topLevelComponentImplementation = topLevelComponentImplementation;
- this.componentRequirementExpressions = checkNotNull(componentRequirementExpressions);
- this.optionalFactories = checkNotNull(optionalFactories);
- this.types = checkNotNull(types);
- this.elements = checkNotNull(elements);
- this.sourceVersion = checkNotNull(sourceVersion);
- this.compilerOptions = checkNotNull(compilerOptions);
- this.membersInjectionMethods =
- new MembersInjectionMethods(
- componentImplementation, this, graph, elements, types, metadataUtil);
- this.innerSwitchingProviders =
- new InnerSwitchingProviders(componentImplementation, this, types);
- this.metadataUtil = metadataUtil;
- }
-
- /**
- * Returns an expression that evaluates to the value of a binding request for a binding owned by
- * this component or an ancestor.
- *
- * @param requestingClass the class that will contain the expression
- * @throws IllegalStateException if there is no binding expression that satisfies the request
- */
- public Expression getDependencyExpression(BindingRequest request, ClassName requestingClass) {
- return getBindingExpression(request).getDependencyExpression(requestingClass);
- }
-
- /**
- * Equivalent to {@link #getDependencyExpression(BindingRequest, ClassName)} that is used only
- * when the request is for implementation of a component method.
- *
- * @throws IllegalStateException if there is no binding expression that satisfies the request
- */
- Expression getDependencyExpressionForComponentMethod(
- BindingRequest request,
- ComponentMethodDescriptor componentMethod,
- ComponentImplementation componentImplementation) {
- return getBindingExpression(request)
- .getDependencyExpressionForComponentMethod(componentMethod, componentImplementation);
- }
-
- /**
- * Returns the {@link CodeBlock} for the method arguments used with the factory {@code create()}
- * method for the given {@link ContributionBinding binding}.
- */
- CodeBlock getCreateMethodArgumentsCodeBlock(ContributionBinding binding) {
- return makeParametersCodeBlock(getCreateMethodArgumentsCodeBlocks(binding));
- }
-
- private ImmutableList<CodeBlock> getCreateMethodArgumentsCodeBlocks(ContributionBinding binding) {
- ImmutableList.Builder<CodeBlock> arguments = ImmutableList.builder();
-
- if (binding.requiresModuleInstance()) {
- arguments.add(
- componentRequirementExpressions.getExpressionDuringInitialization(
- ComponentRequirement.forModule(binding.contributingModule().get().asType()),
- componentImplementation.name()));
- }
-
- binding.dependencies().stream()
- .map(dependency -> frameworkRequest(binding, dependency))
- .map(request -> getDependencyExpression(request, componentImplementation.name()))
- .map(Expression::codeBlock)
- .forEach(arguments::add);
-
- return arguments.build();
- }
-
- private static BindingRequest frameworkRequest(
- ContributionBinding binding, DependencyRequest dependency) {
- // TODO(bcorso): See if we can get rid of FrameworkTypeMatcher
- FrameworkType frameworkType =
- FrameworkTypeMapper.forBindingType(binding.bindingType())
- .getFrameworkType(dependency.kind());
- return BindingRequest.bindingRequest(dependency.key(), frameworkType);
- }
-
- /**
- * Returns an expression that evaluates to the value of a dependency request, for passing to a
- * binding method, an {@code @Inject}-annotated constructor or member, or a proxy for one.
- *
- * <p>If the method is a generated static {@link InjectionMethods injection method}, each
- * parameter will be {@link Object} if the dependency's raw type is inaccessible. If that is the
- * case for this dependency, the returned expression will use a cast to evaluate to the raw type.
- *
- * @param requestingClass the class that will contain the expression
- */
- Expression getDependencyArgumentExpression(
- DependencyRequest dependencyRequest, ClassName requestingClass) {
-
- TypeMirror dependencyType = dependencyRequest.key().type();
- BindingRequest bindingRequest = bindingRequest(dependencyRequest);
- Expression dependencyExpression = getDependencyExpression(bindingRequest, requestingClass);
-
- if (dependencyRequest.kind().equals(RequestKind.INSTANCE)
- && !isTypeAccessibleFrom(dependencyType, requestingClass.packageName())
- && isRawTypeAccessible(dependencyType, requestingClass.packageName())) {
- return dependencyExpression.castTo(types.erasure(dependencyType));
- }
-
- return dependencyExpression;
- }
-
- /** Returns the implementation of a component method. */
- public MethodSpec getComponentMethod(ComponentMethodDescriptor componentMethod) {
- checkArgument(componentMethod.dependencyRequest().isPresent());
- BindingRequest request = bindingRequest(componentMethod.dependencyRequest().get());
- return MethodSpec.overriding(
- componentMethod.methodElement(),
- MoreTypes.asDeclared(graph.componentTypeElement().asType()),
- types)
- .addCode(
- getBindingExpression(request)
- .getComponentMethodImplementation(componentMethod, componentImplementation))
- .build();
- }
-
- /** Returns the {@link BindingExpression} for the given {@link BindingRequest}. */
- BindingExpression getBindingExpression(BindingRequest request) {
- if (expressions.containsKey(request)) {
- return expressions.get(request);
- }
-
- Optional<Binding> optionalBinding =
- graph.bindingNodes(request.key()).stream()
- // Filter out nodes we don't own.
- .filter(bindingNode -> bindingNode.componentPath().equals(graph.componentPath()))
- // Filter out nodes that don't match the request kind
- .filter(
- bindingNode ->
- // The binding used for the binding expression depends on the request:
- // 1. MembersInjectionBinding: satisfies MEMBERS_INJECTION requests
- // 2. ContributionBindings: satisfies all other requests.
- request.isRequestKind(RequestKind.MEMBERS_INJECTION)
- ? bindingNode.delegate().bindingType() == BindingType.MEMBERS_INJECTION
- : bindingNode.delegate().bindingType() == BindingType.PROVISION
- || bindingNode.delegate().bindingType() == BindingType.PRODUCTION)
- .map(BindingNode::delegate)
- // We expect at most one binding to match since this graph is already validated.
- .collect(toOptional());
-
- if (optionalBinding.isPresent()) {
- BindingExpression expression = createBindingExpression(optionalBinding.get(), request);
- expressions.put(request, expression);
- return expression;
- }
-
- checkArgument(parent.isPresent(), "no expression found for %s", request);
- return parent.get().getBindingExpression(request);
- }
-
- /** Creates a binding expression. */
- private BindingExpression createBindingExpression(Binding binding, BindingRequest request) {
- switch (binding.bindingType()) {
- case MEMBERS_INJECTION:
- checkArgument(request.isRequestKind(RequestKind.MEMBERS_INJECTION));
- return new MembersInjectionBindingExpression(
- (MembersInjectionBinding) binding, membersInjectionMethods);
-
- case PROVISION:
- return provisionBindingExpression((ContributionBinding) binding, request);
-
- case PRODUCTION:
- return productionBindingExpression((ContributionBinding) binding, request);
- }
- throw new AssertionError(binding);
- }
-
- /**
- * Returns a binding expression that uses a {@link javax.inject.Provider} for provision bindings
- * or a {@link dagger.producers.Producer} for production bindings.
- */
- private BindingExpression frameworkInstanceBindingExpression(ContributionBinding binding) {
- // TODO(bcorso): Consider merging the static factory creation logic into CreationExpressions?
- Optional<MemberSelect> staticMethod =
- useStaticFactoryCreation(binding) ? staticFactoryCreation(binding) : Optional.empty();
- FrameworkInstanceSupplier frameworkInstanceSupplier =
- staticMethod.isPresent()
- ? staticMethod::get
- : new FrameworkFieldInitializer(
- componentImplementation,
- binding,
- binding.scope().isPresent()
- ? scope(binding, frameworkInstanceCreationExpression(binding))
- : frameworkInstanceCreationExpression(binding));
-
- switch (binding.bindingType()) {
- case PROVISION:
- return new ProviderInstanceBindingExpression(
- binding, frameworkInstanceSupplier, types, elements);
- case PRODUCTION:
- return new ProducerNodeInstanceBindingExpression(
- binding, frameworkInstanceSupplier, types, elements, componentImplementation);
- default:
- throw new AssertionError("invalid binding type: " + binding.bindingType());
- }
- }
-
- private FrameworkInstanceCreationExpression scope(
- ContributionBinding binding, FrameworkInstanceCreationExpression unscoped) {
- return () ->
- CodeBlock.of(
- "$T.provider($L)",
- binding.scope().get().isReusable() ? SINGLE_CHECK : DOUBLE_CHECK,
- unscoped.creationExpression());
- }
-
- /**
- * Returns a creation expression for a {@link javax.inject.Provider} for provision bindings or a
- * {@link dagger.producers.Producer} for production bindings.
- */
- private FrameworkInstanceCreationExpression frameworkInstanceCreationExpression(
- ContributionBinding binding) {
- switch (binding.kind()) {
- case COMPONENT:
- // The cast can be removed when we drop java 7 source support
- return new InstanceFactoryCreationExpression(
- () -> CodeBlock.of("($T) this", binding.key().type()));
-
- case BOUND_INSTANCE:
- return instanceFactoryCreationExpression(
- binding, ComponentRequirement.forBoundInstance(binding));
-
- case COMPONENT_DEPENDENCY:
- return instanceFactoryCreationExpression(
- binding, ComponentRequirement.forDependency(binding.key().type()));
-
- case COMPONENT_PROVISION:
- return new DependencyMethodProviderCreationExpression(
- binding,
- componentImplementation,
- componentRequirementExpressions,
- compilerOptions,
- graph);
-
- case SUBCOMPONENT_CREATOR:
- return new AnonymousProviderCreationExpression(
- binding, this, componentImplementation.name());
-
- case ASSISTED_FACTORY:
- case ASSISTED_INJECTION:
- case INJECTION:
- case PROVISION:
- return new InjectionOrProvisionProviderCreationExpression(binding, this);
-
- case COMPONENT_PRODUCTION:
- return new DependencyMethodProducerCreationExpression(
- binding, componentImplementation, componentRequirementExpressions, graph);
-
- case PRODUCTION:
- return new ProducerCreationExpression(binding, this);
-
- case MULTIBOUND_SET:
- return new SetFactoryCreationExpression(binding, componentImplementation, this, graph);
-
- case MULTIBOUND_MAP:
- return new MapFactoryCreationExpression(
- binding, componentImplementation, this, graph, elements);
-
- case DELEGATE:
- return new DelegatingFrameworkInstanceCreationExpression(
- binding, componentImplementation, this);
-
- case OPTIONAL:
- return new OptionalFactoryInstanceCreationExpression(
- optionalFactories, binding, componentImplementation, this);
-
- case MEMBERS_INJECTOR:
- return new MembersInjectorProviderCreationExpression((ProvisionBinding) binding, this);
-
- default:
- throw new AssertionError(binding);
- }
- }
-
- private InstanceFactoryCreationExpression instanceFactoryCreationExpression(
- ContributionBinding binding, ComponentRequirement componentRequirement) {
- return new InstanceFactoryCreationExpression(
- binding.nullableType().isPresent(),
- () ->
- componentRequirementExpressions.getExpressionDuringInitialization(
- componentRequirement, componentImplementation.name()));
- }
-
- /** Returns a binding expression for a provision binding. */
- private BindingExpression provisionBindingExpression(
- ContributionBinding binding, BindingRequest request) {
- if (!request.requestKind().isPresent()) {
- verify(
- request.frameworkType().get().equals(FrameworkType.PRODUCER_NODE),
- "expected a PRODUCER_NODE: %s",
- request);
- return producerFromProviderBindingExpression(binding);
- }
- RequestKind requestKind = request.requestKind().get();
- Key key = request.key();
- switch (requestKind) {
- case INSTANCE:
- return instanceBindingExpression(binding);
-
- case PROVIDER:
- return providerBindingExpression(binding);
-
- case LAZY:
- case PRODUCED:
- case PROVIDER_OF_LAZY:
- return new DerivedFromFrameworkInstanceBindingExpression(
- key, FrameworkType.PROVIDER, requestKind, this, types);
-
- case PRODUCER:
- return producerFromProviderBindingExpression(binding);
-
- case FUTURE:
- return new ImmediateFutureBindingExpression(key, this, types, sourceVersion);
-
- case MEMBERS_INJECTION:
- throw new IllegalArgumentException();
- }
-
- throw new AssertionError();
- }
-
- /** Returns a binding expression for a production binding. */
- private BindingExpression productionBindingExpression(
- ContributionBinding binding, BindingRequest request) {
- if (request.frameworkType().isPresent()) {
- return frameworkInstanceBindingExpression(binding);
- } else {
- // If no FrameworkType is present, a RequestKind is guaranteed to be present.
- RequestKind requestKind = request.requestKind().get();
- return new DerivedFromFrameworkInstanceBindingExpression(
- request.key(), FrameworkType.PRODUCER_NODE, requestKind, this, types);
- }
- }
-
- /**
- * Returns a binding expression for {@link RequestKind#PROVIDER} requests.
- *
- * <p>{@code @Binds} bindings that don't {@linkplain #needsCaching(ContributionBinding) need to be
- * cached} can use a {@link DelegateBindingExpression}.
- *
- * <p>In fastInit mode, use an {@link InnerSwitchingProviders inner switching provider} unless
- * that provider's case statement will simply call {@code get()} on another {@link Provider} (in
- * which case, just use that Provider directly).
- *
- * <p>Otherwise, return a {@link FrameworkInstanceBindingExpression}.
- */
- private BindingExpression providerBindingExpression(ContributionBinding binding) {
- if (binding.kind().equals(DELEGATE) && !needsCaching(binding)) {
- return new DelegateBindingExpression(binding, RequestKind.PROVIDER, this, types, elements);
- } else if (isFastInit()
- && frameworkInstanceCreationExpression(binding).useInnerSwitchingProvider()
- && !(instanceBindingExpression(binding)
- instanceof DerivedFromFrameworkInstanceBindingExpression)) {
- return wrapInMethod(
- binding,
- bindingRequest(binding.key(), RequestKind.PROVIDER),
- innerSwitchingProviders.newBindingExpression(binding));
- }
- return frameworkInstanceBindingExpression(binding);
- }
-
- /**
- * Returns a binding expression that uses a {@link dagger.producers.Producer} field for a
- * provision binding.
- */
- private FrameworkInstanceBindingExpression producerFromProviderBindingExpression(
- ContributionBinding binding) {
- checkArgument(binding.bindingType().equals(BindingType.PROVISION));
- return new ProducerNodeInstanceBindingExpression(
- binding,
- new FrameworkFieldInitializer(
- componentImplementation,
- binding,
- new ProducerFromProviderCreationExpression(binding, componentImplementation, this)),
- types,
- elements,
- componentImplementation);
- }
-
- /**
- * Returns a binding expression for {@link RequestKind#INSTANCE} requests.
- */
- private BindingExpression instanceBindingExpression(ContributionBinding binding) {
- Optional<BindingExpression> maybeDirectInstanceExpression =
- unscopedDirectInstanceExpression(binding);
- if (maybeDirectInstanceExpression.isPresent()) {
- // If this is the case where we don't need to use Provider#get() because there's no caching
- // and it isn't an assisted factory, or because we're in fastInit mode (since fastInit avoids
- // using Providers), we can try to use the direct expression, possibly wrapped in a method
- // if necessary (e.g. it has dependencies).
- if ((!needsCaching(binding) && binding.kind() != BindingKind.ASSISTED_FACTORY)
- || isFastInit()) {
- BindingExpression directInstanceExpression = maybeDirectInstanceExpression.get();
- // While this can't require caching in default mode, if we're in fastInit mode and we need
- // caching we also need to wrap it in a method.
- return directInstanceExpression.requiresMethodEncapsulation() || needsCaching(binding)
- ? wrapInMethod(
- binding,
- bindingRequest(binding.key(), RequestKind.INSTANCE),
- directInstanceExpression)
- : directInstanceExpression;
- }
- }
- return new DerivedFromFrameworkInstanceBindingExpression(
- binding.key(), FrameworkType.PROVIDER, RequestKind.INSTANCE, this, types);
- }
-
- /**
- * Returns an unscoped binding expression for an {@link RequestKind#INSTANCE} that does not call
- * {@code get()} on its provider, if there is one.
- */
- private Optional<BindingExpression> unscopedDirectInstanceExpression(
- ContributionBinding binding) {
- switch (binding.kind()) {
- case DELEGATE:
- return Optional.of(
- new DelegateBindingExpression(binding, RequestKind.INSTANCE, this, types, elements));
-
- case COMPONENT:
- return Optional.of(
- new ComponentInstanceBindingExpression(binding, componentImplementation.name()));
-
- case COMPONENT_DEPENDENCY:
- return Optional.of(
- new ComponentRequirementBindingExpression(
- binding,
- ComponentRequirement.forDependency(binding.key().type()),
- componentRequirementExpressions));
-
- case COMPONENT_PROVISION:
- return Optional.of(
- new ComponentProvisionBindingExpression(
- (ProvisionBinding) binding,
- graph,
- componentRequirementExpressions,
- compilerOptions));
-
- case SUBCOMPONENT_CREATOR:
- return Optional.of(
- new SubcomponentCreatorBindingExpression(
- binding, componentImplementation.getSubcomponentCreatorSimpleName(binding.key())));
-
- case MULTIBOUND_SET:
- return Optional.of(
- new SetBindingExpression((ProvisionBinding) binding, graph, this, types, elements));
-
- case MULTIBOUND_MAP:
- return Optional.of(
- new MapBindingExpression((ProvisionBinding) binding, graph, this, types, elements));
-
- case OPTIONAL:
- return Optional.of(
- new OptionalBindingExpression((ProvisionBinding) binding, this, types, sourceVersion));
-
- case BOUND_INSTANCE:
- return Optional.of(
- new ComponentRequirementBindingExpression(
- binding,
- ComponentRequirement.forBoundInstance(binding),
- componentRequirementExpressions));
-
- case ASSISTED_FACTORY:
- return Optional.of(
- new AssistedFactoryBindingExpression(
- (ProvisionBinding) binding, this, types, elements));
-
- case ASSISTED_INJECTION:
- case INJECTION:
- case PROVISION:
- return Optional.of(
- new SimpleMethodBindingExpression(
- (ProvisionBinding) binding,
- compilerOptions,
- this,
- membersInjectionMethods,
- componentRequirementExpressions,
- elements,
- sourceVersion,
- metadataUtil));
-
- case MEMBERS_INJECTOR:
- return Optional.empty();
-
- case MEMBERS_INJECTION:
- case COMPONENT_PRODUCTION:
- case PRODUCTION:
- throw new IllegalArgumentException(binding.kind().toString());
- default:
- throw new AssertionError("Unexpected binding kind: " + binding.kind());
- }
- }
-
- /**
- * Returns {@code true} if the binding should use the static factory creation strategy.
- *
- * <p>In default mode, we always use the static factory creation strategy. In fastInit mode, we
- * prefer to use a SwitchingProvider instead of static factories in order to reduce class loading;
- * however, we allow static factories that can reused across multiple bindings, e.g. {@code
- * MapFactory} or {@code SetFactory}.
- */
- private boolean useStaticFactoryCreation(ContributionBinding binding) {
- return !isFastInit()
- || binding.kind().equals(MULTIBOUND_MAP)
- || binding.kind().equals(MULTIBOUND_SET);
- }
-
- /**
- * Returns a binding expression that uses a given one as the body of a method that users call. If
- * a component provision method matches it, it will be the method implemented. If it does not
- * match a component provision method and the binding is modifiable, then a new public modifiable
- * binding method will be written. If the binding doesn't match a component method and is not
- * modifiable, then a new private method will be written.
- */
- BindingExpression wrapInMethod(
- ContributionBinding binding, BindingRequest request, BindingExpression bindingExpression) {
- // If we've already wrapped the expression, then use the delegate.
- if (bindingExpression instanceof MethodBindingExpression) {
- return bindingExpression;
- }
-
- MethodImplementationStrategy methodImplementationStrategy =
- methodImplementationStrategy(binding, request);
- Optional<ComponentMethodDescriptor> matchingComponentMethod =
- graph.componentDescriptor().firstMatchingComponentMethod(request);
-
- ComponentImplementation shard = componentImplementation.shardImplementation(binding.key());
-
- // Consider the case of a request from a component method like:
- //
- // DaggerMyComponent extends MyComponent {
- // @Overrides
- // Foo getFoo() {
- // <FOO_BINDING_REQUEST>
- // }
- // }
- //
- // Normally, in this case we would return a ComponentMethodBindingExpression rather than a
- // PrivateMethodBindingExpression so that #getFoo() can inline the implementation rather than
- // create an unnecessary private method and return that. However, with sharding we don't want to
- // inline the implementation because that would defeat some of the class pool savings if those
- // fields had to communicate across shards. Thus, when a key belongs to a separate shard use a
- // PrivateMethodBindingExpression and put the private method in the shard.
- if (matchingComponentMethod.isPresent() && componentImplementation == shard) {
- ComponentMethodDescriptor componentMethod = matchingComponentMethod.get();
- return new ComponentMethodBindingExpression(
- request,
- binding,
- methodImplementationStrategy,
- bindingExpression,
- componentImplementation,
- componentMethod,
- types);
- } else {
- return new PrivateMethodBindingExpression(
- request,
- binding,
- methodImplementationStrategy,
- bindingExpression,
- shard,
- types,
- compilerOptions);
- }
- }
-
- private MethodImplementationStrategy methodImplementationStrategy(
- ContributionBinding binding, BindingRequest request) {
- if (isFastInit()) {
- if (request.isRequestKind(RequestKind.PROVIDER)) {
- return MethodImplementationStrategy.SINGLE_CHECK;
- } else if (request.isRequestKind(RequestKind.INSTANCE) && needsCaching(binding)) {
- return binding.scope().get().isReusable()
- ? MethodImplementationStrategy.SINGLE_CHECK
- : MethodImplementationStrategy.DOUBLE_CHECK;
- }
- }
- return MethodImplementationStrategy.SIMPLE;
- }
-
- /**
- * Returns {@code true} if the component needs to make sure the provided value is cached.
- *
- * <p>The component needs to cache the value for scoped bindings except for {@code @Binds}
- * bindings whose scope is no stronger than their delegate's.
- */
- private boolean needsCaching(ContributionBinding binding) {
- if (!binding.scope().isPresent()) {
- return false;
- }
- if (binding.kind().equals(DELEGATE)) {
- return isBindsScopeStrongerThanDependencyScope(binding, graph);
- }
- return true;
- }
-
- private boolean isFastInit() {
- return compilerOptions.fastInit(
- topLevelComponentImplementation.componentDescriptor().typeElement());
- }
-}
diff --git a/java/dagger/internal/codegen/componentgenerator/ComponentCreatorImplementationFactory.java b/java/dagger/internal/codegen/writing/ComponentCreatorImplementationFactory.java
index 66270c697..313b37921 100644
--- a/java/dagger/internal/codegen/componentgenerator/ComponentCreatorImplementationFactory.java
+++ b/java/dagger/internal/codegen/writing/ComponentCreatorImplementationFactory.java
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-package dagger.internal.codegen.componentgenerator;
+package dagger.internal.codegen.writing;
-import static com.google.auto.common.MoreTypes.asDeclared;
+import static androidx.room.compiler.processing.XTypeKt.isVoid;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.getOnlyElement;
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
import static com.squareup.javapoet.TypeSpec.classBuilder;
import static dagger.internal.codegen.binding.SourceFiles.simpleVariableName;
@@ -32,11 +31,12 @@ import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
-import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
@@ -50,40 +50,25 @@ import dagger.internal.codegen.binding.ComponentDescriptor;
import dagger.internal.codegen.binding.ComponentRequirement;
import dagger.internal.codegen.binding.ComponentRequirement.NullPolicy;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.internal.codegen.writing.ComponentCreatorImplementation;
-import dagger.internal.codegen.writing.ComponentImplementation;
-import dagger.internal.codegen.writing.ModuleProxies;
+import dagger.internal.codegen.xprocessing.MethodSpecs;
+import dagger.internal.codegen.xprocessing.XElements;
import java.util.Optional;
import java.util.Set;
+import java.util.stream.Stream;
import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeKind;
/** Factory for creating {@link ComponentCreatorImplementation} instances. */
final class ComponentCreatorImplementationFactory {
private final ComponentImplementation componentImplementation;
- private final DaggerElements elements;
- private final DaggerTypes types;
- private final KotlinMetadataUtil metadataUtil;
private final ModuleProxies moduleProxies;
@Inject
ComponentCreatorImplementationFactory(
ComponentImplementation componentImplementation,
- DaggerElements elements,
- DaggerTypes types,
- KotlinMetadataUtil metadataUtil,
ModuleProxies moduleProxies) {
this.componentImplementation = componentImplementation;
- this.elements = elements;
- this.types = types;
- this.metadataUtil = metadataUtil;
this.moduleProxies = moduleProxies;
}
@@ -98,34 +83,28 @@ final class ComponentCreatorImplementationFactory {
Builder builder =
creatorDescriptor.isPresent()
- ? new BuilderForCreatorDescriptor(componentImplementation, creatorDescriptor.get())
- : new BuilderForGeneratedRootComponentBuilder(componentImplementation);
+ ? new BuilderForCreatorDescriptor(creatorDescriptor.get())
+ : new BuilderForGeneratedRootComponentBuilder();
return Optional.of(builder.build());
}
/** Base class for building a creator implementation. */
private abstract class Builder {
- final ComponentImplementation componentImplementation;
- final ClassName className;
- final TypeSpec.Builder classBuilder;
-
+ private final TypeSpec.Builder classBuilder =
+ classBuilder(componentImplementation.getCreatorName());
+ private final UniqueNameSet fieldNames = new UniqueNameSet();
private ImmutableMap<ComponentRequirement, FieldSpec> fields;
- Builder(ComponentImplementation componentImplementation) {
- this.componentImplementation = componentImplementation;
- this.className = componentImplementation.getCreatorName();
- this.classBuilder = classBuilder(className);
- }
-
/** Builds the {@link ComponentCreatorImplementation}. */
ComponentCreatorImplementation build() {
setModifiers();
setSupertype();
- this.fields = addFields();
addConstructor();
+ this.fields = addFields();
addSetterMethods();
addFactoryMethod();
- return ComponentCreatorImplementation.create(classBuilder.build(), className, fields);
+ return ComponentCreatorImplementation.create(
+ classBuilder.build(), componentImplementation.getCreatorName(), fields);
}
/** Returns the descriptor for the component. */
@@ -168,10 +147,7 @@ final class ComponentCreatorImplementationFactory {
private void setModifiers() {
visibility().ifPresent(classBuilder::addModifiers);
- if (!componentImplementation.isNested()) {
- classBuilder.addModifiers(STATIC);
- }
- classBuilder.addModifiers(FINAL);
+ classBuilder.addModifiers(STATIC, FINAL);
}
/** Returns the visibility modifier the generated class should have, if any. */
@@ -181,17 +157,28 @@ final class ComponentCreatorImplementationFactory {
protected abstract void setSupertype();
/** Adds a constructor for the creator type, if needed. */
- protected abstract void addConstructor();
+ protected void addConstructor() {
+ MethodSpec.Builder constructor = MethodSpec.constructorBuilder().addModifiers(PRIVATE);
+ componentImplementation
+ .creatorComponentFields()
+ .forEach(
+ field -> {
+ fieldNames.claim(field.name);
+ classBuilder.addField(field);
+ constructor.addParameter(field.type, field.name);
+ constructor.addStatement("this.$1N = $1N", field);
+ });
+ classBuilder.addMethod(constructor.build());
+ }
private ImmutableMap<ComponentRequirement, FieldSpec> addFields() {
// Fields in an abstract creator class need to be visible from subclasses.
- UniqueNameSet fieldNames = new UniqueNameSet();
ImmutableMap<ComponentRequirement, FieldSpec> result =
Maps.toMap(
Sets.intersection(neededUserSettableRequirements(), setterMethods()),
requirement ->
FieldSpec.builder(
- TypeName.get(requirement.type()),
+ requirement.type().getTypeName(),
fieldNames.getUniqueName(requirement.variableName()),
PRIVATE)
.build());
@@ -220,7 +207,8 @@ final class ComponentCreatorImplementationFactory {
// to generate noop setters for impossible cases like when the requirement type
// is in another package. This avoids unnecessary breakages in Dagger's generated
// due to the noop setters.
- if (isElementAccessibleFrom(requirement.typeElement(), className.packageName())) {
+ if (isElementAccessibleFrom(
+ requirement.typeElement(), componentImplementation.name().packageName())) {
return Optional.of(noopSetterMethod(requirement));
} else {
return Optional.empty();
@@ -237,7 +225,7 @@ final class ComponentCreatorImplementationFactory {
method.addStatement(
"this.$N = $L",
fields.get(requirement),
- requirement.nullPolicy(elements, metadataUtil).equals(NullPolicy.ALLOW)
+ requirement.nullPolicy().equals(NullPolicy.ALLOW)
? CodeBlock.of("$N", parameter)
: CodeBlock.of("$T.checkNotNull($N)", Preconditions.class, parameter));
return maybeReturnThis(method);
@@ -262,7 +250,7 @@ final class ComponentCreatorImplementationFactory {
UnsupportedOperationException.class,
String.class,
"%s cannot be set because it is inherited from the enclosing component",
- TypeNames.rawTypeName(TypeName.get(requirement.type())))
+ TypeNames.rawTypeName(requirement.type().getTypeName()))
.build();
}
@@ -284,7 +272,7 @@ final class ComponentCreatorImplementationFactory {
MethodSpec factoryMethod() {
MethodSpec.Builder factoryMethod = factoryMethodBuilder();
factoryMethod
- .returns(ClassName.get(componentDescriptor().typeElement()))
+ .returns(componentDescriptor().typeElement().getClassName())
.addModifiers(PUBLIC);
ImmutableMap<ComponentRequirement, String> factoryMethodParameters =
@@ -310,7 +298,7 @@ final class ComponentCreatorImplementationFactory {
private void addNullHandlingForField(
ComponentRequirement requirement, FieldSpec field, MethodSpec.Builder factoryMethod) {
- switch (requirement.nullPolicy(elements, metadataUtil)) {
+ switch (requirement.nullPolicy()) {
case NEW:
checkState(requirement.kind().isModule());
factoryMethod
@@ -334,7 +322,7 @@ final class ComponentCreatorImplementationFactory {
private void addNullHandlingForParameter(
ComponentRequirement requirement, String parameter, MethodSpec.Builder factoryMethod) {
- if (!requirement.nullPolicy(elements, metadataUtil).equals(NullPolicy.ALLOW)) {
+ if (!requirement.nullPolicy().equals(NullPolicy.ALLOW)) {
// Factory method parameters are always required unless they are a nullable
// binds-instance (i.e. ALLOW)
factoryMethod.addStatement("$T.checkNotNull($L)", Preconditions.class, parameter);
@@ -346,23 +334,27 @@ final class ComponentCreatorImplementationFactory {
private CodeBlock componentConstructorArgs(
ImmutableMap<ComponentRequirement, String> factoryMethodParameters) {
- return componentConstructorRequirements().stream()
- .map(
- requirement -> {
- if (fields.containsKey(requirement)) {
- return CodeBlock.of("$N", fields.get(requirement));
- } else if (factoryMethodParameters.containsKey(requirement)) {
- return CodeBlock.of("$L", factoryMethodParameters.get(requirement));
- } else {
- return newModuleInstance(requirement);
- }
- })
+ return Stream.concat(
+ componentImplementation.creatorComponentFields().stream()
+ .map(field -> CodeBlock.of("$N", field)),
+ componentConstructorRequirements().stream()
+ .map(
+ requirement -> {
+ if (fields.containsKey(requirement)) {
+ return CodeBlock.of("$N", fields.get(requirement));
+ } else if (factoryMethodParameters.containsKey(requirement)) {
+ return CodeBlock.of("$L", factoryMethodParameters.get(requirement));
+ } else {
+ return newModuleInstance(requirement);
+ }
+ }))
.collect(toParametersCodeBlock());
}
private CodeBlock newModuleInstance(ComponentRequirement requirement) {
checkArgument(requirement.kind().isModule()); // this should be guaranteed to be true here
- return moduleProxies.newModuleInstance(requirement.typeElement(), className);
+ return moduleProxies.newModuleInstance(
+ requirement.typeElement(), componentImplementation.getCreatorName());
}
}
@@ -370,10 +362,7 @@ final class ComponentCreatorImplementationFactory {
private final class BuilderForCreatorDescriptor extends Builder {
final ComponentCreatorDescriptor creatorDescriptor;
- BuilderForCreatorDescriptor(
- ComponentImplementation componentImplementation,
- ComponentCreatorDescriptor creatorDescriptor) {
- super(componentImplementation);
+ BuilderForCreatorDescriptor(ComponentCreatorDescriptor creatorDescriptor) {
this.creatorDescriptor = creatorDescriptor;
}
@@ -389,12 +378,14 @@ final class ComponentCreatorImplementationFactory {
@Override
protected void setSupertype() {
- addSupertype(classBuilder, creatorDescriptor.typeElement());
+ addSupertype(super.classBuilder, creatorDescriptor.typeElement());
}
@Override
protected void addConstructor() {
- // Just use the implicit no-arg public constructor.
+ if (!componentImplementation.creatorComponentFields().isEmpty()) {
+ super.addConstructor();
+ }
}
@Override
@@ -405,18 +396,16 @@ final class ComponentCreatorImplementationFactory {
@Override
protected ImmutableMap<ComponentRequirement, String> factoryMethodParameters() {
return ImmutableMap.copyOf(
- Maps.transformValues(
- creatorDescriptor.factoryParameters(),
- element -> element.getSimpleName().toString()));
+ Maps.transformValues(creatorDescriptor.factoryParameters(), XElements::getSimpleName));
}
- private DeclaredType creatorType() {
- return asDeclared(creatorDescriptor.typeElement().asType());
+ private XType creatorType() {
+ return creatorDescriptor.typeElement().getType();
}
@Override
protected MethodSpec.Builder factoryMethodBuilder() {
- return MethodSpec.overriding(creatorDescriptor.factoryMethod(), creatorType(), types);
+ return MethodSpecs.overriding(creatorDescriptor.factoryMethod(), creatorType());
}
private RequirementStatus requirementStatus(ComponentRequirement requirement) {
@@ -447,11 +436,11 @@ final class ComponentCreatorImplementationFactory {
@Override
protected MethodSpec.Builder setterMethodBuilder(ComponentRequirement requirement) {
- ExecutableElement supertypeMethod = creatorDescriptor.setterMethods().get(requirement);
- MethodSpec.Builder method = MethodSpec.overriding(supertypeMethod, creatorType(), types);
- if (!supertypeMethod.getReturnType().getKind().equals(TypeKind.VOID)) {
+ XMethodElement supertypeMethod = creatorDescriptor.setterMethods().get(requirement);
+ MethodSpec.Builder method = MethodSpecs.overriding(supertypeMethod, creatorType());
+ if (!isVoid(supertypeMethod.getReturnType())) {
// Take advantage of covariant returns so that we don't have to worry about type variables
- method.returns(className);
+ method.returns(componentImplementation.getCreatorName());
}
return method;
}
@@ -462,9 +451,6 @@ final class ComponentCreatorImplementationFactory {
* does not have its own user-defined creator type (i.e. a {@code ComponentCreatorDescriptor}).
*/
private final class BuilderForGeneratedRootComponentBuilder extends Builder {
- BuilderForGeneratedRootComponentBuilder(ComponentImplementation componentImplementation) {
- super(componentImplementation);
- }
@Override
protected ImmutableMap<ComponentRequirement, RequirementStatus> userSettableRequirements() {
@@ -478,11 +464,9 @@ final class ComponentCreatorImplementationFactory {
@Override
protected Optional<Modifier> visibility() {
- return componentImplementation
- .componentDescriptor()
- .typeElement()
- .getModifiers()
- .contains(PUBLIC) ? Optional.of(PUBLIC) : Optional.empty();
+ return componentImplementation.componentDescriptor().typeElement().isPublic()
+ ? Optional.of(PUBLIC)
+ : Optional.empty();
}
@Override
@@ -491,11 +475,6 @@ final class ComponentCreatorImplementationFactory {
}
@Override
- protected void addConstructor() {
- classBuilder.addMethod(constructorBuilder().addModifiers(PRIVATE).build());
- }
-
- @Override
protected ImmutableSet<ComponentRequirement> setterMethods() {
return componentDescriptor().dependenciesAndConcreteModules();
}
@@ -512,11 +491,11 @@ final class ComponentCreatorImplementationFactory {
@Override
protected MethodSpec.Builder setterMethodBuilder(ComponentRequirement requirement) {
- String name = simpleVariableName(requirement.typeElement());
+ String name = simpleVariableName(requirement.typeElement().getClassName());
return methodBuilder(name)
.addModifiers(PUBLIC)
- .addParameter(TypeName.get(requirement.type()), name)
- .returns(className);
+ .addParameter(requirement.type().getTypeName(), name)
+ .returns(componentImplementation.getCreatorName());
}
}
diff --git a/java/dagger/internal/codegen/writing/ComponentImplementation.java b/java/dagger/internal/codegen/writing/ComponentImplementation.java
index a09620e87..f458a9a94 100644
--- a/java/dagger/internal/codegen/writing/ComponentImplementation.java
+++ b/java/dagger/internal/codegen/writing/ComponentImplementation.java
@@ -16,68 +16,129 @@
package dagger.internal.codegen.writing;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static com.google.auto.common.MoreTypes.asDeclared;
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
+import static com.squareup.javapoet.MethodSpec.constructorBuilder;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.BUILDER;
+import static dagger.internal.codegen.base.ComponentCreatorKind.BUILDER;
+import static dagger.internal.codegen.binding.SourceFiles.simpleVariableName;
+import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.suppressWarnings;
+import static dagger.internal.codegen.javapoet.CodeBlocks.parameterNames;
+import static dagger.internal.codegen.langmodel.Accessibility.isProtectedMemberOf;
import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.COMPONENT_METHOD;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static dagger.producers.CancellationPolicy.Propagation.PROPAGATE;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+import static javax.tools.Diagnostic.Kind.ERROR;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.compat.XConverters;
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import com.google.common.collect.MultimapBuilder;
-import com.squareup.javapoet.AnnotationSpec;
+import com.google.common.collect.Sets;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
+import dagger.internal.Preconditions;
+import dagger.internal.codegen.base.ComponentCreatorKind;
import dagger.internal.codegen.base.UniqueNameSet;
+import dagger.internal.codegen.binding.Binding;
import dagger.internal.codegen.binding.BindingGraph;
+import dagger.internal.codegen.binding.BindingNode;
import dagger.internal.codegen.binding.BindingRequest;
import dagger.internal.codegen.binding.ComponentCreatorDescriptor;
-import dagger.internal.codegen.binding.ComponentCreatorKind;
import dagger.internal.codegen.binding.ComponentDescriptor;
+import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
import dagger.internal.codegen.binding.ComponentRequirement;
import dagger.internal.codegen.binding.KeyVariableNamer;
+import dagger.internal.codegen.binding.MethodSignature;
import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.javapoet.CodeBlocks;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.javapoet.TypeSpecs;
-import dagger.model.Key;
-import dagger.model.RequestKind;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.spi.model.BindingGraph.Node;
+import dagger.spi.model.Key;
+import dagger.spi.model.RequestKind;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
-import java.util.LinkedHashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
/** The implementation of a component type. */
+@PerComponentImplementation
public final class ComponentImplementation {
+ /** A factory for creating a {@link ComponentImplementation}. */
+ public interface ChildComponentImplementationFactory {
+ /** Creates a {@link ComponentImplementation} for the given {@code childGraph}. */
+ ComponentImplementation create(BindingGraph childGraph);
+ }
+
+ /** Compiler Modes. */
+ public enum CompilerMode {
+ DEFAULT,
+ FAST_INIT,
+ EXPERIMENTAL_MERGED_MODE;
+
+ public boolean isFastInit() {
+ return this == CompilerMode.FAST_INIT;
+ }
+
+ public boolean isExperimentalMergedMode() {
+ return this == CompilerMode.EXPERIMENTAL_MERGED_MODE;
+ }
+ }
+
/** A type of field that this component can contain. */
public enum FieldSpecKind {
/** A field for a component shard. */
- COMPONENT_SHARD,
+ COMPONENT_SHARD_FIELD,
/** A field required by the component, e.g. module instances. */
COMPONENT_REQUIREMENT_FIELD,
- /**
- * A field for the lock and cached value for {@linkplain PrivateMethodBindingExpression
- * private-method scoped bindings}.
- */
- PRIVATE_METHOD_SCOPED_FIELD,
-
/** A framework field for type T, e.g. {@code Provider<T>}. */
FRAMEWORK_FIELD,
@@ -114,8 +175,7 @@ public final class ComponentImplementation {
* The {@link dagger.producers.internal.CancellationListener#onProducerFutureCancelled(boolean)}
* method for a production component.
*/
- CANCELLATION_LISTENER_METHOD,
- ;
+ CANCELLATION_LISTENER_METHOD
}
/** A type of nested class that this component can contain. */
@@ -129,134 +189,237 @@ public final class ComponentImplementation {
/** A provider class for a component provision. */
COMPONENT_PROVISION_FACTORY,
+ /** A class for a component shard. */
+ COMPONENT_SHARD_TYPE,
+
/** A class for the subcomponent or subcomponent builder. */
SUBCOMPONENT
}
- private ComponentImplementation currentShard = this;
- private final Map<Key, ComponentImplementation> shardsByKey = new HashMap<>();
- private final Optional<ComponentImplementation> shardOwner;
+ /**
+ * Returns the {@link ShardImplementation} for each binding in this graph.
+ *
+ * <p>Each shard contains approximately {@link CompilerOptions#keysPerComponentShard()} bindings.
+ *
+ * <p>If more than 1 shard is needed, we iterate the strongly connected nodes to make sure of two
+ * things: 1) bindings are put in shards in reverse topological order (i.e., bindings in Shard{i}
+ * do not depend on bindings in Shard{i+j}) and 2) bindings belonging to the same cycle are put in
+ * the same shard. These two guarantees allow us to initialize each shard in a well defined order.
+ */
+ private static ImmutableMap<Binding, ShardImplementation> createShardsByBinding(
+ ShardImplementation componentShard, BindingGraph graph, CompilerOptions compilerOptions) {
+ ImmutableList<ImmutableList<Binding>> partitions = bindingPartitions(graph, compilerOptions);
+ ImmutableMap.Builder<Binding, ShardImplementation> builder = ImmutableMap.builder();
+ for (int i = 0; i < partitions.size(); i++) {
+ ShardImplementation shard = i == 0 ? componentShard : componentShard.createShard("Shard" + i);
+ partitions.get(i).forEach(binding -> builder.put(binding, shard));
+ }
+ return builder.build();
+ }
+
+ private static ImmutableList<ImmutableList<Binding>> bindingPartitions(
+ BindingGraph graph, CompilerOptions compilerOptions) {
+ int bindingsPerShard = compilerOptions.keysPerComponentShard(graph.componentTypeElement());
+ int maxPartitions = (graph.localBindingNodes().size() / bindingsPerShard) + 1;
+ if (maxPartitions <= 1) {
+ return ImmutableList.of(
+ graph.localBindingNodes().stream().map(BindingNode::delegate).collect(toImmutableList()));
+ }
+
+ // Iterate through all SCCs in order until all bindings local to this component are partitioned.
+ List<Binding> currPartition = new ArrayList<>(bindingsPerShard);
+ ImmutableList.Builder<ImmutableList<Binding>> partitions =
+ ImmutableList.builderWithExpectedSize(maxPartitions);
+ for (ImmutableSet<Node> nodes : graph.topLevelBindingGraph().stronglyConnectedNodes()) {
+ nodes.stream()
+ .flatMap(instancesOf(BindingNode.class))
+ .filter(bindingNode -> bindingNode.componentPath().equals(graph.componentPath()))
+ .map(BindingNode::delegate)
+ .forEach(currPartition::add);
+ if (currPartition.size() >= bindingsPerShard) {
+ partitions.add(ImmutableList.copyOf(currPartition));
+ currPartition = new ArrayList<>(bindingsPerShard);
+ }
+ }
+ if (!currPartition.isEmpty()) {
+ partitions.add(ImmutableList.copyOf(currPartition));
+ }
+ return partitions.build();
+ }
+
+ /** The boolean parameter of the onProducerFutureCancelled method. */
+ public static final ParameterSpec MAY_INTERRUPT_IF_RUNNING_PARAM =
+ ParameterSpec.builder(boolean.class, "mayInterruptIfRunning").build();
+
+ private static final String CANCELLATION_LISTENER_METHOD_NAME = "onProducerFutureCancelled";
+
+ /**
+ * How many statements per {@code initialize()} or {@code onProducerFutureCancelled()} method
+ * before they get partitioned.
+ */
+ private static final int STATEMENTS_PER_METHOD = 100;
+
+ private final ShardImplementation componentShard;
+ private final ImmutableMap<Binding, ShardImplementation> shardsByBinding;
+ private final Map<ShardImplementation, FieldSpec> shardFieldsByImplementation = new HashMap<>();
+ private final List<CodeBlock> shardInitializations = new ArrayList<>();
+ private final List<CodeBlock> shardCancellations = new ArrayList<>();
+ private final Optional<ComponentImplementation> parent;
+ private final ChildComponentImplementationFactory childComponentImplementationFactory;
+ private final Provider<ComponentRequestRepresentations> bindingExpressionsProvider;
+ private final Provider<ComponentCreatorImplementationFactory>
+ componentCreatorImplementationFactoryProvider;
private final BindingGraph graph;
- private final ClassName name;
- private final TypeSpec.Builder component;
- private final SubcomponentNames subcomponentNames;
- private final CompilerOptions compilerOptions;
- private final CodeBlock externalReferenceBlock;
- private final UniqueNameSet componentFieldNames = new UniqueNameSet();
- private final UniqueNameSet componentMethodNames = new UniqueNameSet();
- private final List<CodeBlock> initializations = new ArrayList<>();
- private final List<CodeBlock> componentRequirementInitializations = new ArrayList<>();
- private final Map<ComponentRequirement, String> componentRequirementParameterNames =
- new HashMap<>();
- private final Set<Key> cancellableProducerKeys = new LinkedHashSet<>();
- private final ListMultimap<FieldSpecKind, FieldSpec> fieldSpecsMap =
- MultimapBuilder.enumKeys(FieldSpecKind.class).arrayListValues().build();
- private final ListMultimap<MethodSpecKind, MethodSpec> methodSpecsMap =
- MultimapBuilder.enumKeys(MethodSpecKind.class).arrayListValues().build();
- private final ListMultimap<TypeSpecKind, TypeSpec> typeSpecsMap =
- MultimapBuilder.enumKeys(TypeSpecKind.class).arrayListValues().build();
- private final List<Supplier<TypeSpec>> typeSuppliers = new ArrayList<>();
-
- private ComponentImplementation(
+ private final ComponentNames componentNames;
+ private final DaggerElements elements;
+ private final DaggerTypes types;
+ private final ImmutableMap<ComponentImplementation, FieldSpec> componentFieldsByImplementation;
+ private final XMessager messager;
+ private final CompilerMode compilerMode;
+
+ @Inject
+ ComponentImplementation(
+ @ParentComponent Optional<ComponentImplementation> parent,
+ ChildComponentImplementationFactory childComponentImplementationFactory,
+ // Inject as Provider<> to prevent a cycle.
+ Provider<ComponentRequestRepresentations> bindingExpressionsProvider,
+ Provider<ComponentCreatorImplementationFactory> componentCreatorImplementationFactoryProvider,
BindingGraph graph,
- ClassName name,
- SubcomponentNames subcomponentNames,
- CompilerOptions compilerOptions) {
+ ComponentNames componentNames,
+ CompilerOptions compilerOptions,
+ DaggerElements elements,
+ DaggerTypes types,
+ XMessager messager) {
+ this.parent = parent;
+ this.childComponentImplementationFactory = childComponentImplementationFactory;
+ this.bindingExpressionsProvider = bindingExpressionsProvider;
+ this.componentCreatorImplementationFactoryProvider =
+ componentCreatorImplementationFactoryProvider;
this.graph = graph;
- this.name = name;
- this.component = classBuilder(name);
- this.subcomponentNames = subcomponentNames;
- this.shardOwner = Optional.empty();
- this.externalReferenceBlock = CodeBlock.of("$T.this", name);
- this.compilerOptions = compilerOptions;
+ this.componentNames = componentNames;
+ this.elements = elements;
+ this.types = types;
+
+ // The first group of keys belong to the component itself. We call this the componentShard.
+ this.componentShard = new ShardImplementation(componentNames.get(graph.componentPath()));
+
+ // Claim the method names for all local and inherited methods on the component type.
+ elements
+ .getLocalAndInheritedMethods(toJavac(graph.componentTypeElement()))
+ .forEach(method -> componentShard.componentMethodNames.claim(method.getSimpleName()));
+
+ // Create the shards for this component, indexed by binding.
+ this.shardsByBinding = createShardsByBinding(componentShard, graph, compilerOptions);
+
+ // Create and claim the fields for this and all ancestor components stored as fields.
+ this.componentFieldsByImplementation =
+ createComponentFieldsByImplementation(this, compilerOptions);
+ this.messager = messager;
+ XTypeElement typeElement = rootComponentImplementation().componentDescriptor().typeElement();
+ this.compilerMode =
+ compilerOptions.fastInit(typeElement)
+ ? CompilerMode.FAST_INIT
+ : (compilerOptions.experimentalMergedMode(typeElement)
+ ? CompilerMode.EXPERIMENTAL_MERGED_MODE
+ : CompilerMode.DEFAULT);
+ }
+
+ /**
+ * Returns the shard for a given {@link Binding}.
+ *
+ * <p>Each set of {@link CompilerOptions#keysPerShard()} will get its own shard instance.
+ */
+ public ShardImplementation shardImplementation(Binding binding) {
+ checkState(shardsByBinding.containsKey(binding), "No shard in %s for: %s", name(), binding);
+ return shardsByBinding.get(binding);
}
- private ComponentImplementation(ComponentImplementation shardOwner, ClassName shardName) {
- this.graph = shardOwner.graph;
- this.name = shardName;
- this.component = classBuilder(shardName);
- this.subcomponentNames = shardOwner.subcomponentNames;
- this.compilerOptions = shardOwner.compilerOptions;
- this.shardOwner = Optional.of(shardOwner);
- String fieldName = UPPER_CAMEL.to(LOWER_CAMEL, name.simpleName());
- String uniqueFieldName = shardOwner.getUniqueFieldName(fieldName);
- this.externalReferenceBlock = CodeBlock.of("$T.this.$N", shardOwner.name, uniqueFieldName);
- shardOwner.addTypeSupplier(() -> generate().build());
- shardOwner.addField(
- FieldSpecKind.COMPONENT_SHARD,
- FieldSpec.builder(name, uniqueFieldName, PRIVATE, FINAL)
- .initializer("new $T()", name)
- .build());
+ /** Returns the root {@link ComponentImplementation}. */
+ ComponentImplementation rootComponentImplementation() {
+ return parent.map(ComponentImplementation::rootComponentImplementation).orElse(this);
}
- /** Returns a component implementation for a top-level component. */
- public static ComponentImplementation topLevelComponentImplementation(
- BindingGraph graph,
- ClassName name,
- SubcomponentNames subcomponentNames,
- CompilerOptions compilerOptions) {
- return new ComponentImplementation(graph, name, subcomponentNames, compilerOptions);
+ /** Returns a reference to this implementation when called from a different class. */
+ public CodeBlock componentFieldReference() {
+ // TODO(bcorso): This currently relies on all requesting classes having a reference to the
+ // component with the same name, which is kind of sketchy. Try to think of a better way that
+ // can accomodate the component missing in some classes if it's not used.
+ return CodeBlock.of("$N", componentFieldsByImplementation.get(this));
}
- /** Returns a component implementation that is a child of the current implementation. */
- public ComponentImplementation childComponentImplementation(BindingGraph graph) {
- checkState(!shardOwner.isPresent(), "Shards cannot create child components.");
- ClassName childName = getSubcomponentName(graph.componentDescriptor());
- return new ComponentImplementation(graph, childName, subcomponentNames, compilerOptions);
+ /** Returns the fields for all components in the component path. */
+ public ImmutableList<FieldSpec> componentFields() {
+ return ImmutableList.copyOf(componentFieldsByImplementation.values());
}
- /** Returns a component implementation that is a shard of the current implementation. */
- public ComponentImplementation shardImplementation(Key key) {
- checkState(!shardOwner.isPresent(), "Shards cannot create other shards.");
- if (!shardsByKey.containsKey(key)) {
- int keysPerShard = compilerOptions.keysPerComponentShard(graph.componentTypeElement());
- if (!shardsByKey.isEmpty() && shardsByKey.size() % keysPerShard == 0) {
- ClassName shardName = name.nestedClass("Shard" + shardsByKey.size() / keysPerShard);
- currentShard = new ComponentImplementation(this, shardName);
- }
- shardsByKey.put(key, currentShard);
- }
- return shardsByKey.get(key);
+ /** Returns the fields for all components in the component path except the current component. */
+ public ImmutableList<FieldSpec> creatorComponentFields() {
+ return componentFieldsByImplementation.entrySet().stream()
+ .filter(entry -> !this.equals(entry.getKey()))
+ .map(Map.Entry::getValue)
+ .collect(toImmutableList());
}
- /** Returns a reference to this compenent when called from a class nested in this component. */
- public CodeBlock externalReferenceBlock() {
- return externalReferenceBlock;
+ private static ImmutableMap<ComponentImplementation, FieldSpec>
+ createComponentFieldsByImplementation(
+ ComponentImplementation componentImplementation, CompilerOptions compilerOptions) {
+ checkArgument(
+ componentImplementation.componentShard != null,
+ "The component shard must be set before computing the component fields.");
+ ImmutableList.Builder<ComponentImplementation> builder = ImmutableList.builder();
+ for (ComponentImplementation curr = componentImplementation;
+ curr != null;
+ curr = curr.parent.orElse(null)) {
+ builder.add(curr);
+ }
+ // For better readability when adding these fields/parameters to generated code, we collect the
+ // component implementations in reverse order so that parents appear before children.
+ return builder.build().reverse().stream()
+ .collect(
+ toImmutableMap(
+ componentImpl -> componentImpl,
+ componentImpl -> {
+ ClassName component =
+ componentImpl.graph.componentPath().currentComponent().className();
+ ClassName fieldType = componentImpl.name();
+ String fieldName =
+ componentImpl.isNested()
+ ? simpleVariableName(componentImpl.name())
+ : simpleVariableName(component);
+ FieldSpec.Builder field = FieldSpec.builder(fieldType, fieldName, PRIVATE, FINAL);
+ componentImplementation.componentShard.componentFieldNames.claim(fieldName);
+
+ return field.build();
+ }));
+ }
+ /** Returns the shard representing the {@link ComponentImplementation} itself. */
+ public ShardImplementation getComponentShard() {
+ return componentShard;
}
- // TODO(ronshapiro): see if we can remove this method and instead inject it in the objects that
- // need it.
/** Returns the binding graph for the component being generated. */
public BindingGraph graph() {
- return graph;
+ return componentShard.graph();
}
/** Returns the descriptor for the component being generated. */
public ComponentDescriptor componentDescriptor() {
- return graph.componentDescriptor();
+ return componentShard.componentDescriptor();
}
/** Returns the name of the component. */
public ClassName name() {
- return name;
+ return componentShard.name;
}
- /** Returns whether or not the implementation is nested within another class. */
- public boolean isNested() {
- return name.enclosingClassName() != null;
+ /** Returns if the current compile mode is fast init. */
+ public CompilerMode compilerMode() {
+ return compilerMode;
}
- /**
- * Returns the kind of this component's creator.
- *
- * @throws IllegalStateException if the component has no creator
- */
- private ComponentCreatorKind creatorKind() {
- checkState(componentDescriptor().hasCreator());
- return componentDescriptor()
- .creatorDescriptor()
- .map(ComponentCreatorDescriptor::kind)
- .orElse(BUILDER);
+ /** Returns whether or not the implementation is nested within another class. */
+ private boolean isNested() {
+ return name().enclosingClassName() != null;
}
/**
@@ -264,172 +427,666 @@ public final class ComponentImplementation {
* generated class unless this is a top-level component, in which case it will be nested.
*/
public ClassName getCreatorName() {
- return isNested()
- ? name.peerClass(subcomponentNames.getCreatorName(componentDescriptor()))
- : name.nestedClass(creatorKind().typeName());
+ return componentNames.getCreatorName(graph.componentPath());
}
- /** Returns the name of the nested implementation class for a child component. */
- private ClassName getSubcomponentName(ComponentDescriptor childDescriptor) {
- checkArgument(
- componentDescriptor().childComponents().contains(childDescriptor),
- "%s is not a child component of %s",
- childDescriptor.typeElement(),
- componentDescriptor().typeElement());
- // TODO(erichang): Hacky fix to shorten the suffix if we're too deeply
- // nested to save on file name length. 2 chosen arbitrarily.
- String suffix = name.simpleNames().size() > 2 ? "I" : "Impl";
- return name.nestedClass(subcomponentNames.get(childDescriptor) + suffix);
+ /** Generates the component and returns the resulting {@link TypeSpec}. */
+ public TypeSpec generate() {
+ return componentShard.generate();
}
/**
- * Returns the simple name of the creator implementation class for the given subcomponent creator
- * {@link Key}.
+ * The implementation of a shard.
+ *
+ * <p>The purpose of a shard is to allow a component implemenation to be split into multiple
+ * classes, where each class owns the creation logic for a set of keys. Sharding is useful for
+ * large component implementations, where a single component implementation class can reach size
+ * limitations, such as the constant pool size.
+ *
+ * <p>When generating the actual sources, the creation logic within the first instance of {@link
+ * ShardImplementation} will go into the component implementation class itself (e.g. {@code
+ * MySubcomponentImpl}). Each subsequent instance of {@link ShardImplementation} will generate a
+ * nested "shard" class within the component implementation (e.g. {@code
+ * MySubcomponentImpl.Shard1}, {@code MySubcomponentImpl.Shard2}, etc).
*/
- String getSubcomponentCreatorSimpleName(Key key) {
- return subcomponentNames.getCreatorName(key);
- }
+ public final class ShardImplementation {
+ private final ClassName name;
+ private final UniqueNameSet componentFieldNames = new UniqueNameSet();
+ private final UniqueNameSet componentMethodNames = new UniqueNameSet();
+ private final UniqueNameSet componentClassNames = new UniqueNameSet();
+ private final UniqueNameSet assistedParamNames = new UniqueNameSet();
+ private final List<CodeBlock> initializations = new ArrayList<>();
+ private final Map<Key, CodeBlock> cancellations = new LinkedHashMap<>();
+ private final Map<VariableElement, String> uniqueAssistedName = new LinkedHashMap<>();
+ private final List<CodeBlock> componentRequirementInitializations = new ArrayList<>();
+ private final ImmutableMap<ComponentRequirement, ParameterSpec> constructorParameters;
+ private final ListMultimap<FieldSpecKind, FieldSpec> fieldSpecsMap =
+ MultimapBuilder.enumKeys(FieldSpecKind.class).arrayListValues().build();
+ private final ListMultimap<MethodSpecKind, MethodSpec> methodSpecsMap =
+ MultimapBuilder.enumKeys(MethodSpecKind.class).arrayListValues().build();
+ private final ListMultimap<TypeSpecKind, TypeSpec> typeSpecsMap =
+ MultimapBuilder.enumKeys(TypeSpecKind.class).arrayListValues().build();
+ private final List<Supplier<TypeSpec>> typeSuppliers = new ArrayList<>();
+ private boolean initialized = false; // This is used for initializing assistedParamNames.
- /** Returns {@code true} if {@code type} is accessible from the generated component. */
- boolean isTypeAccessible(TypeMirror type) {
- return isTypeAccessibleFrom(type, name.packageName());
- }
+ private ShardImplementation(ClassName name) {
+ this.name = name;
+ if (graph.componentDescriptor().isProduction()) {
+ claimMethodName(CANCELLATION_LISTENER_METHOD_NAME);
+ }
- /** Adds the given super type to the component. */
- public void addSupertype(TypeElement supertype) {
- TypeSpecs.addSupertype(component, supertype);
- }
+ // Build the map of constructor parameters for this shard and claim the field names to prevent
+ // collisions between the constructor parameters and fields.
+ constructorParameters =
+ constructorRequirements(graph).stream()
+ .collect(
+ toImmutableMap(
+ requirement -> requirement,
+ requirement ->
+ ParameterSpec.builder(
+ requirement.type().getTypeName(),
+ getUniqueFieldName(requirement.variableName() + "Param"))
+ .build()));
+ }
- // TODO(dpb): Consider taking FieldSpec, and returning identical FieldSpec with unique name?
- /** Adds the given field to the component. */
- public void addField(FieldSpecKind fieldKind, FieldSpec fieldSpec) {
- fieldSpecsMap.put(fieldKind, fieldSpec);
- }
+ private ShardImplementation createShard(String shardName) {
+ checkState(isComponentShard(), "Only the componentShard can create other shards.");
+ return new ShardImplementation(name.nestedClass(shardName));
+ }
- // TODO(dpb): Consider taking MethodSpec, and returning identical MethodSpec with unique name?
- /** Adds the given method to the component. */
- public void addMethod(MethodSpecKind methodKind, MethodSpec methodSpec) {
- methodSpecsMap.put(methodKind, methodSpec);
- }
+ /** Returns the {@link ComponentImplementation} that owns this shard. */
+ public ComponentImplementation getComponentImplementation() {
+ return ComponentImplementation.this;
+ }
- /** Adds the given annotation to the component. */
- public void addAnnotation(AnnotationSpec annotation) {
- component.addAnnotation(annotation);
- }
+ /**
+ * Returns {@code true} if this shard represents the component implementation rather than a
+ * separate {@code Shard} class.
+ */
+ public boolean isComponentShard() {
+ return this == componentShard;
+ }
- /** Adds the given type to the component. */
- public void addType(TypeSpecKind typeKind, TypeSpec typeSpec) {
- typeSpecsMap.put(typeKind, typeSpec);
- }
+ /** Returns the fields for all components in the component path by component implementation. */
+ public ImmutableMap<ComponentImplementation, FieldSpec> componentFieldsByImplementation() {
+ return componentFieldsByImplementation;
+ }
- /** Adds a {@link Supplier} for the SwitchingProvider for the component. */
- void addTypeSupplier(Supplier<TypeSpec> typeSpecSupplier) {
- typeSuppliers.add(typeSpecSupplier);
- }
+ /** Returns a reference to this implementation when called from a different class. */
+ public CodeBlock shardFieldReference() {
+ if (!isComponentShard() && !shardFieldsByImplementation.containsKey(this)) {
+ // Add the shard if this is the first time it's requested by something.
+ String shardFieldName =
+ componentShard.getUniqueFieldName(UPPER_CAMEL.to(LOWER_CAMEL, name.simpleName()));
+ FieldSpec shardField = FieldSpec.builder(name, shardFieldName, PRIVATE).build();
- /** Adds the given code block to the initialize methods of the component. */
- void addInitialization(CodeBlock codeBlock) {
- initializations.add(codeBlock);
- }
+ shardFieldsByImplementation.put(this, shardField);
+ }
+ // TODO(bcorso): This currently relies on all requesting classes having a reference to the
+ // component with the same name, which is kind of sketchy. Try to think of a better way that
+ // can accomodate the component missing in some classes if it's not used.
+ return isComponentShard()
+ ? componentFieldReference()
+ : CodeBlock.of("$L.$N", componentFieldReference(), shardFieldsByImplementation.get(this));
+ }
- /** Adds the given code block that initializes a {@link ComponentRequirement}. */
- void addComponentRequirementInitialization(CodeBlock codeBlock) {
- componentRequirementInitializations.add(codeBlock);
- }
+ // TODO(ronshapiro): see if we can remove this method and instead inject it in the objects that
+ // need it.
+ /** Returns the binding graph for the component being generated. */
+ public BindingGraph graph() {
+ return graph;
+ }
- /**
- * Marks the given key of a producer as one that should have a cancellation statement in the
- * cancellation listener method of the component.
- */
- void addCancellableProducerKey(Key key) {
- cancellableProducerKeys.add(key);
- }
+ /** Returns the descriptor for the component being generated. */
+ public ComponentDescriptor componentDescriptor() {
+ return graph.componentDescriptor();
+ }
- /** Returns a new, unique field name for the component based on the given name. */
- String getUniqueFieldName(String name) {
- return componentFieldNames.getUniqueName(name);
- }
+ /** Returns the name of the component. */
+ public ClassName name() {
+ return name;
+ }
- /** Returns a new, unique method name for the component based on the given name. */
- public String getUniqueMethodName(String name) {
- return componentMethodNames.getUniqueName(name);
- }
+ /**
+ * Returns the name of the creator implementation class for the given subcomponent creator
+ * {@link Key}.
+ */
+ ClassName getSubcomponentCreatorSimpleName(Key creatorKey) {
+ return componentNames.getSubcomponentCreatorName(graph.componentPath(), creatorKey);
+ }
- /** Returns a new, unique method name for a getter method for the given request. */
- String getUniqueMethodName(BindingRequest request) {
- return uniqueMethodName(request, KeyVariableNamer.name(request.key()));
- }
+ /**
+ * Returns an accessible type for this shard implementation, returns Object if the type is not
+ * accessible.
+ *
+ * <p>This method checks accessibility for public types and package private types, and it also
+ * checks protected types' accessibility.
+ */
+ TypeMirror accessibleType(TypeMirror type) {
+ // Returns the original type if the type is accessible from this shard, or returns original
+ // type's raw type if only its raw type is accessible. Otherwise, returns Object.
+ TypeMirror castedType = types.accessibleType(type, name());
+ // Previous check marks protected type as inaccessible, so a second check is needed to check
+ // if the type is protected type and accessible.
+ if (TypeName.get(castedType).equals(TypeName.OBJECT) && isTypeAccessible(type)) {
+ castedType = type;
+ }
+ return castedType;
+ }
- private String uniqueMethodName(BindingRequest request, String bindingName) {
- // This name is intentionally made to match the name for fields in fastInit
- // in order to reduce the constant pool size. b/162004246
- String baseMethodName = bindingName
- + (request.isRequestKind(RequestKind.INSTANCE)
- ? ""
- : UPPER_UNDERSCORE.to(UPPER_CAMEL, request.kindName()));
- return getUniqueMethodName(baseMethodName);
- }
+ /**
+ * Returns {@code true} if {@code type} is accessible from the generated component.
+ *
+ * <p>This method checks accessibility for public types and package private types, and it also
+ * checks protected types' accessibility.
+ */
+ boolean isTypeAccessible(TypeMirror type) {
+ if (isTypeAccessibleFrom(type, name.packageName())) {
+ return true;
+ }
+ // Check if the type is protected and accessible from current component.
+ if (type instanceof DeclaredType
+ && isProtectedMemberOf(
+ MoreTypes.asDeclared(type),
+ getComponentImplementation().componentDescriptor().typeElement())) {
+ return true;
+ }
+ return false;
+ }
- /**
- * Gets the parameter name to use for the given requirement for this component, starting with the
- * given base name if no parameter name has already been selected for the requirement.
- */
- public String getParameterName(ComponentRequirement requirement, String baseName) {
- return componentRequirementParameterNames.computeIfAbsent(
- requirement, r -> getUniqueFieldName(baseName));
- }
+ // TODO(dpb): Consider taking FieldSpec, and returning identical FieldSpec with unique name?
+ /** Adds the given field to the component. */
+ public void addField(FieldSpecKind fieldKind, FieldSpec fieldSpec) {
+ fieldSpecsMap.put(fieldKind, fieldSpec);
+ }
- /** Claims a new method name for the component. Does nothing if method name already exists. */
- public void claimMethodName(CharSequence name) {
- componentMethodNames.claim(name);
- }
+ // TODO(dpb): Consider taking MethodSpec, and returning identical MethodSpec with unique name?
+ /** Adds the given method to the component. */
+ public void addMethod(MethodSpecKind methodKind, MethodSpec methodSpec) {
+ methodSpecsMap.put(methodKind, methodSpec);
+ }
- /** Returns the list of {@link CodeBlock}s that need to go in the initialize method. */
- public ImmutableList<CodeBlock> getInitializations() {
- return ImmutableList.copyOf(initializations);
- }
+ /** Adds the given type to the component. */
+ public void addType(TypeSpecKind typeKind, TypeSpec typeSpec) {
+ typeSpecsMap.put(typeKind, typeSpec);
+ }
- /**
- * Returns a list of {@link CodeBlock}s for initializing {@link ComponentRequirement}s.
- *
- * <p>These initializations are kept separate from {@link #getInitializations()} because they must
- * be executed before the initializations of any framework instance initializations in a
- * superclass implementation that may depend on the instances. We cannot use the same strategy
- * that we use for framework instances (i.e. wrap in a {@link dagger.internal.DelegateFactory} or
- * {@link dagger.producers.internal.DelegateProducer} since the types of these initialized fields
- * have no interface type that we can write a proxy for.
- */
- // TODO(cgdecker): can these be inlined with getInitializations() now that we've turned down
- // ahead-of-time subcomponents?
- public ImmutableList<CodeBlock> getComponentRequirementInitializations() {
- return ImmutableList.copyOf(componentRequirementInitializations);
- }
+ /** Adds a {@link Supplier} for the SwitchingProvider for the component. */
+ void addTypeSupplier(Supplier<TypeSpec> typeSpecSupplier) {
+ typeSuppliers.add(typeSpecSupplier);
+ }
- /**
- * Returns the list of producer {@link Key}s that need cancellation statements in the cancellation
- * listener method.
- */
- public ImmutableList<Key> getCancellableProducerKeys() {
- return ImmutableList.copyOf(cancellableProducerKeys);
- }
+ /** Adds the given code block to the initialize methods of the component. */
+ void addInitialization(CodeBlock codeBlock) {
+ initializations.add(codeBlock);
+ }
+
+ /** Adds the given code block that initializes a {@link ComponentRequirement}. */
+ void addComponentRequirementInitialization(CodeBlock codeBlock) {
+ componentRequirementInitializations.add(codeBlock);
+ }
+
+ /**
+ * Adds the given cancellation statement to the cancellation listener method of the component.
+ */
+ void addCancellation(Key key, CodeBlock codeBlock) {
+ // Store cancellations by key to avoid adding the same cancellation twice.
+ cancellations.putIfAbsent(key, codeBlock);
+ }
+
+ /** Returns a new, unique field name for the component based on the given name. */
+ String getUniqueFieldName(String name) {
+ return componentFieldNames.getUniqueName(name);
+ }
+
+ String getUniqueAssistedParamName(String name) {
+ if (!initialized) {
+ // Assisted params will be used in switching provider, so they can't conflict with component
+ // field names in switching provider. {@link UniqueNameSet#getUniqueName} will add the
+ // component field names to the unique set if it does not exists. If the name already exists
+ // in the set, then a dedupe will be performed automatically on the passed in name, and the
+ // newly created unique name will then be added to the set.
+ componentFieldsByImplementation()
+ .values()
+ .forEach(fieldSpec -> assistedParamNames.getUniqueName(fieldSpec.name));
+ initialized = true;
+ }
+ return assistedParamNames.getUniqueName(name);
+ }
+
+ public String getUniqueFieldNameForAssistedParam(VariableElement element) {
+ if (uniqueAssistedName.containsKey(element)) {
+ return uniqueAssistedName.get(element);
+ }
+ String name = getUniqueAssistedParamName(element.getSimpleName().toString());
+ uniqueAssistedName.put(element, name);
+ return name;
+ }
+
+ /** Returns a new, unique nested class name for the component based on the given name. */
+ public String getUniqueMethodName(String name) {
+ return componentMethodNames.getUniqueName(name);
+ }
+
+ /** Returns a new, unique method name for a getter method for the given request. */
+ String getUniqueMethodName(BindingRequest request) {
+ return uniqueMethodName(request, KeyVariableNamer.name(request.key()));
+ }
+
+ /** Returns a new, unique method name for the component based on the given name. */
+ public String getUniqueClassName(String name) {
+ return componentClassNames.getUniqueName(name);
+ }
+
+ private String uniqueMethodName(BindingRequest request, String bindingName) {
+ // This name is intentionally made to match the name for fields in fastInit
+ // in order to reduce the constant pool size. b/162004246
+ String baseMethodName =
+ bindingName
+ + (request.isRequestKind(RequestKind.INSTANCE)
+ ? ""
+ : UPPER_UNDERSCORE.to(UPPER_CAMEL, request.kindName()));
+ return getUniqueMethodName(baseMethodName);
+ }
+
+ /**
+ * Gets the parameter name to use for the given requirement for this component, starting with
+ * the given base name if no parameter name has already been selected for the requirement.
+ */
+ public String getParameterName(ComponentRequirement requirement) {
+ return constructorParameters.get(requirement).name;
+ }
+
+ /** Claims a new method name for the component. Does nothing if method name already exists. */
+ public void claimMethodName(CharSequence name) {
+ componentMethodNames.claim(name);
+ }
+
+ /** Generates the component and returns the resulting {@link TypeSpec.Builder}. */
+ private TypeSpec generate() {
+ TypeSpec.Builder builder = classBuilder(name);
+
+ if (isComponentShard()) {
+ TypeSpecs.addSupertype(builder, graph.componentTypeElement());
+ addCreator();
+ addFactoryMethods();
+ addInterfaceMethods();
+ addChildComponents();
+ addShards();
+ }
+
+ addConstructorAndInitializationMethods();
+
+ if (graph.componentDescriptor().isProduction()) {
+ if (isComponentShard() || !cancellations.isEmpty()) {
+ TypeSpecs.addSupertype(
+ builder, elements.getTypeElement(TypeNames.CANCELLATION_LISTENER.canonicalName()));
+ addCancellationListenerImplementation();
+ }
+ }
+
+ modifiers().forEach(builder::addModifiers);
+ fieldSpecsMap.asMap().values().forEach(builder::addFields);
+ methodSpecsMap.asMap().values().forEach(builder::addMethods);
+ typeSpecsMap.asMap().values().forEach(builder::addTypes);
+ typeSuppliers.stream().map(Supplier::get).forEach(builder::addType);
+ return builder.build();
+ }
+
+ private ImmutableSet<Modifier> modifiers() {
+ if (!isComponentShard()) {
+ // TODO(bcorso): Consider making shards static and unnested too?
+ return ImmutableSet.of(PRIVATE, FINAL);
+ } else if (isNested()) {
+ return ImmutableSet.of(PRIVATE, STATIC, FINAL);
+ }
+ return graph.componentTypeElement().isPublic()
+ // TODO(ronshapiro): perhaps all generated components should be non-public?
+ ? ImmutableSet.of(PUBLIC, FINAL)
+ : ImmutableSet.of(FINAL);
+ }
+
+ private void addCreator() {
+ componentCreatorImplementationFactoryProvider
+ .get()
+ .create()
+ .map(ComponentCreatorImplementation::spec)
+ .ifPresent(
+ creator ->
+ rootComponentImplementation()
+ .getComponentShard()
+ .addType(TypeSpecKind.COMPONENT_CREATOR, creator));
+ }
- /** Generates the component and returns the resulting {@link TypeSpec.Builder}. */
- public TypeSpec.Builder generate() {
- modifiers().forEach(component::addModifiers);
- fieldSpecsMap.asMap().values().forEach(component::addFields);
- methodSpecsMap.asMap().values().forEach(component::addMethods);
- typeSpecsMap.asMap().values().forEach(component::addTypes);
- typeSuppliers.stream().map(Supplier::get).forEach(component::addType);
- return component;
+ private void addFactoryMethods() {
+ if (parent.isPresent()) {
+ graph
+ .factoryMethod()
+ .map(XConverters::toJavac)
+ .ifPresent(this::createSubcomponentFactoryMethod);
+ } else {
+ createRootComponentFactoryMethod();
+ }
+ }
+
+ private void createRootComponentFactoryMethod() {
+ checkState(!parent.isPresent());
+ // Top-level components have a static method that returns a builder or factory for the
+ // component. If the user defined a @Component.Builder or @Component.Factory, an
+ // implementation of their type is returned. Otherwise, an autogenerated Builder type is
+ // returned.
+ // TODO(cgdecker): Replace this abomination with a small class?
+ // Better yet, change things so that an autogenerated builder type has a descriptor of sorts
+ // just like a user-defined creator type.
+ ComponentCreatorKind creatorKind;
+ ClassName creatorType;
+ String factoryMethodName;
+ boolean noArgFactoryMethod;
+ Optional<ComponentCreatorDescriptor> creatorDescriptor =
+ graph.componentDescriptor().creatorDescriptor();
+ if (creatorDescriptor.isPresent()) {
+ ComponentCreatorDescriptor descriptor = creatorDescriptor.get();
+ creatorKind = descriptor.kind();
+ creatorType = descriptor.typeElement().getClassName();
+ factoryMethodName = getSimpleName(descriptor.factoryMethod());
+ noArgFactoryMethod = descriptor.factoryParameters().isEmpty();
+ } else {
+ creatorKind = BUILDER;
+ creatorType = getCreatorName();
+ factoryMethodName = "build";
+ noArgFactoryMethod = true;
+ }
+ validateMethodNameDoesNotOverrideGeneratedCreator(creatorKind.methodName());
+ claimMethodName(creatorKind.methodName());
+ MethodSpec creatorFactoryMethod =
+ methodBuilder(creatorKind.methodName())
+ .addModifiers(PUBLIC, STATIC)
+ .returns(creatorType)
+ .addStatement("return new $T()", getCreatorName())
+ .build();
+ addMethod(MethodSpecKind.BUILDER_METHOD, creatorFactoryMethod);
+ if (noArgFactoryMethod && canInstantiateAllRequirements()) {
+ validateMethodNameDoesNotOverrideGeneratedCreator("create");
+ claimMethodName("create");
+ addMethod(
+ MethodSpecKind.BUILDER_METHOD,
+ methodBuilder("create")
+ .returns(graph.componentTypeElement().getClassName())
+ .addModifiers(PUBLIC, STATIC)
+ .addStatement("return new $L().$L()", creatorKind.typeName(), factoryMethodName)
+ .build());
+ }
+ }
+
+ private void validateMethodNameDoesNotOverrideGeneratedCreator(String creatorName) {
+ // Check if there is any client added method has the same signature as generated creatorName.
+ MoreElements.getAllMethods(toJavac(graph.componentTypeElement()), types, elements).stream()
+ .filter(method -> method.getSimpleName().contentEquals(creatorName))
+ .filter(method -> method.getParameters().isEmpty())
+ .filter(method -> !method.getModifiers().contains(Modifier.STATIC))
+ .forEach(
+ (ExecutableElement method) ->
+ messager.printMessage(
+ ERROR,
+ String.format(
+ "Cannot override generated method: %s.%s()",
+ method.getEnclosingElement().getSimpleName(), method.getSimpleName())));
+ }
+
+ /** {@code true} if all of the graph's required dependencies can be automatically constructed */
+ private boolean canInstantiateAllRequirements() {
+ return !Iterables.any(
+ graph.componentRequirements(), ComponentRequirement::requiresAPassedInstance);
+ }
+
+ private void createSubcomponentFactoryMethod(ExecutableElement factoryMethod) {
+ checkState(parent.isPresent());
+ Collection<ParameterSpec> params =
+ Maps.transformValues(
+ graph.factoryMethodParameters(),
+ parameter -> ParameterSpec.get(toJavac(parameter)))
+ .values();
+ DeclaredType parentType =
+ asDeclared(toJavac(parent.get().graph().componentTypeElement()).asType());
+ MethodSpec.Builder method = MethodSpec.overriding(factoryMethod, parentType, types);
+ params.forEach(
+ param -> method.addStatement("$T.checkNotNull($N)", Preconditions.class, param));
+ method.addStatement(
+ "return new $T($L)",
+ name(),
+ parameterNames(
+ ImmutableList.<ParameterSpec>builder()
+ .addAll(
+ creatorComponentFields().stream()
+ .map(field -> ParameterSpec.builder(field.type, field.name).build())
+ .collect(toImmutableList()))
+ .addAll(params)
+ .build()));
+
+ parent.get().getComponentShard().addMethod(COMPONENT_METHOD, method.build());
+ }
+
+ private void addInterfaceMethods() {
+ // Each component method may have been declared by several supertypes. We want to implement
+ // only one method for each distinct signature.
+ XType componentType = graph.componentTypeElement().getType();
+ Set<MethodSignature> signatures = Sets.newHashSet();
+ for (ComponentMethodDescriptor method : graph.componentDescriptor().entryPointMethods()) {
+ if (signatures.add(MethodSignature.forComponentMethod(method, componentType))) {
+ addMethod(COMPONENT_METHOD, bindingExpressionsProvider.get().getComponentMethod(method));
+ }
+ }
+ }
+
+ private void addChildComponents() {
+ for (BindingGraph subgraph : graph.subgraphs()) {
+ rootComponentImplementation()
+ .getComponentShard()
+ .addType(
+ TypeSpecKind.SUBCOMPONENT,
+ childComponentImplementationFactory.create(subgraph).generate());
+ }
+ }
+
+ private void addShards() {
+ // Generate all shards and add them to this component implementation.
+ for (ShardImplementation shard : ImmutableSet.copyOf(shardsByBinding.values())) {
+ if (shardFieldsByImplementation.containsKey(shard)) {
+ addField(FieldSpecKind.COMPONENT_SHARD_FIELD, shardFieldsByImplementation.get(shard));
+ TypeSpec shardTypeSpec = shard.generate();
+ addType(TypeSpecKind.COMPONENT_SHARD_TYPE, shardTypeSpec);
+ }
+ }
+ }
+
+ /** Creates and adds the constructor and methods needed for initializing the component. */
+ private void addConstructorAndInitializationMethods() {
+ MethodSpec.Builder constructor = constructorBuilder().addModifiers(PRIVATE);
+ ImmutableList<ParameterSpec> parameters = constructorParameters.values().asList();
+
+ if (isComponentShard()) {
+ // Add a constructor parameter and initialization for each component field. We initialize
+ // these fields immediately so that we don't need to be pass them to each initialize method
+ // and shard constructor.
+ componentFieldsByImplementation()
+ .forEach(
+ (componentImplementation, field) -> {
+ if (componentImplementation.equals(ComponentImplementation.this)) {
+ // For the self-referenced component field,
+ // just initialize it in the initializer.
+ addField(
+ FieldSpecKind.COMPONENT_REQUIREMENT_FIELD,
+ field.toBuilder().initializer("this").build());
+ } else {
+ addField(FieldSpecKind.COMPONENT_REQUIREMENT_FIELD, field);
+ constructor.addStatement("this.$1N = $1N", field);
+ constructor.addParameter(field.type, field.name);
+ }
+ });
+ constructor.addCode(CodeBlocks.concat(componentRequirementInitializations));
+ }
+ constructor.addParameters(parameters);
+
+ // TODO(cgdecker): It's not the case that each initialize() method has need for all of the
+ // given parameters. In some cases, those parameters may have already been assigned to fields
+ // which could be referenced instead. In other cases, an initialize method may just not need
+ // some of the parameters because the set of initializations in that partition does not
+ // include any reference to them. Right now, the Dagger code has no way of getting that
+ // information because, among other things, componentImplementation.getImplementations() just
+ // returns a bunch of CodeBlocks with no semantic information. Additionally, we may not know
+ // yet whether a field will end up needing to be created for a specific requirement, and we
+ // don't want to create a field that ends up only being used during initialization.
+ CodeBlock args = parameterNames(parameters);
+ ImmutableList<MethodSpec> initializationMethods =
+ createPartitionedMethods(
+ "initialize",
+ // TODO(bcorso): Rather than passing in all of the constructor parameters, keep track
+ // of which parameters are used during initialization and only pass those. This could
+ // be useful for FastInit, where most of the initializations are just calling
+ // SwitchingProvider with no parameters.
+ makeFinal(parameters),
+ initializations,
+ methodName ->
+ methodBuilder(methodName)
+ /* TODO(gak): Strictly speaking, we only need the suppression here if we are
+ * also initializing a raw field in this method, but the structure of this
+ * code makes it awkward to pass that bit through. This will be cleaned up
+ * when we no longer separate fields and initialization as we do now. */
+ .addAnnotation(suppressWarnings(UNCHECKED)));
+
+ for (MethodSpec initializationMethod : initializationMethods) {
+ constructor.addStatement("$N($L)", initializationMethod, args);
+ addMethod(MethodSpecKind.INITIALIZE_METHOD, initializationMethod);
+ }
+
+ if (isComponentShard()) {
+ constructor.addCode(CodeBlocks.concat(shardInitializations));
+ } else {
+ // This initialization is called from the componentShard, so we need to use those args.
+ CodeBlock componentArgs =
+ parameterNames(componentShard.constructorParameters.values().asList());
+ FieldSpec shardField = shardFieldsByImplementation.get(this);
+ shardInitializations.add(CodeBlock.of("$N = new $T($L);", shardField, name, componentArgs));
+ }
+
+ addMethod(MethodSpecKind.CONSTRUCTOR, constructor.build());
+ }
+
+ private void addCancellationListenerImplementation() {
+ MethodSpec.Builder methodBuilder =
+ methodBuilder(CANCELLATION_LISTENER_METHOD_NAME)
+ .addModifiers(PUBLIC)
+ .addAnnotation(Override.class)
+ .addParameter(MAY_INTERRUPT_IF_RUNNING_PARAM);
+
+ // Reversing should order cancellations starting from entry points and going down to leaves
+ // rather than the other way around. This shouldn't really matter but seems *slightly*
+ // preferable because:
+ // When a future that another future depends on is cancelled, that cancellation will propagate
+ // up the future graph toward the entry point. Cancelling in reverse order should ensure that
+ // everything that depends on a particular node has already been cancelled when that node is
+ // cancelled, so there's no need to propagate. Otherwise, when we cancel a leaf node, it might
+ // propagate through most of the graph, making most of the cancel calls that follow in the
+ // onProducerFutureCancelled method do nothing.
+ if (isComponentShard()) {
+ methodBuilder.addCode(
+ CodeBlocks.concat(ImmutableList.copyOf(shardCancellations).reverse()));
+ } else if (!cancellations.isEmpty()) {
+ shardCancellations.add(
+ CodeBlock.of(
+ "$N.$N($N);",
+ shardFieldsByImplementation.get(this),
+ CANCELLATION_LISTENER_METHOD_NAME,
+ MAY_INTERRUPT_IF_RUNNING_PARAM));
+ }
+
+ ImmutableList<CodeBlock> cancellationStatements =
+ ImmutableList.copyOf(cancellations.values()).reverse();
+ if (cancellationStatements.size() < STATEMENTS_PER_METHOD) {
+ methodBuilder.addCode(CodeBlocks.concat(cancellationStatements)).build();
+ } else {
+ ImmutableList<MethodSpec> cancelProducersMethods =
+ createPartitionedMethods(
+ "cancelProducers",
+ ImmutableList.of(MAY_INTERRUPT_IF_RUNNING_PARAM),
+ cancellationStatements,
+ methodName -> methodBuilder(methodName).addModifiers(PRIVATE));
+ for (MethodSpec cancelProducersMethod : cancelProducersMethods) {
+ methodBuilder.addStatement(
+ "$N($N)", cancelProducersMethod, MAY_INTERRUPT_IF_RUNNING_PARAM);
+ addMethod(MethodSpecKind.CANCELLATION_LISTENER_METHOD, cancelProducersMethod);
+ }
+ }
+
+ if (isComponentShard()) {
+ cancelParentStatement().ifPresent(methodBuilder::addCode);
+ }
+
+ addMethod(MethodSpecKind.CANCELLATION_LISTENER_METHOD, methodBuilder.build());
+ }
+
+ private Optional<CodeBlock> cancelParentStatement() {
+ if (!shouldPropagateCancellationToParent()) {
+ return Optional.empty();
+ }
+ return Optional.of(
+ CodeBlock.builder()
+ .addStatement(
+ "$L.$N($N)",
+ parent.get().componentFieldReference(),
+ CANCELLATION_LISTENER_METHOD_NAME,
+ MAY_INTERRUPT_IF_RUNNING_PARAM)
+ .build());
+ }
+
+ private boolean shouldPropagateCancellationToParent() {
+ return parent.isPresent()
+ && parent
+ .get()
+ .componentDescriptor()
+ .cancellationPolicy()
+ .map(policy -> policy.fromSubcomponents().equals(PROPAGATE))
+ .orElse(false);
+ }
+
+ /**
+ * Creates one or more methods, all taking the given {@code parameters}, which partition the
+ * given list of {@code statements} among themselves such that no method has more than {@code
+ * STATEMENTS_PER_METHOD} statements in it and such that the returned methods, if called in
+ * order, will execute the {@code statements} in the given order.
+ */
+ private ImmutableList<MethodSpec> createPartitionedMethods(
+ String methodName,
+ Iterable<ParameterSpec> parameters,
+ List<CodeBlock> statements,
+ Function<String, MethodSpec.Builder> methodBuilderCreator) {
+ return Lists.partition(statements, STATEMENTS_PER_METHOD).stream()
+ .map(
+ partition ->
+ methodBuilderCreator
+ .apply(getUniqueMethodName(methodName))
+ .addModifiers(PRIVATE)
+ .addParameters(parameters)
+ .addCode(CodeBlocks.concat(partition))
+ .build())
+ .collect(toImmutableList());
+ }
}
- private ImmutableSet<Modifier> modifiers() {
- if (isNested()) {
- return ImmutableSet.of(PRIVATE, FINAL);
+ private static ImmutableList<ComponentRequirement> constructorRequirements(BindingGraph graph) {
+ if (graph.componentDescriptor().hasCreator()) {
+ return graph.componentRequirements().asList();
+ } else if (graph.factoryMethod().isPresent()) {
+ return graph.factoryMethodParameters().keySet().asList();
+ } else {
+ throw new AssertionError(
+ "Expected either a component creator or factory method but found neither.");
}
- return graph.componentTypeElement().getModifiers().contains(PUBLIC)
- // TODO(ronshapiro): perhaps all generated components should be non-public?
- ? ImmutableSet.of(PUBLIC, FINAL)
- : ImmutableSet.of(FINAL);
+ }
+
+ private static ImmutableList<ParameterSpec> makeFinal(List<ParameterSpec> parameters) {
+ return parameters.stream()
+ .map(param -> param.toBuilder().addModifiers(FINAL).build())
+ .collect(toImmutableList());
}
}
diff --git a/java/dagger/internal/codegen/writing/ComponentInstanceBindingExpression.java b/java/dagger/internal/codegen/writing/ComponentInstanceRequestRepresentation.java
index 9fa10c6e0..441ee83b2 100644
--- a/java/dagger/internal/codegen/writing/ComponentInstanceBindingExpression.java
+++ b/java/dagger/internal/codegen/writing/ComponentInstanceRequestRepresentation.java
@@ -18,26 +18,35 @@ package dagger.internal.codegen.writing;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.javapoet.Expression;
/** A binding expression for the instance of the component itself, i.e. {@code this}. */
-final class ComponentInstanceBindingExpression extends SimpleInvocationBindingExpression {
- private final ClassName componentName;
+final class ComponentInstanceRequestRepresentation extends RequestRepresentation {
+ private final ComponentImplementation componentImplementation;
private final ContributionBinding binding;
- ComponentInstanceBindingExpression(ContributionBinding binding, ClassName componentName) {
- super(binding);
+ @AssistedInject
+ ComponentInstanceRequestRepresentation(
+ @Assisted ContributionBinding binding, ComponentImplementation componentImplementation) {
+ this.componentImplementation = componentImplementation;
this.binding = binding;
- this.componentName = componentName;
}
@Override
Expression getDependencyExpression(ClassName requestingClass) {
return Expression.create(
- binding.key().type(),
- componentName.equals(requestingClass)
+ binding.key().type().java(),
+ componentImplementation.name().equals(requestingClass)
? CodeBlock.of("this")
- : CodeBlock.of("$T.this", componentName));
+ : componentImplementation.componentFieldReference());
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ ComponentInstanceRequestRepresentation create(ContributionBinding binding);
}
}
diff --git a/java/dagger/internal/codegen/writing/ComponentMethodBindingExpression.java b/java/dagger/internal/codegen/writing/ComponentMethodRequestRepresentation.java
index 7fa9aa3ed..77e313f0f 100644
--- a/java/dagger/internal/codegen/writing/ComponentMethodBindingExpression.java
+++ b/java/dagger/internal/codegen/writing/ComponentMethodRequestRepresentation.java
@@ -17,13 +17,13 @@
package dagger.internal.codegen.writing;
import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
-import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.binding.BindingRequest;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.javapoet.Expression;
import dagger.internal.codegen.langmodel.DaggerTypes;
import javax.lang.model.type.TypeMirror;
@@ -32,61 +32,58 @@ import javax.lang.model.type.TypeMirror;
*
* <p>Dependents of this binding expression will just call the component method.
*/
-final class ComponentMethodBindingExpression extends MethodBindingExpression {
+final class ComponentMethodRequestRepresentation extends MethodRequestRepresentation {
+ private final RequestRepresentation wrappedRequestRepresentation;
private final ComponentImplementation componentImplementation;
private final ComponentMethodDescriptor componentMethod;
+ private final DaggerTypes types;
- ComponentMethodBindingExpression(
- BindingRequest request,
- ContributionBinding binding,
- MethodImplementationStrategy methodImplementationStrategy,
- BindingExpression wrappedBindingExpression,
+ @AssistedInject
+ ComponentMethodRequestRepresentation(
+ @Assisted RequestRepresentation wrappedRequestRepresentation,
+ @Assisted ComponentMethodDescriptor componentMethod,
ComponentImplementation componentImplementation,
- ComponentMethodDescriptor componentMethod,
DaggerTypes types) {
- super(
- request,
- binding,
- methodImplementationStrategy,
- wrappedBindingExpression,
- componentImplementation,
- types);
- this.componentImplementation = checkNotNull(componentImplementation);
+ super(componentImplementation.getComponentShard(), types);
+ this.wrappedRequestRepresentation = checkNotNull(wrappedRequestRepresentation);
this.componentMethod = checkNotNull(componentMethod);
+ this.componentImplementation = componentImplementation;
+ this.types = types;
}
@Override
protected CodeBlock getComponentMethodImplementation(
ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
// There could be several methods on the component for the same request key and kind.
- // Only one should use the BindingMethodImplementation; the others can delegate that one. So
- // use methodImplementation.body() only if componentMethod equals the method for this instance.
-
+ // Only one should use the BindingMethodImplementation; the others can delegate that one.
// Separately, the method might be defined on a supertype that is also a supertype of some
// parent component. In that case, the same ComponentMethodDescriptor will be used to add a CMBE
// for the parent and the child. Only the parent's should use the BindingMethodImplementation;
// the child's can delegate to the parent. So use methodImplementation.body() only if
// componentName equals the component for this instance.
return componentMethod.equals(this.componentMethod) && component.equals(componentImplementation)
- ? methodBodyForComponentMethod(componentMethod)
+ ? CodeBlock.of(
+ "return $L;",
+ wrappedRequestRepresentation
+ .getDependencyExpressionForComponentMethod(componentMethod, componentImplementation)
+ .codeBlock())
: super.getComponentMethodImplementation(componentMethod, component);
}
@Override
- Expression getDependencyExpression(ClassName requestingClass) {
- // If a component method returns a primitive, update the expression's type which might be boxed.
- Expression expression = super.getDependencyExpression(requestingClass);
- TypeMirror methodReturnType = componentMethod.methodElement().getReturnType();
- return methodReturnType.getKind().isPrimitive()
- ? Expression.create(methodReturnType, expression.codeBlock())
- : expression;
+ protected CodeBlock methodCall() {
+ return CodeBlock.of("$N()", getSimpleName(componentMethod.methodElement()));
}
@Override
- protected void addMethod() {}
+ protected TypeMirror returnType() {
+ return componentMethod.resolvedReturnType(types);
+ }
- @Override
- protected String methodName() {
- return componentMethod.methodElement().getSimpleName().toString();
+ @AssistedFactory
+ static interface Factory {
+ ComponentMethodRequestRepresentation create(
+ RequestRepresentation wrappedRequestRepresentation,
+ ComponentMethodDescriptor componentMethod);
}
}
diff --git a/java/dagger/internal/codegen/writing/ComponentNames.java b/java/dagger/internal/codegen/writing/ComponentNames.java
new file mode 100644
index 000000000..d53a0f4c8
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/ComponentNames.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.binding.SourceFiles.classFileName;
+import static dagger.internal.codegen.extension.DaggerCollectors.onlyElement;
+import static java.lang.String.format;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimaps;
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.base.ComponentCreatorKind;
+import dagger.internal.codegen.base.UniqueNameSet;
+import dagger.internal.codegen.binding.BindingGraph;
+import dagger.internal.codegen.binding.ComponentCreatorDescriptor;
+import dagger.internal.codegen.binding.ComponentDescriptor;
+import dagger.internal.codegen.binding.KeyFactory;
+import dagger.spi.model.ComponentPath;
+import dagger.spi.model.Key;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import javax.inject.Inject;
+
+/**
+ * Holds the unique simple names for all components, keyed by their {@link ComponentPath} and {@link
+ * Key} of the subcomponent builder.
+ */
+public final class ComponentNames {
+ /** Returns the class name for the root component. */
+ public static ClassName getRootComponentClassName(ComponentDescriptor componentDescriptor) {
+ checkState(!componentDescriptor.isSubcomponent());
+ ClassName componentName = componentDescriptor.typeElement().getClassName();
+ return ClassName.get(componentName.packageName(), "Dagger" + classFileName(componentName));
+ }
+
+ private static final Splitter QUALIFIED_NAME_SPLITTER = Splitter.on('.');
+
+ private final ClassName rootName;
+ private final ImmutableMap<ComponentPath, String> namesByPath;
+ private final ImmutableMap<ComponentPath, String> creatorNamesByPath;
+ private final ImmutableMultimap<Key, ComponentPath> pathsByCreatorKey;
+
+ @Inject
+ ComponentNames(@TopLevel BindingGraph graph, KeyFactory keyFactory) {
+ this.rootName = getRootComponentClassName(graph.componentDescriptor());
+ this.namesByPath = namesByPath(graph);
+ this.creatorNamesByPath = creatorNamesByPath(namesByPath, graph);
+ this.pathsByCreatorKey = pathsByCreatorKey(keyFactory, graph);
+ }
+
+ /** Returns the simple component name for the given {@link ComponentDescriptor}. */
+ ClassName get(ComponentPath componentPath) {
+ return componentPath.atRoot()
+ ? rootName
+ : rootName.nestedClass(namesByPath.get(componentPath) + "Impl");
+ }
+
+ /**
+ * Returns the component descriptor for the component with the given subcomponent creator {@link
+ * Key}.
+ */
+ ClassName getSubcomponentCreatorName(ComponentPath componentPath, Key creatorKey) {
+ checkArgument(pathsByCreatorKey.containsKey(creatorKey));
+ // First, find the subcomponent path corresponding to the subcomponent creator key.
+ // The key may correspond to multiple paths, so we need to find the one under this component.
+ ComponentPath subcomponentPath =
+ pathsByCreatorKey.get(creatorKey).stream()
+ .filter(path -> path.parent().equals(componentPath))
+ .collect(onlyElement());
+ return getCreatorName(subcomponentPath);
+ }
+
+ /**
+ * Returns the simple name for the subcomponent creator implementation for the given {@link
+ * ComponentDescriptor}.
+ */
+ ClassName getCreatorName(ComponentPath componentPath) {
+ checkArgument(creatorNamesByPath.containsKey(componentPath));
+ return rootName.nestedClass(creatorNamesByPath.get(componentPath));
+ }
+
+ private static ImmutableMap<ComponentPath, String> creatorNamesByPath(
+ ImmutableMap<ComponentPath, String> namesByPath, BindingGraph graph) {
+ ImmutableMap.Builder<ComponentPath, String> builder = ImmutableMap.builder();
+ graph
+ .componentDescriptorsByPath()
+ .forEach(
+ (componentPath, componentDescriptor) -> {
+ if (componentPath.atRoot()) {
+ ComponentCreatorKind creatorKind =
+ componentDescriptor
+ .creatorDescriptor()
+ .map(ComponentCreatorDescriptor::kind)
+ .orElse(ComponentCreatorKind.BUILDER);
+ builder.put(componentPath, creatorKind.typeName());
+ } else if (componentDescriptor.creatorDescriptor().isPresent()) {
+ ComponentCreatorDescriptor creatorDescriptor =
+ componentDescriptor.creatorDescriptor().get();
+ String componentName = namesByPath.get(componentPath);
+ builder.put(componentPath, componentName + creatorDescriptor.kind().typeName());
+ }
+ });
+ return builder.build();
+ }
+
+ private static ImmutableMap<ComponentPath, String> namesByPath(BindingGraph graph) {
+ Map<ComponentPath, String> componentPathsBySimpleName = new LinkedHashMap<>();
+ Multimaps.index(graph.componentDescriptorsByPath().keySet(), ComponentNames::simpleName)
+ .asMap()
+ .values()
+ .stream()
+ .map(ComponentNames::disambiguateConflictingSimpleNames)
+ .forEach(componentPathsBySimpleName::putAll);
+ componentPathsBySimpleName.remove(graph.componentPath());
+ return ImmutableMap.copyOf(componentPathsBySimpleName);
+ }
+
+ private static ImmutableMultimap<Key, ComponentPath> pathsByCreatorKey(
+ KeyFactory keyFactory, BindingGraph graph) {
+ ImmutableMultimap.Builder<Key, ComponentPath> builder = ImmutableMultimap.builder();
+ graph
+ .componentDescriptorsByPath()
+ .forEach(
+ (componentPath, componentDescriptor) -> {
+ if (componentDescriptor.creatorDescriptor().isPresent()) {
+ Key creatorKey =
+ keyFactory.forSubcomponentCreator(
+ componentDescriptor.creatorDescriptor().get().typeElement().getType());
+ builder.put(creatorKey, componentPath);
+ }
+ });
+ return builder.build();
+ }
+
+ private static ImmutableMap<ComponentPath, String> disambiguateConflictingSimpleNames(
+ Collection<ComponentPath> componentsWithConflictingNames) {
+ // If there's only 1 component there's nothing to disambiguate so return the simple name.
+ if (componentsWithConflictingNames.size() == 1) {
+ ComponentPath componentPath = Iterables.getOnlyElement(componentsWithConflictingNames);
+ return ImmutableMap.of(componentPath, simpleName(componentPath));
+ }
+
+ // There are conflicting simple names, so disambiguate them with a unique prefix.
+ // We keep them small to fix https://github.com/google/dagger/issues/421.
+ UniqueNameSet nameSet = new UniqueNameSet();
+ ImmutableMap.Builder<ComponentPath, String> uniqueNames = ImmutableMap.builder();
+ for (ComponentPath componentPath : componentsWithConflictingNames) {
+ String simpleName = simpleName(componentPath);
+ String basePrefix = uniquingPrefix(componentPath);
+ uniqueNames.put(
+ componentPath, format("%s_%s", nameSet.getUniqueName(basePrefix), simpleName));
+ }
+ return uniqueNames.build();
+ }
+
+ private static String simpleName(ComponentPath componentPath) {
+ return componentPath.currentComponent().className().simpleName();
+ }
+
+ /** Returns a prefix that could make the component's simple name more unique. */
+ private static String uniquingPrefix(ComponentPath componentPath) {
+ ClassName component = componentPath.currentComponent().className();
+
+ if (component.enclosingClassName() != null) {
+ return CharMatcher.javaLowerCase().removeFrom(component.enclosingClassName().simpleName());
+ }
+
+ // Not in a normally named class. Prefix with the initials of the elements leading here.
+ Iterator<String> pieces = QUALIFIED_NAME_SPLITTER.split(component.canonicalName()).iterator();
+ StringBuilder b = new StringBuilder();
+
+ while (pieces.hasNext()) {
+ String next = pieces.next();
+ if (pieces.hasNext()) {
+ b.append(next.charAt(0));
+ }
+ }
+
+ // Note that a top level class in the root package will be prefixed "$_".
+ return b.length() > 0 ? b.toString() : "$";
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/ComponentProvisionBindingExpression.java b/java/dagger/internal/codegen/writing/ComponentProvisionRequestRepresentation.java
index 53914b669..31eecb250 100644
--- a/java/dagger/internal/codegen/writing/ComponentProvisionBindingExpression.java
+++ b/java/dagger/internal/codegen/writing/ComponentProvisionRequestRepresentation.java
@@ -16,10 +16,13 @@
package dagger.internal.codegen.writing;
-import static com.google.common.base.Preconditions.checkNotNull;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.Preconditions;
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.ComponentRequirement;
@@ -28,36 +31,48 @@ import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.javapoet.Expression;
/** A binding expression for component provision methods. */
-final class ComponentProvisionBindingExpression extends SimpleInvocationBindingExpression {
+final class ComponentProvisionRequestRepresentation extends RequestRepresentation {
private final ProvisionBinding binding;
private final BindingGraph bindingGraph;
private final ComponentRequirementExpressions componentRequirementExpressions;
private final CompilerOptions compilerOptions;
+ private final boolean isExperimentalMergedMode;
- ComponentProvisionBindingExpression(
- ProvisionBinding binding,
+ @AssistedInject
+ ComponentProvisionRequestRepresentation(
+ @Assisted ProvisionBinding binding,
BindingGraph bindingGraph,
+ ComponentImplementation componentImplementation,
ComponentRequirementExpressions componentRequirementExpressions,
CompilerOptions compilerOptions) {
- super(binding);
this.binding = binding;
- this.bindingGraph = checkNotNull(bindingGraph);
- this.componentRequirementExpressions = checkNotNull(componentRequirementExpressions);
- this.compilerOptions = checkNotNull(compilerOptions);
+ this.bindingGraph = bindingGraph;
+ this.componentRequirementExpressions = componentRequirementExpressions;
+ this.compilerOptions = compilerOptions;
+ this.isExperimentalMergedMode =
+ componentImplementation.compilerMode().isExperimentalMergedMode();
}
@Override
Expression getDependencyExpression(ClassName requestingClass) {
+ CodeBlock componentDependency =
+ isExperimentalMergedMode
+ ? CodeBlock.of("(($T) dependencies[0])", componentRequirement().type().getTypeName())
+ : getComponentRequirementExpression(requestingClass);
CodeBlock invocation =
CodeBlock.of(
"$L.$L()",
- componentRequirementExpressions.getExpression(componentRequirement(), requestingClass),
- binding.bindingElement().get().getSimpleName());
+ componentDependency,
+ toJavac(binding.bindingElement().get()).getSimpleName());
return Expression.create(
- binding.contributedPrimitiveType().orElse(binding.key().type()),
+ binding.contributedPrimitiveType().orElse(binding.key().type().xprocessing()),
maybeCheckForNull(binding, compilerOptions, invocation));
}
+ CodeBlock getComponentRequirementExpression(ClassName requestingClass) {
+ return componentRequirementExpressions.getExpression(componentRequirement(), requestingClass);
+ }
+
private ComponentRequirement componentRequirement() {
return bindingGraph
.componentDescriptor()
@@ -70,4 +85,9 @@ final class ComponentProvisionBindingExpression extends SimpleInvocationBindingE
? CodeBlock.of("$T.checkNotNullFromComponent($L)", Preconditions.class, invocation)
: invocation;
}
+
+ @AssistedFactory
+ static interface Factory {
+ ComponentProvisionRequestRepresentation create(ProvisionBinding binding);
+ }
}
diff --git a/java/dagger/internal/codegen/writing/ComponentRequestRepresentations.java b/java/dagger/internal/codegen/writing/ComponentRequestRepresentations.java
new file mode 100644
index 000000000..324cef675
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/ComponentRequestRepresentations.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2016 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
+import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
+import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
+import static dagger.internal.codegen.langmodel.Accessibility.isRawTypeAccessible;
+import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+
+import com.google.common.collect.ImmutableList;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.MethodSpec;
+import dagger.internal.codegen.binding.Binding;
+import dagger.internal.codegen.binding.BindingGraph;
+import dagger.internal.codegen.binding.BindingRequest;
+import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.binding.ComponentRequirement;
+import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.FrameworkType;
+import dagger.internal.codegen.binding.FrameworkTypeMapper;
+import dagger.internal.codegen.binding.MembersInjectionBinding;
+import dagger.internal.codegen.binding.ProductionBinding;
+import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.xprocessing.MethodSpecs;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.RequestKind;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.lang.model.type.TypeMirror;
+
+/** A central repository of code expressions used to access any binding available to a component. */
+@PerComponentImplementation
+public final class ComponentRequestRepresentations {
+ // TODO(dpb,ronshapiro): refactor this and ComponentRequirementExpressions into a
+ // HierarchicalComponentMap<K, V>, or perhaps this use a flattened ImmutableMap, built from its
+ // parents? If so, maybe make RequestRepresentation.Factory create it.
+
+ private final Optional<ComponentRequestRepresentations> parent;
+ private final BindingGraph graph;
+ private final ComponentImplementation componentImplementation;
+ private final ComponentRequirementExpressions componentRequirementExpressions;
+ private final MembersInjectionBindingRepresentation.Factory
+ membersInjectionBindingRepresentationFactory;
+ private final ProvisionBindingRepresentation.Factory provisionBindingRepresentationFactory;
+ private final ProductionBindingRepresentation.Factory productionBindingRepresentationFactory;
+ private final ExperimentalSwitchingProviderDependencyRepresentation.Factory
+ experimentalSwitchingProviderDependencyRepresentationFactory;
+ private final DaggerTypes types;
+ private final Map<Binding, BindingRepresentation> representations = new HashMap<>();
+ private final Map<Binding, ExperimentalSwitchingProviderDependencyRepresentation>
+ experimentalSwitchingProviderDependencyRepresentations = new HashMap<>();
+
+ @Inject
+ ComponentRequestRepresentations(
+ @ParentComponent Optional<ComponentRequestRepresentations> parent,
+ BindingGraph graph,
+ ComponentImplementation componentImplementation,
+ ComponentRequirementExpressions componentRequirementExpressions,
+ MembersInjectionBindingRepresentation.Factory membersInjectionBindingRepresentationFactory,
+ ProvisionBindingRepresentation.Factory provisionBindingRepresentationFactory,
+ ProductionBindingRepresentation.Factory productionBindingRepresentationFactory,
+ ExperimentalSwitchingProviderDependencyRepresentation.Factory
+ experimentalSwitchingProviderDependencyRepresentationFactory,
+ DaggerTypes types) {
+ this.parent = parent;
+ this.graph = graph;
+ this.componentImplementation = componentImplementation;
+ this.membersInjectionBindingRepresentationFactory =
+ membersInjectionBindingRepresentationFactory;
+ this.provisionBindingRepresentationFactory = provisionBindingRepresentationFactory;
+ this.productionBindingRepresentationFactory = productionBindingRepresentationFactory;
+ this.experimentalSwitchingProviderDependencyRepresentationFactory =
+ experimentalSwitchingProviderDependencyRepresentationFactory;
+ this.componentRequirementExpressions = checkNotNull(componentRequirementExpressions);
+ this.types = types;
+ }
+
+ /**
+ * Returns an expression that evaluates to the value of a binding request for a binding owned by
+ * this component or an ancestor.
+ *
+ * @param requestingClass the class that will contain the expression
+ * @throws IllegalStateException if there is no binding expression that satisfies the request
+ */
+ public Expression getDependencyExpression(BindingRequest request, ClassName requestingClass) {
+ return getRequestRepresentation(request).getDependencyExpression(requestingClass);
+ }
+
+ /**
+ * Equivalent to {@link #getDependencyExpression(BindingRequest, ClassName)} that is used only
+ * when the request is for implementation of a component method.
+ *
+ * @throws IllegalStateException if there is no binding expression that satisfies the request
+ */
+ Expression getDependencyExpressionForComponentMethod(
+ BindingRequest request,
+ ComponentMethodDescriptor componentMethod,
+ ComponentImplementation componentImplementation) {
+ return getRequestRepresentation(request)
+ .getDependencyExpressionForComponentMethod(componentMethod, componentImplementation);
+ }
+
+ /**
+ * Returns the {@link CodeBlock} for the method arguments used with the factory {@code create()}
+ * method for the given {@link ContributionBinding binding}.
+ */
+ CodeBlock getCreateMethodArgumentsCodeBlock(
+ ContributionBinding binding, ClassName requestingClass) {
+ return makeParametersCodeBlock(getCreateMethodArgumentsCodeBlocks(binding, requestingClass));
+ }
+
+ private ImmutableList<CodeBlock> getCreateMethodArgumentsCodeBlocks(
+ ContributionBinding binding, ClassName requestingClass) {
+ ImmutableList.Builder<CodeBlock> arguments = ImmutableList.builder();
+
+ if (binding.requiresModuleInstance()) {
+ arguments.add(
+ componentRequirementExpressions.getExpressionDuringInitialization(
+ ComponentRequirement.forModule(binding.contributingModule().get().getType()),
+ requestingClass));
+ }
+
+ binding.dependencies().stream()
+ .map(dependency -> frameworkRequest(binding, dependency))
+ .map(request -> getDependencyExpression(request, requestingClass))
+ .map(Expression::codeBlock)
+ .forEach(arguments::add);
+
+ return arguments.build();
+ }
+
+ private static BindingRequest frameworkRequest(
+ ContributionBinding binding, DependencyRequest dependency) {
+ // TODO(bcorso): See if we can get rid of FrameworkTypeMatcher
+ FrameworkType frameworkType =
+ FrameworkTypeMapper.forBindingType(binding.bindingType())
+ .getFrameworkType(dependency.kind());
+ return BindingRequest.bindingRequest(dependency.key(), frameworkType);
+ }
+
+ /**
+ * Returns an expression that evaluates to the value of a dependency request, for passing to a
+ * binding method, an {@code @Inject}-annotated constructor or member, or a proxy for one.
+ *
+ * <p>If the method is a generated static {@link InjectionMethods injection method}, each
+ * parameter will be {@link Object} if the dependency's raw type is inaccessible. If that is the
+ * case for this dependency, the returned expression will use a cast to evaluate to the raw type.
+ *
+ * @param requestingClass the class that will contain the expression
+ */
+ Expression getDependencyArgumentExpression(
+ DependencyRequest dependencyRequest, ClassName requestingClass) {
+
+ TypeMirror dependencyType = dependencyRequest.key().type().java();
+ BindingRequest bindingRequest = bindingRequest(dependencyRequest);
+ Expression dependencyExpression = getDependencyExpression(bindingRequest, requestingClass);
+
+ if (dependencyRequest.kind().equals(RequestKind.INSTANCE)
+ && !isTypeAccessibleFrom(dependencyType, requestingClass.packageName())
+ && isRawTypeAccessible(dependencyType, requestingClass.packageName())) {
+ return dependencyExpression.castTo(types.erasure(dependencyType));
+ }
+
+ return dependencyExpression;
+ }
+
+ /** Returns the implementation of a component method. */
+ public MethodSpec getComponentMethod(ComponentMethodDescriptor componentMethod) {
+ checkArgument(componentMethod.dependencyRequest().isPresent());
+ BindingRequest request = bindingRequest(componentMethod.dependencyRequest().get());
+ return MethodSpecs.overriding(
+ componentMethod.methodElement(), graph.componentTypeElement().getType())
+ .addCode(
+ getRequestRepresentation(request)
+ .getComponentMethodImplementation(componentMethod, componentImplementation))
+ .build();
+ }
+
+ /** Returns the {@link RequestRepresentation} for the given {@link BindingRequest}. */
+ RequestRepresentation getRequestRepresentation(BindingRequest request) {
+ Optional<Binding> localBinding =
+ request.isRequestKind(RequestKind.MEMBERS_INJECTION)
+ ? graph.localMembersInjectionBinding(request.key())
+ : graph.localContributionBinding(request.key());
+
+ if (localBinding.isPresent()) {
+ return getBindingRepresentation(localBinding.get()).getRequestRepresentation(request);
+ }
+
+ checkArgument(parent.isPresent(), "no expression found for %s", request);
+ return parent.get().getRequestRepresentation(request);
+ }
+
+ private BindingRepresentation getBindingRepresentation(Binding binding) {
+ return reentrantComputeIfAbsent(
+ representations, binding, this::getBindingRepresentationUncached);
+ }
+
+ private BindingRepresentation getBindingRepresentationUncached(Binding binding) {
+ switch (binding.bindingType()) {
+ case MEMBERS_INJECTION:
+ return membersInjectionBindingRepresentationFactory.create(
+ (MembersInjectionBinding) binding);
+ case PROVISION:
+ return provisionBindingRepresentationFactory.create((ProvisionBinding) binding);
+ case PRODUCTION:
+ return productionBindingRepresentationFactory.create((ProductionBinding) binding);
+ }
+ throw new AssertionError();
+ }
+
+ /**
+ * Returns an {@link ExperimentalSwitchingProviderDependencyRepresentation} for the requested
+ * binding to satisfy dependency requests on it from experimental switching providers. Cannot be
+ * used for Members Injection requests.
+ */
+ ExperimentalSwitchingProviderDependencyRepresentation
+ getExperimentalSwitchingProviderDependencyRepresentation(BindingRequest request) {
+ checkState(
+ componentImplementation.compilerMode().isExperimentalMergedMode(),
+ "Compiler mode should be experimentalMergedMode!");
+ Optional<Binding> localBinding = graph.localContributionBinding(request.key());
+
+ if (localBinding.isPresent()) {
+ return reentrantComputeIfAbsent(
+ experimentalSwitchingProviderDependencyRepresentations,
+ localBinding.get(),
+ binding ->
+ experimentalSwitchingProviderDependencyRepresentationFactory.create(
+ (ProvisionBinding) binding));
+ }
+
+ checkArgument(parent.isPresent(), "no expression found for %s", request);
+ return parent.get().getExperimentalSwitchingProviderDependencyRepresentation(request);
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/ComponentRequirementExpression.java b/java/dagger/internal/codegen/writing/ComponentRequirementExpression.java
index 13008b8eb..cdfdf26c5 100644
--- a/java/dagger/internal/codegen/writing/ComponentRequirementExpression.java
+++ b/java/dagger/internal/codegen/writing/ComponentRequirementExpression.java
@@ -22,8 +22,8 @@ import dagger.internal.codegen.binding.ComponentRequirement;
/**
* A factory for expressions of {@link ComponentRequirement}s in the generated component. This is
- * <em>not</em> a {@link BindingExpression}, since {@link ComponentRequirement}s do not have a
- * {@link dagger.model.Key}. See {@link ComponentRequirementBindingExpression} for binding
+ * <em>not</em> a {@link RequestRepresentation}, since {@link ComponentRequirement}s do not have a
+ * {@link dagger.spi.model.Key}. See {@link ComponentRequirementRequestRepresentation} for binding
* expressions that are themselves a component requirement.
*/
interface ComponentRequirementExpression {
diff --git a/java/dagger/internal/codegen/writing/ComponentRequirementExpressions.java b/java/dagger/internal/codegen/writing/ComponentRequirementExpressions.java
index 653a7a25a..2e9e5f1fd 100644
--- a/java/dagger/internal/codegen/writing/ComponentRequirementExpressions.java
+++ b/java/dagger/internal/codegen/writing/ComponentRequirementExpressions.java
@@ -23,6 +23,7 @@ import static dagger.internal.codegen.writing.ComponentImplementation.FieldSpecK
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.base.Supplier;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
@@ -31,11 +32,11 @@ import com.squareup.javapoet.TypeName;
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.ComponentRequirement;
import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import javax.inject.Inject;
-import javax.lang.model.element.TypeElement;
/**
* A central repository of expressions used to access any {@link ComponentRequirement} available to
@@ -44,7 +45,7 @@ import javax.lang.model.element.TypeElement;
@PerComponentImplementation
public final class ComponentRequirementExpressions {
- // TODO(dpb,ronshapiro): refactor this and ComponentBindingExpressions into a
+ // TODO(dpb,ronshapiro): refactor this and ComponentRequestRepresentations into a
// HierarchicalComponentMap<K, V>, or perhaps this use a flattened ImmutableMap, built from its
// parents? If so, maybe make ComponentRequirementExpression.Factory create it.
@@ -52,10 +53,9 @@ public final class ComponentRequirementExpressions {
private final Map<ComponentRequirement, ComponentRequirementExpression>
componentRequirementExpressions = new HashMap<>();
private final BindingGraph graph;
- private final ComponentImplementation componentImplementation;
+ private final ShardImplementation componentShard;
private final ModuleProxies moduleProxies;
- // TODO(ronshapiro): give ComponentImplementation a graph() method
@Inject
ComponentRequirementExpressions(
@ParentComponent Optional<ComponentRequirementExpressions> parent,
@@ -65,7 +65,8 @@ public final class ComponentRequirementExpressions {
ModuleProxies moduleProxies) {
this.parent = parent;
this.graph = graph;
- this.componentImplementation = componentImplementation;
+ // All component requirements go in the componentShard.
+ this.componentShard = componentImplementation.getComponentShard();
this.moduleProxies = moduleProxies;
}
@@ -78,6 +79,19 @@ public final class ComponentRequirementExpressions {
return getExpression(componentRequirement).getExpression(requestingClass);
}
+ private ComponentRequirementExpression getExpression(ComponentRequirement componentRequirement) {
+ if (graph.componentRequirements().contains(componentRequirement)) {
+ return componentRequirementExpressions.computeIfAbsent(
+ componentRequirement, this::createExpression);
+ }
+ if (parent.isPresent()) {
+ return parent.get().getExpression(componentRequirement);
+ }
+
+ throw new IllegalStateException(
+ "no component requirement expression found for " + componentRequirement);
+ }
+
/**
* Returns an expression for the {@code componentRequirement} to be used only within {@code
* initialize()} methods, where the component constructor parameters are available.
@@ -90,58 +104,26 @@ public final class ComponentRequirementExpressions {
return getExpression(componentRequirement).getExpressionDuringInitialization(requestingClass);
}
- ComponentRequirementExpression getExpression(ComponentRequirement componentRequirement) {
- if (graph.componentRequirements().contains(componentRequirement)) {
- return componentRequirementExpressions.computeIfAbsent(
- componentRequirement, this::createField);
- }
- if (parent.isPresent()) {
- return parent.get().getExpression(componentRequirement);
- }
-
- throw new IllegalStateException(
- "no component requirement expression found for " + componentRequirement);
- }
-
/** Returns a field for a {@link ComponentRequirement}. */
- private ComponentRequirementExpression createField(ComponentRequirement requirement) {
- if (componentImplementation.componentDescriptor().hasCreator()) {
- return new ComponentParameterField(requirement, componentImplementation, Optional.empty());
- } else if (graph.factoryMethod().isPresent()
- && graph.factoryMethodParameters().containsKey(requirement)) {
- String parameterName =
- graph.factoryMethodParameters().get(requirement).getSimpleName().toString();
- return new ComponentParameterField(
- requirement, componentImplementation, Optional.of(parameterName));
+ private ComponentRequirementExpression createExpression(ComponentRequirement requirement) {
+ if (componentShard.componentDescriptor().hasCreator()
+ || (graph.factoryMethod().isPresent()
+ && graph.factoryMethodParameters().containsKey(requirement))) {
+ return new ComponentParameterField(requirement);
} else if (requirement.kind().isModule()) {
- return new InstantiableModuleField(requirement, componentImplementation);
+ return new InstantiableModuleField(requirement);
} else {
throw new AssertionError(
- String.format("Can't create %s in %s", requirement, componentImplementation.name()));
+ String.format("Can't create %s in %s", requirement, componentShard.name()));
}
}
- private abstract static class AbstractField implements ComponentRequirementExpression {
+ private abstract class AbstractField implements ComponentRequirementExpression {
final ComponentRequirement componentRequirement;
- final ComponentImplementation componentImplementation;
- final String fieldName;
- private final Supplier<MemberSelect> field = memoize(this::addField);
+ private final Supplier<MemberSelect> field = memoize(this::createField);
- private AbstractField(
- ComponentRequirement componentRequirement,
- ComponentImplementation componentImplementation) {
+ private AbstractField(ComponentRequirement componentRequirement) {
this.componentRequirement = checkNotNull(componentRequirement);
- this.componentImplementation = checkNotNull(componentImplementation);
- // Note: The field name is being claimed eagerly here even though we don't know at this point
- // whether or not the requirement will even need a field. This is done because:
- // A) ComponentParameterField wants to ensure that it doesn't give the parameter the same name
- // as any field in the component, which requires that it claim a "field name" for itself
- // when naming the parameter.
- // B) The parameter name may be needed before the field name is.
- // C) We want to prefer giving the best name to the field rather than the parameter given its
- // wider scope.
- this.fieldName =
- componentImplementation.getUniqueFieldName(componentRequirement.variableName());
}
@Override
@@ -149,16 +131,13 @@ public final class ComponentRequirementExpressions {
return field.get().getExpressionFor(requestingClass);
}
- private MemberSelect addField() {
- FieldSpec field = createField();
- componentImplementation.addField(COMPONENT_REQUIREMENT_FIELD, field);
- componentImplementation.addComponentRequirementInitialization(fieldInitialization(field));
- return MemberSelect.localField(componentImplementation.name(), fieldName);
- }
-
- private FieldSpec createField() {
- return FieldSpec.builder(TypeName.get(componentRequirement.type()), fieldName, PRIVATE, FINAL)
- .build();
+ private MemberSelect createField() {
+ String fieldName = componentShard.getUniqueFieldName(componentRequirement.variableName());
+ TypeName fieldType = componentRequirement.type().getTypeName();
+ FieldSpec field = FieldSpec.builder(fieldType, fieldName, PRIVATE, FINAL).build();
+ componentShard.addField(COMPONENT_REQUIREMENT_FIELD, field);
+ componentShard.addComponentRequirementInitialization(fieldInitialization(field));
+ return MemberSelect.localField(componentShard, fieldName);
}
/** Returns the {@link CodeBlock} that initializes the component field during construction. */
@@ -170,11 +149,10 @@ public final class ComponentRequirementExpressions {
* instantiated by the component (i.e. a static class with a no-arg constructor).
*/
private final class InstantiableModuleField extends AbstractField {
- private final TypeElement moduleElement;
+ private final XTypeElement moduleElement;
- private InstantiableModuleField(
- ComponentRequirement module, ComponentImplementation componentImplementation) {
- super(module, componentImplementation);
+ InstantiableModuleField(ComponentRequirement module) {
+ super(module);
checkArgument(module.kind().isModule());
this.moduleElement = module.typeElement();
}
@@ -184,7 +162,7 @@ public final class ComponentRequirementExpressions {
return CodeBlock.of(
"this.$N = $L;",
componentField,
- moduleProxies.newModuleInstance(moduleElement, componentImplementation.name()));
+ moduleProxies.newModuleInstance(moduleElement, componentShard.name()));
}
}
@@ -192,29 +170,17 @@ public final class ComponentRequirementExpressions {
* A {@link ComponentRequirementExpression} for {@link ComponentRequirement}s that are passed in
* as parameters to the component's constructor.
*/
- private static final class ComponentParameterField extends AbstractField {
+ private final class ComponentParameterField extends AbstractField {
private final String parameterName;
- private ComponentParameterField(
- ComponentRequirement componentRequirement,
- ComponentImplementation componentImplementation,
- Optional<String> name) {
- super(componentRequirement, componentImplementation);
- // Get the name that the component implementation will use for its parameter for the
- // requirement. If the given name is different than the name of the field created for the
- // requirement (as may be the case when the parameter name is derived from a user-written
- // factory method parameter), just use that as the base name for the parameter. Otherwise,
- // append "Param" to the end of the name to differentiate.
- // In either case, componentImplementation.getParameterName() will ensure that the final name
- // that is used is not the same name as any field in the component even if there's something
- // weird where the component actually has fields named, say, "foo" and "fooParam".
- String baseName = name.filter(n -> !n.equals(fieldName)).orElse(fieldName + "Param");
- this.parameterName = componentImplementation.getParameterName(componentRequirement, baseName);
+ ComponentParameterField(ComponentRequirement module) {
+ super(module);
+ this.parameterName = componentShard.getParameterName(componentRequirement);
}
@Override
public CodeBlock getExpressionDuringInitialization(ClassName requestingClass) {
- if (componentImplementation.name().equals(requestingClass)) {
+ if (componentShard.name().equals(requestingClass)) {
return CodeBlock.of("$L", parameterName);
} else {
// requesting this component requirement during initialization of a child component requires
diff --git a/java/dagger/internal/codegen/writing/ComponentRequirementBindingExpression.java b/java/dagger/internal/codegen/writing/ComponentRequirementRequestRepresentation.java
index 299f27974..f9e8f1479 100644
--- a/java/dagger/internal/codegen/writing/ComponentRequirementBindingExpression.java
+++ b/java/dagger/internal/codegen/writing/ComponentRequirementRequestRepresentation.java
@@ -16,7 +16,12 @@
package dagger.internal.codegen.writing;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.squareup.javapoet.ClassName;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.ComponentRequirement;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.javapoet.Expression;
@@ -26,16 +31,16 @@ import dagger.internal.codegen.javapoet.Expression;
* {@linkplain dagger.Component#dependencies() component} and {@linkplain
* dagger.producers.ProductionComponent#dependencies() production component dependencies}.
*/
-final class ComponentRequirementBindingExpression extends SimpleInvocationBindingExpression {
+final class ComponentRequirementRequestRepresentation extends RequestRepresentation {
private final ComponentRequirement componentRequirement;
private final ComponentRequirementExpressions componentRequirementExpressions;
- ComponentRequirementBindingExpression(
- ContributionBinding binding,
- ComponentRequirement componentRequirement,
+ @AssistedInject
+ ComponentRequirementRequestRepresentation(
+ @Assisted ContributionBinding binding,
+ @Assisted ComponentRequirement componentRequirement,
ComponentRequirementExpressions componentRequirementExpressions) {
- super(binding);
- this.componentRequirement = componentRequirement;
+ this.componentRequirement = checkNotNull(componentRequirement);
this.componentRequirementExpressions = componentRequirementExpressions;
}
@@ -45,4 +50,10 @@ final class ComponentRequirementBindingExpression extends SimpleInvocationBindin
componentRequirement.type(),
componentRequirementExpressions.getExpression(componentRequirement, requestingClass));
}
+
+ @AssistedFactory
+ static interface Factory {
+ ComponentRequirementRequestRepresentation create(
+ ContributionBinding binding, ComponentRequirement componentRequirement);
+ }
}
diff --git a/java/dagger/internal/codegen/writing/DelegateBindingExpression.java b/java/dagger/internal/codegen/writing/DelegateRequestRepresentation.java
index 336113264..59aa39492 100644
--- a/java/dagger/internal/codegen/writing/DelegateBindingExpression.java
+++ b/java/dagger/internal/codegen/writing/DelegateRequestRepresentation.java
@@ -16,15 +16,20 @@
package dagger.internal.codegen.writing;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.base.RequestKinds.requestType;
import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-import static dagger.model.BindingKind.DELEGATE;
+import static dagger.spi.model.BindingKind.DELEGATE;
import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.Binding;
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.BindsTypeChecker;
@@ -32,27 +37,28 @@ import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.javapoet.Expression;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.RequestKind;
+import dagger.spi.model.RequestKind;
import javax.lang.model.type.TypeMirror;
-/** A {@link dagger.internal.codegen.writing.BindingExpression} for {@code @Binds} methods. */
-final class DelegateBindingExpression extends BindingExpression {
+/** A {@link dagger.internal.codegen.writing.RequestRepresentation} for {@code @Binds} methods. */
+final class DelegateRequestRepresentation extends RequestRepresentation {
private final ContributionBinding binding;
private final RequestKind requestKind;
- private final ComponentBindingExpressions componentBindingExpressions;
+ private final ComponentRequestRepresentations componentRequestRepresentations;
private final DaggerTypes types;
private final BindsTypeChecker bindsTypeChecker;
- DelegateBindingExpression(
- ContributionBinding binding,
- RequestKind requestKind,
- ComponentBindingExpressions componentBindingExpressions,
+ @AssistedInject
+ DelegateRequestRepresentation(
+ @Assisted ContributionBinding binding,
+ @Assisted RequestKind requestKind,
+ ComponentRequestRepresentations componentRequestRepresentations,
DaggerTypes types,
DaggerElements elements) {
this.binding = checkNotNull(binding);
this.requestKind = checkNotNull(requestKind);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
- this.types = checkNotNull(types);
+ this.componentRequestRepresentations = componentRequestRepresentations;
+ this.types = types;
this.bindsTypeChecker = new BindsTypeChecker(types, elements);
}
@@ -73,14 +79,14 @@ final class DelegateBindingExpression extends BindingExpression {
@Override
Expression getDependencyExpression(ClassName requestingClass) {
Expression delegateExpression =
- componentBindingExpressions.getDependencyExpression(
+ componentRequestRepresentations.getDependencyExpression(
bindingRequest(getOnlyElement(binding.dependencies()).key(), requestKind),
requestingClass);
- TypeMirror contributedType = binding.contributedType();
+ TypeMirror contributedType = toJavac(binding.contributedType());
switch (requestKind) {
case INSTANCE:
- return instanceRequiresCast(delegateExpression, requestingClass)
+ return instanceRequiresCast(binding, delegateExpression, requestingClass, bindsTypeChecker)
? delegateExpression.castTo(contributedType)
: delegateExpression;
default:
@@ -89,12 +95,17 @@ final class DelegateBindingExpression extends BindingExpression {
}
}
- private boolean instanceRequiresCast(Expression delegateExpression, ClassName requestingClass) {
+ static boolean instanceRequiresCast(
+ ContributionBinding binding,
+ Expression delegateExpression,
+ ClassName requestingClass,
+ BindsTypeChecker bindsTypeChecker) {
// delegateExpression.type() could be Object if expression is satisfied with a raw
// Provider's get() method.
+ TypeMirror contributedType = toJavac(binding.contributedType());
return !bindsTypeChecker.isAssignable(
- delegateExpression.type(), binding.contributedType(), binding.contributionType())
- && isTypeAccessibleFrom(binding.contributedType(), requestingClass.packageName());
+ delegateExpression.type(), contributedType, binding.contributionType())
+ && isTypeAccessibleFrom(contributedType, requestingClass.packageName());
}
/**
@@ -110,7 +121,13 @@ final class DelegateBindingExpression extends BindingExpression {
if (types.isAssignable(delegateExpression.type(), desiredType)) {
return delegateExpression;
}
- return delegateExpression.castTo(types.erasure(desiredType));
+ Expression castedExpression = delegateExpression.castTo(types.erasure(desiredType));
+ // Casted raw type provider expression has to be wrapped parentheses, otherwise there
+ // will be an error when DerivedFromFrameworkInstanceRequestRepresentation appends a `get()` to
+ // it.
+ // TODO(wanyingd): change the logic to only add parenthesis when necessary.
+ return Expression.create(
+ castedExpression.type(), CodeBlock.of("($L)", castedExpression.codeBlock()));
}
private enum ScopeKind {
@@ -130,4 +147,9 @@ final class DelegateBindingExpression extends BindingExpression {
return this.ordinal() > other.ordinal();
}
}
+
+ @AssistedFactory
+ static interface Factory {
+ DelegateRequestRepresentation create(ContributionBinding binding, RequestKind requestKind);
+ }
}
diff --git a/java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java b/java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java
index a7f9556d9..096d1090e 100644
--- a/java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java
@@ -21,10 +21,14 @@ import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.javapoet.CodeBlocks;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import dagger.model.DependencyRequest;
+import dagger.spi.model.DependencyRequest;
/** A framework instance creation expression for a {@link dagger.Binds @Binds} binding. */
final class DelegatingFrameworkInstanceCreationExpression
@@ -32,26 +36,33 @@ final class DelegatingFrameworkInstanceCreationExpression
private final ContributionBinding binding;
private final ComponentImplementation componentImplementation;
- private final ComponentBindingExpressions componentBindingExpressions;
+ private final ComponentRequestRepresentations componentRequestRepresentations;
+ @AssistedInject
DelegatingFrameworkInstanceCreationExpression(
- ContributionBinding binding,
+ @Assisted ContributionBinding binding,
ComponentImplementation componentImplementation,
- ComponentBindingExpressions componentBindingExpressions) {
+ ComponentRequestRepresentations componentRequestRepresentations,
+ CompilerOptions compilerOptions) {
this.binding = checkNotNull(binding);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ this.componentImplementation = componentImplementation;
+ this.componentRequestRepresentations = componentRequestRepresentations;
}
@Override
public CodeBlock creationExpression() {
DependencyRequest dependency = getOnlyElement(binding.dependencies());
return CodeBlocks.cast(
- componentBindingExpressions
+ componentRequestRepresentations
.getDependencyExpression(
bindingRequest(dependency.key(), binding.frameworkType()),
- componentImplementation.name())
+ componentImplementation.shardImplementation(binding).name())
.codeBlock(),
- binding.frameworkType().frameworkClass());
+ binding.frameworkType().frameworkClassName());
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ DelegatingFrameworkInstanceCreationExpression create(ContributionBinding binding);
}
}
diff --git a/java/dagger/internal/codegen/writing/DependencyMethodProducerCreationExpression.java b/java/dagger/internal/codegen/writing/DependencyMethodProducerCreationExpression.java
index 5ac1e8f6b..64a689ea9 100644
--- a/java/dagger/internal/codegen/writing/DependencyMethodProducerCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/DependencyMethodProducerCreationExpression.java
@@ -16,6 +16,7 @@
package dagger.internal.codegen.writing;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
import static com.squareup.javapoet.TypeSpec.anonymousClassBuilder;
@@ -25,10 +26,12 @@ import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
-import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.TypeName;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.ComponentRequirement;
import dagger.internal.codegen.binding.ContributionBinding;
@@ -47,15 +50,16 @@ final class DependencyMethodProducerCreationExpression
private final ComponentRequirementExpressions componentRequirementExpressions;
private final BindingGraph graph;
+ @AssistedInject
DependencyMethodProducerCreationExpression(
- ContributionBinding binding,
+ @Assisted ContributionBinding binding,
ComponentImplementation componentImplementation,
ComponentRequirementExpressions componentRequirementExpressions,
BindingGraph graph) {
this.binding = checkNotNull(binding);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.componentRequirementExpressions = checkNotNull(componentRequirementExpressions);
- this.graph = checkNotNull(graph);
+ this.componentImplementation = componentImplementation;
+ this.componentRequirementExpressions = componentRequirementExpressions;
+ this.graph = graph;
}
@Override
@@ -64,7 +68,7 @@ final class DependencyMethodProducerCreationExpression
graph.componentDescriptor().getDependencyThatDefinesMethod(binding.bindingElement().get());
FieldSpec dependencyField =
FieldSpec.builder(
- ClassName.get(dependency.typeElement()), dependency.variableName(), PRIVATE, FINAL)
+ dependency.typeElement().getClassName(), dependency.variableName(), PRIVATE, FINAL)
.initializer(
componentRequirementExpressions.getExpressionDuringInitialization(
dependency,
@@ -79,7 +83,7 @@ final class DependencyMethodProducerCreationExpression
componentImplementation.name().nestedClass("Anonymous")))
.build();
// TODO(b/70395982): Explore using a private static type instead of an anonymous class.
- TypeName keyType = TypeName.get(binding.key().type());
+ TypeName keyType = TypeName.get(binding.key().type().java());
return CodeBlock.of(
"$L",
anonymousClassBuilder("")
@@ -93,8 +97,13 @@ final class DependencyMethodProducerCreationExpression
.addStatement(
"return $N.$L()",
dependencyField,
- binding.bindingElement().get().getSimpleName())
+ toJavac(binding.bindingElement().get()).getSimpleName())
.build())
.build());
}
+
+ @AssistedFactory
+ static interface Factory {
+ DependencyMethodProducerCreationExpression create(ContributionBinding binding);
+ }
}
diff --git a/java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java b/java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java
index af5d45e66..8ea3742ab 100644
--- a/java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java
@@ -16,29 +16,35 @@
package dagger.internal.codegen.writing;
+import static androidx.room.compiler.processing.XElementKt.isMethod;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.squareup.javapoet.MethodSpec.constructorBuilder;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
import static com.squareup.javapoet.TypeSpec.classBuilder;
import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
import static dagger.internal.codegen.writing.ComponentImplementation.TypeSpecKind.COMPONENT_PROVISION_FACTORY;
+import static dagger.internal.codegen.xprocessing.XElements.asMethod;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XMethodElement;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import javax.lang.model.element.Element;
/**
* A {@link javax.inject.Provider} creation expression for a provision method on a component's
@@ -48,23 +54,29 @@ import javax.lang.model.element.Element;
final class DependencyMethodProviderCreationExpression
implements FrameworkInstanceCreationExpression {
- private final ComponentImplementation componentImplementation;
+ private final ShardImplementation shardImplementation;
private final ComponentRequirementExpressions componentRequirementExpressions;
private final CompilerOptions compilerOptions;
private final BindingGraph graph;
- private final ContributionBinding binding;
+ private final ProvisionBinding binding;
+ private final XMethodElement provisionMethod;
+ @AssistedInject
DependencyMethodProviderCreationExpression(
- ContributionBinding binding,
+ @Assisted ProvisionBinding binding,
ComponentImplementation componentImplementation,
ComponentRequirementExpressions componentRequirementExpressions,
CompilerOptions compilerOptions,
BindingGraph graph) {
this.binding = checkNotNull(binding);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.componentRequirementExpressions = checkNotNull(componentRequirementExpressions);
- this.compilerOptions = checkNotNull(compilerOptions);
- this.graph = checkNotNull(graph);
+ this.shardImplementation = componentImplementation.shardImplementation(binding);
+ this.componentRequirementExpressions = componentRequirementExpressions;
+ this.compilerOptions = compilerOptions;
+ this.graph = graph;
+
+ checkArgument(binding.bindingElement().isPresent());
+ checkArgument(isMethod(binding.bindingElement().get()));
+ provisionMethod = asMethod(binding.bindingElement().get());
}
@Override
@@ -76,13 +88,12 @@ final class DependencyMethodProviderCreationExpression
// using .class & String.format -- but that wouldn't be the whole story.
// What should we do?
CodeBlock invocation =
- ComponentProvisionBindingExpression.maybeCheckForNull(
- (ProvisionBinding) binding,
+ ComponentProvisionRequestRepresentation.maybeCheckForNull(
+ binding,
compilerOptions,
- CodeBlock.of(
- "$N.$N()", dependency().variableName(), provisionMethod().getSimpleName()));
- ClassName dependencyClassName = ClassName.get(dependency().typeElement());
- TypeName keyType = TypeName.get(binding.key().type());
+ CodeBlock.of("$N.$N()", dependency().variableName(), getSimpleName(provisionMethod)));
+ ClassName dependencyClassName = dependency().typeElement().getClassName();
+ TypeName keyType = binding.key().type().xprocessing().getTypeName();
MethodSpec.Builder getMethod =
methodBuilder("get")
.addAnnotation(Override.class)
@@ -90,11 +101,23 @@ final class DependencyMethodProviderCreationExpression
.returns(keyType)
.addStatement("return $L", invocation);
if (binding.nullableType().isPresent()) {
- getMethod.addAnnotation(ClassName.get(MoreTypes.asTypeElement(binding.nullableType().get())));
+ getMethod.addAnnotation(binding.nullableType().get().getTypeElement().getClassName());
}
- componentImplementation.addType(
+
+ // We need to use the componentShard here since the generated type is static and shards are
+ // not static classes so it can't be nested inside the shard.
+ ShardImplementation componentShard =
+ shardImplementation.getComponentImplementation().getComponentShard();
+ ClassName factoryClassName =
+ componentShard
+ .name()
+ .nestedClass(
+ dependency().typeElement().getQualifiedName().replace('.', '_')
+ + "_"
+ + getSimpleName(provisionMethod));
+ componentShard.addType(
COMPONENT_PROVISION_FACTORY,
- classBuilder(factoryClassName())
+ classBuilder(factoryClassName)
.addSuperinterface(providerOf(keyType))
.addModifiers(PRIVATE, STATIC, FINAL)
.addField(dependencyClassName, dependency().variableName(), PRIVATE, FINAL)
@@ -107,24 +130,17 @@ final class DependencyMethodProviderCreationExpression
.build());
return CodeBlock.of(
"new $T($L)",
- factoryClassName(),
+ factoryClassName,
componentRequirementExpressions.getExpressionDuringInitialization(
- dependency(), componentImplementation.name()));
- }
-
- private ClassName factoryClassName() {
- String factoryName =
- ClassName.get(dependency().typeElement()).toString().replace('.', '_')
- + "_"
- + binding.bindingElement().get().getSimpleName();
- return componentImplementation.name().nestedClass(factoryName);
+ dependency(), shardImplementation.name()));
}
private ComponentRequirement dependency() {
- return graph.componentDescriptor().getDependencyThatDefinesMethod(provisionMethod());
+ return graph.componentDescriptor().getDependencyThatDefinesMethod(provisionMethod);
}
- private Element provisionMethod() {
- return binding.bindingElement().get();
+ @AssistedFactory
+ static interface Factory {
+ DependencyMethodProviderCreationExpression create(ProvisionBinding binding);
}
}
diff --git a/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceBindingExpression.java b/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceBindingExpression.java
deleted file mode 100644
index 6e5dca84e..000000000
--- a/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceBindingExpression.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2018 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-
-import com.squareup.javapoet.ClassName;
-import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
-import dagger.model.RequestKind;
-
-/** A binding expression that depends on a framework instance. */
-final class DerivedFromFrameworkInstanceBindingExpression extends BindingExpression {
-
- private final BindingRequest frameworkRequest;
- private final RequestKind requestKind;
- private final FrameworkType frameworkType;
- private final ComponentBindingExpressions componentBindingExpressions;
- private final DaggerTypes types;
-
- DerivedFromFrameworkInstanceBindingExpression(
- Key key,
- FrameworkType frameworkType,
- RequestKind requestKind,
- ComponentBindingExpressions componentBindingExpressions,
- DaggerTypes types) {
- this.frameworkRequest = bindingRequest(key, frameworkType);
- this.requestKind = checkNotNull(requestKind);
- this.frameworkType = checkNotNull(frameworkType);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
- this.types = checkNotNull(types);
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- return frameworkType.to(
- requestKind,
- componentBindingExpressions.getDependencyExpression(frameworkRequest, requestingClass),
- types);
- }
-
- @Override
- Expression getDependencyExpressionForComponentMethod(
- ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
- Expression frameworkInstance =
- componentBindingExpressions.getDependencyExpressionForComponentMethod(
- frameworkRequest, componentMethod, component);
- return frameworkType.to(requestKind, frameworkInstance, types);
- }
-}
diff --git a/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceRequestRepresentation.java b/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceRequestRepresentation.java
new file mode 100644
index 000000000..79895e9a0
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceRequestRepresentation.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.writing.DelegateRequestRepresentation.instanceRequiresCast;
+
+import com.squareup.javapoet.ClassName;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.binding.BindsTypeChecker;
+import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.FrameworkType;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.RequestKind;
+
+/** A binding expression that depends on a framework instance. */
+final class DerivedFromFrameworkInstanceRequestRepresentation extends RequestRepresentation {
+ private final ContributionBinding binding;
+ private final RequestRepresentation frameworkRequestRepresentation;
+ private final RequestKind requestKind;
+ private final FrameworkType frameworkType;
+ private final DaggerTypes types;
+ private final BindsTypeChecker bindsTypeChecker;
+
+ @AssistedInject
+ DerivedFromFrameworkInstanceRequestRepresentation(
+ @Assisted ContributionBinding binding,
+ @Assisted RequestRepresentation frameworkRequestRepresentation,
+ @Assisted RequestKind requestKind,
+ @Assisted FrameworkType frameworkType,
+ DaggerTypes types,
+ DaggerElements elements) {
+ this.binding = binding;
+ this.frameworkRequestRepresentation = checkNotNull(frameworkRequestRepresentation);
+ this.requestKind = requestKind;
+ this.frameworkType = checkNotNull(frameworkType);
+ this.types = types;
+ this.bindsTypeChecker = new BindsTypeChecker(types, elements);
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ Expression expression =
+ frameworkType.to(
+ requestKind,
+ frameworkRequestRepresentation.getDependencyExpression(requestingClass),
+ types);
+ return requiresTypeCast(expression, requestingClass)
+ ? expression.castTo(binding.contributedType())
+ : expression;
+ }
+
+ @Override
+ Expression getDependencyExpressionForComponentMethod(
+ ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
+ Expression expression =
+ frameworkType.to(
+ requestKind,
+ frameworkRequestRepresentation.getDependencyExpressionForComponentMethod(
+ componentMethod, component),
+ types);
+ return requiresTypeCast(expression, component.name())
+ ? expression.castTo(binding.contributedType())
+ : expression;
+ }
+
+ private boolean requiresTypeCast(Expression expression, ClassName requestingClass) {
+ return binding.kind().equals(BindingKind.DELEGATE)
+ && requestKind.equals(RequestKind.INSTANCE)
+ && instanceRequiresCast(binding, expression, requestingClass, bindsTypeChecker);
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ DerivedFromFrameworkInstanceRequestRepresentation create(
+ ContributionBinding binding,
+ RequestRepresentation frameworkRequestRepresentation,
+ RequestKind requestKind,
+ FrameworkType frameworkType);
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java b/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java
new file mode 100644
index 000000000..c90d81348
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
+import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
+
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.binding.BindingGraph;
+import dagger.internal.codegen.binding.BindingRequest;
+import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
+import dagger.spi.model.RequestKind;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+/** Returns request representation based on a direct instance expression. */
+final class DirectInstanceBindingRepresentation {
+ private final ProvisionBinding binding;
+ private final BindingGraph graph;
+ private final ComponentImplementation componentImplementation;
+ private final ComponentMethodRequestRepresentation.Factory
+ componentMethodRequestRepresentationFactory;
+ private final ImmediateFutureRequestRepresentation.Factory
+ immediateFutureRequestRepresentationFactory;
+ private final PrivateMethodRequestRepresentation.Factory
+ privateMethodRequestRepresentationFactory;
+ private final UnscopedDirectInstanceRequestRepresentationFactory
+ unscopedDirectInstanceRequestRepresentationFactory;
+ private final Map<BindingRequest, RequestRepresentation> requestRepresentations = new HashMap<>();
+
+ @AssistedInject
+ DirectInstanceBindingRepresentation(
+ @Assisted ProvisionBinding binding,
+ BindingGraph graph,
+ ComponentImplementation componentImplementation,
+ ComponentMethodRequestRepresentation.Factory componentMethodRequestRepresentationFactory,
+ ImmediateFutureRequestRepresentation.Factory immediateFutureRequestRepresentationFactory,
+ PrivateMethodRequestRepresentation.Factory privateMethodRequestRepresentationFactory,
+ UnscopedDirectInstanceRequestRepresentationFactory
+ unscopedDirectInstanceRequestRepresentationFactory) {
+ this.binding = binding;
+ this.graph = graph;
+ this.componentImplementation = componentImplementation;
+ this.componentMethodRequestRepresentationFactory = componentMethodRequestRepresentationFactory;
+ this.immediateFutureRequestRepresentationFactory = immediateFutureRequestRepresentationFactory;
+ this.privateMethodRequestRepresentationFactory = privateMethodRequestRepresentationFactory;
+ this.unscopedDirectInstanceRequestRepresentationFactory =
+ unscopedDirectInstanceRequestRepresentationFactory;
+ }
+
+ public RequestRepresentation getRequestRepresentation(BindingRequest request) {
+ return reentrantComputeIfAbsent(
+ requestRepresentations, request, this::getRequestRepresentationUncached);
+ }
+
+ private RequestRepresentation getRequestRepresentationUncached(BindingRequest request) {
+ switch (request.requestKind()) {
+ case INSTANCE:
+ return requiresMethodEncapsulation(binding)
+ ? wrapInMethod(unscopedDirectInstanceRequestRepresentationFactory.create(binding))
+ : unscopedDirectInstanceRequestRepresentationFactory.create(binding);
+
+ case FUTURE:
+ return immediateFutureRequestRepresentationFactory.create(
+ getRequestRepresentation(bindingRequest(binding.key(), RequestKind.INSTANCE)),
+ binding.key().type().java());
+
+ default:
+ throw new AssertionError(
+ String.format("Invalid binding request kind: %s", request.requestKind()));
+ }
+ }
+
+ /**
+ * Returns a binding expression that uses a given one as the body of a method that users call. If
+ * a component provision method matches it, it will be the method implemented. If it does not
+ * match a component provision method and the binding is modifiable, then a new public modifiable
+ * binding method will be written. If the binding doesn't match a component method and is not
+ * modifiable, then a new private method will be written.
+ */
+ RequestRepresentation wrapInMethod(RequestRepresentation bindingExpression) {
+ // If we've already wrapped the expression, then use the delegate.
+ if (bindingExpression instanceof MethodRequestRepresentation) {
+ return bindingExpression;
+ }
+
+ BindingRequest request = bindingRequest(binding.key(), RequestKind.INSTANCE);
+ Optional<ComponentMethodDescriptor> matchingComponentMethod =
+ graph.componentDescriptor().firstMatchingComponentMethod(request);
+
+ ShardImplementation shardImplementation = componentImplementation.shardImplementation(binding);
+
+ // Consider the case of a request from a component method like:
+ //
+ // DaggerMyComponent extends MyComponent {
+ // @Overrides
+ // Foo getFoo() {
+ // <FOO_BINDING_REQUEST>
+ // }
+ // }
+ //
+ // Normally, in this case we would return a ComponentMethodRequestRepresentation rather than a
+ // PrivateMethodRequestRepresentation so that #getFoo() can inline the implementation rather
+ // than
+ // create an unnecessary private method and return that. However, with sharding we don't want to
+ // inline the implementation because that would defeat some of the class pool savings if those
+ // fields had to communicate across shards. Thus, when a key belongs to a separate shard use a
+ // PrivateMethodRequestRepresentation and put the private method in the shard.
+ if (matchingComponentMethod.isPresent() && shardImplementation.isComponentShard()) {
+ ComponentMethodDescriptor componentMethod = matchingComponentMethod.get();
+ return componentMethodRequestRepresentationFactory.create(bindingExpression, componentMethod);
+ } else {
+ return privateMethodRequestRepresentationFactory.create(request, binding, bindingExpression);
+ }
+ }
+
+ private static boolean requiresMethodEncapsulation(ProvisionBinding binding) {
+ switch (binding.kind()) {
+ case COMPONENT:
+ case COMPONENT_PROVISION:
+ case SUBCOMPONENT_CREATOR:
+ case COMPONENT_DEPENDENCY:
+ case MULTIBOUND_SET:
+ case MULTIBOUND_MAP:
+ case BOUND_INSTANCE:
+ case ASSISTED_FACTORY:
+ case ASSISTED_INJECTION:
+ case INJECTION:
+ case PROVISION:
+ // These binding kinds satify a binding request with a component method or a private
+ // method when the requested binding has dependencies. The method will wrap the logic of
+ // creating the binding instance. Without the encapsulation, we might see many levels of
+ // nested instance creation code in a single statement to satisfy all dependencies of a
+ // binding request.
+ return !binding.dependencies().isEmpty();
+ case MEMBERS_INJECTOR:
+ case PRODUCTION:
+ case COMPONENT_PRODUCTION:
+ case OPTIONAL:
+ case DELEGATE:
+ case MEMBERS_INJECTION:
+ return false;
+ }
+ throw new AssertionError(String.format("No such binding kind: %s", binding.kind()));
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ DirectInstanceBindingRepresentation create(ProvisionBinding binding);
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/ExperimentalSwitchingProviderDependencyRepresentation.java b/java/dagger/internal/codegen/writing/ExperimentalSwitchingProviderDependencyRepresentation.java
new file mode 100644
index 000000000..817f76b87
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/ExperimentalSwitchingProviderDependencyRepresentation.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.langmodel.Accessibility.isRawTypeAccessible;
+import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+
+import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.binding.BindsTypeChecker;
+import dagger.internal.codegen.binding.FrameworkType;
+import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.RequestKind;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Returns type casted expressions to satisfy dependency requests from experimental switching
+ * providers.
+ */
+final class ExperimentalSwitchingProviderDependencyRepresentation {
+ private final ProvisionBinding binding;
+ private final ShardImplementation shardImplementation;
+ private final BindsTypeChecker bindsTypeChecker;
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+ private final TypeMirror type;
+
+ @AssistedInject
+ ExperimentalSwitchingProviderDependencyRepresentation(
+ @Assisted ProvisionBinding binding,
+ ComponentImplementation componentImplementation,
+ DaggerTypes types,
+ DaggerElements elements) {
+ this.binding = binding;
+ this.shardImplementation = componentImplementation.shardImplementation(binding);
+ this.types = types;
+ this.elements = elements;
+ this.bindsTypeChecker = new BindsTypeChecker(types, elements);
+ this.type =
+ isDelegateSetValuesBinding()
+ ? types.erasure(elements.getTypeElement(TypeNames.COLLECTION).asType())
+ : toJavac(binding.contributedType());
+ }
+
+ Expression getDependencyExpression(RequestKind requestKind, ProvisionBinding requestingBinding) {
+ int index = findIndexOfDependency(requestingBinding);
+ TypeMirror frameworkType =
+ types.getDeclaredType(elements.getTypeElement(FrameworkType.PROVIDER.frameworkClassName()));
+ Expression expression =
+ FrameworkType.PROVIDER.to(
+ requestKind,
+ Expression.create(
+ frameworkType, CodeBlock.of("(($T) dependencies[$L])", frameworkType, index)),
+ types);
+ if (usesExplicitTypeCast(expression, requestKind)) {
+ return expression.castTo(type);
+ }
+ if (usesErasedTypeCast(requestKind)) {
+ return expression.castTo(types.erasure(type));
+ }
+ return expression;
+ }
+
+ private int findIndexOfDependency(ProvisionBinding requestingBinding) {
+ return requestingBinding.dependencies().stream()
+ .map(DependencyRequest::key)
+ .collect(toImmutableList())
+ .indexOf(binding.key())
+ + (requestingBinding.requiresModuleInstance()
+ && requestingBinding.contributingModule().isPresent()
+ ? 1
+ : 0);
+ }
+
+ private boolean isDelegateSetValuesBinding() {
+ return binding.kind().equals(BindingKind.DELEGATE)
+ && binding.contributionType().equals(ContributionType.SET_VALUES);
+ }
+
+ private boolean usesExplicitTypeCast(Expression expression, RequestKind requestKind) {
+ // If the type is accessible, we can directly cast the expression use the type.
+ return requestKind.equals(RequestKind.INSTANCE)
+ && !bindsTypeChecker.isAssignable(expression.type(), type, binding.contributionType())
+ && isTypeAccessibleFrom(type, shardImplementation.name().packageName());
+ }
+
+ private boolean usesErasedTypeCast(RequestKind requestKind) {
+ // If a type has inaccessible type arguments, then cast to raw type.
+ return requestKind.equals(RequestKind.INSTANCE)
+ && !isTypeAccessibleFrom(type, shardImplementation.name().packageName())
+ && isRawTypeAccessible(type, shardImplementation.name().packageName());
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ ExperimentalSwitchingProviderDependencyRepresentation create(ProvisionBinding binding);
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/ExperimentalSwitchingProviders.java b/java/dagger/internal/codegen/writing/ExperimentalSwitchingProviders.java
new file mode 100644
index 000000000..679be6b41
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/ExperimentalSwitchingProviders.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getLast;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.suppressWarnings;
+import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import com.squareup.javapoet.TypeVariableName;
+import dagger.internal.codegen.base.UniqueNameSet;
+import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.javapoet.CodeBlocks;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
+import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.spi.model.Key;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+import javax.inject.Inject;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Keeps track of all provider expression requests for a component.
+ *
+ * <p>The provider expression request will be satisfied by a single generated {@code Provider} class
+ * that can provide instances for all types by switching on an id.
+ */
+@PerComponentImplementation
+final class ExperimentalSwitchingProviders {
+ /**
+ * Each switch size is fixed at 100 cases each and put in its own method. This is to limit the
+ * size of the methods so that we don't reach the "huge" method size limit for Android that will
+ * prevent it from being AOT compiled in some versions of Android (b/77652521). This generally
+ * starts to happen around 1500 cases, but we are choosing 100 to be safe.
+ */
+ // TODO(bcorso): Include a proguard_spec in the Dagger library to prevent inlining these methods?
+ // TODO(ronshapiro): Consider making this configurable via a flag.
+ private static final int MAX_CASES_PER_SWITCH = 100;
+
+ private static final long MAX_CASES_PER_CLASS = MAX_CASES_PER_SWITCH * MAX_CASES_PER_SWITCH;
+ private static final TypeVariableName T = TypeVariableName.get("T");
+
+ /**
+ * Maps a {@link Key} to an instance of a {@link SwitchingProviderBuilder}. Each group of {@code
+ * MAX_CASES_PER_CLASS} keys will share the same instance.
+ */
+ private final Map<Key, SwitchingProviderBuilder> switchingProviderBuilders =
+ new LinkedHashMap<>();
+
+ private final ShardImplementation componentShard;
+ private final DaggerTypes types;
+ private final UniqueNameSet switchingProviderNames = new UniqueNameSet();
+ private final ComponentRequestRepresentations componentRequestRepresentations;
+ private final ComponentImplementation componentImplementation;
+
+ @Inject
+ ExperimentalSwitchingProviders(
+ ComponentImplementation componentImplementation,
+ ComponentRequestRepresentations componentRequestRepresentations,
+ DaggerTypes types) {
+ this.componentShard = checkNotNull(componentImplementation).getComponentShard();
+ this.componentRequestRepresentations = componentRequestRepresentations;
+ this.componentImplementation = componentImplementation;
+ this.types = checkNotNull(types);
+ }
+
+ /** Returns the framework instance creation expression for an inner switching provider class. */
+ FrameworkInstanceCreationExpression newFrameworkInstanceCreationExpression(
+ ProvisionBinding binding, RequestRepresentation unscopedInstanceRequestRepresentation) {
+ return new FrameworkInstanceCreationExpression() {
+ @Override
+ public CodeBlock creationExpression() {
+ return switchingProviderBuilders
+ .computeIfAbsent(binding.key(), key -> getSwitchingProviderBuilder())
+ .getNewInstanceCodeBlock(binding, unscopedInstanceRequestRepresentation);
+ }
+ };
+ }
+
+ private SwitchingProviderBuilder getSwitchingProviderBuilder() {
+ if (switchingProviderBuilders.size() % MAX_CASES_PER_CLASS == 0) {
+ String name = switchingProviderNames.getUniqueName("SwitchingProvider");
+ // TODO(wanyingd): move Switching Providers and injection methods to Shard classes to avoid
+ // exceeding component class constant pool limit.
+ SwitchingProviderBuilder switchingProviderBuilder =
+ new SwitchingProviderBuilder(componentShard.name().nestedClass(name));
+ componentShard.addTypeSupplier(switchingProviderBuilder::build);
+ return switchingProviderBuilder;
+ }
+ return getLast(switchingProviderBuilders.values());
+ }
+
+ // TODO(bcorso): Consider just merging this class with ExperimentalSwitchingProviders.
+ private final class SwitchingProviderBuilder {
+ // Keep the switch cases ordered by switch id. The switch Ids are assigned in pre-order
+ // traversal, but the switch cases are assigned in post-order traversal of the binding graph.
+ private final Map<Integer, CodeBlock> switchCases = new TreeMap<>();
+ private final Map<Key, Integer> switchIds = new HashMap<>();
+ private final ClassName switchingProviderType;
+
+ SwitchingProviderBuilder(ClassName switchingProviderType) {
+ this.switchingProviderType = checkNotNull(switchingProviderType);
+ }
+
+ private CodeBlock getNewInstanceCodeBlock(
+ ProvisionBinding binding, RequestRepresentation unscopedInstanceRequestRepresentation) {
+ Key key = binding.key();
+ if (!switchIds.containsKey(key)) {
+ int switchId = switchIds.size();
+ switchIds.put(key, switchId);
+ switchCases.put(
+ switchId, createSwitchCaseCodeBlock(key, unscopedInstanceRequestRepresentation));
+ }
+
+ ShardImplementation shardImplementation =
+ componentImplementation.shardImplementation(binding);
+ CodeBlock switchingProviderDependencies;
+ switch (binding.kind()) {
+ // TODO(wanyingd): there might be a better way to get component requirement information
+ // without using unscopedInstanceRequestRepresentation.
+ case COMPONENT_PROVISION:
+ switchingProviderDependencies =
+ ((ComponentProvisionRequestRepresentation) unscopedInstanceRequestRepresentation)
+ .getComponentRequirementExpression(shardImplementation.name());
+ break;
+ case SUBCOMPONENT_CREATOR:
+ switchingProviderDependencies =
+ ((SubcomponentCreatorRequestRepresentation) unscopedInstanceRequestRepresentation)
+ .getDependencyExpressionArguments();
+ break;
+ case MULTIBOUND_SET:
+ case MULTIBOUND_MAP:
+ case OPTIONAL:
+ case INJECTION:
+ case PROVISION:
+ case ASSISTED_FACTORY:
+ // Arguments built in the order of module reference, provision dependencies and members
+ // injection dependencies
+ switchingProviderDependencies =
+ componentRequestRepresentations.getCreateMethodArgumentsCodeBlock(
+ binding, shardImplementation.name());
+ break;
+ default:
+ throw new IllegalArgumentException("Unexpected binding kind: " + binding.kind());
+ }
+
+ TypeMirror castedType =
+ shardImplementation.accessibleType(toJavac(binding.contributedType()));
+ return CodeBlock.of(
+ "new $T<$L>($L)",
+ switchingProviderType,
+ // Add the type parameter explicitly when the binding is scoped because Java can't resolve
+ // the type when wrapped. For example, the following will error:
+ // fooProvider = DoubleCheck.provider(new SwitchingProvider<>(1));
+ CodeBlock.of("$T", castedType),
+ switchingProviderDependencies.isEmpty()
+ ? CodeBlock.of("$L", switchIds.get(key))
+ : CodeBlock.of("$L, $L", switchIds.get(key), switchingProviderDependencies));
+ }
+
+ private CodeBlock createSwitchCaseCodeBlock(
+ Key key, RequestRepresentation unscopedInstanceRequestRepresentation) {
+ // TODO(bcorso): Try to delay calling getDependencyExpression() until we are writing out the
+ // SwitchingProvider because calling it here makes FrameworkFieldInitializer think there's a
+ // cycle when initializing ExperimentalSwitchingProviders which adds an unnecessary
+ // DelegateFactory.
+ CodeBlock instanceCodeBlock =
+ unscopedInstanceRequestRepresentation
+ .getDependencyExpression(switchingProviderType)
+ .box(types)
+ .codeBlock();
+
+ return CodeBlock.builder()
+ // TODO(bcorso): Is there something else more useful than the key?
+ .add("case $L: // $L \n", switchIds.get(key), key)
+ .addStatement("return ($T) $L", T, instanceCodeBlock)
+ .build();
+ }
+
+ private TypeSpec build() {
+ TypeSpec.Builder builder =
+ classBuilder(switchingProviderType)
+ .addModifiers(PRIVATE, FINAL, STATIC)
+ .addTypeVariable(T)
+ .addSuperinterface(providerOf(T))
+ .addMethods(getMethods());
+
+ // The SwitchingProvider constructor lists switch id first and then the dependency array.
+ MethodSpec.Builder constructor = MethodSpec.constructorBuilder();
+ builder.addField(TypeName.INT, "id", PRIVATE, FINAL);
+ constructor.addParameter(TypeName.INT, "id").addStatement("this.id = id");
+ // Pass in provision dependencies and members injection dependencies.
+ builder.addField(Object[].class, "dependencies", FINAL, PRIVATE);
+ constructor
+ .addParameter(Object[].class, "dependencies")
+ .addStatement("this.dependencies = dependencies")
+ .varargs(true);
+
+ return builder.addMethod(constructor.build()).build();
+ }
+
+ private ImmutableList<MethodSpec> getMethods() {
+ ImmutableList<CodeBlock> switchCodeBlockPartitions = switchCodeBlockPartitions();
+ if (switchCodeBlockPartitions.size() == 1) {
+ // There are less than MAX_CASES_PER_SWITCH cases, so no need for extra get methods.
+ return ImmutableList.of(
+ methodBuilder("get")
+ .addModifiers(PUBLIC)
+ .addAnnotation(suppressWarnings(UNCHECKED))
+ .addAnnotation(Override.class)
+ .returns(T)
+ .addCode(getOnlyElement(switchCodeBlockPartitions))
+ .build());
+ }
+
+ // This is the main public "get" method that will route to private getter methods.
+ MethodSpec.Builder routerMethod =
+ methodBuilder("get")
+ .addModifiers(PUBLIC)
+ .addAnnotation(Override.class)
+ .returns(T)
+ .beginControlFlow("switch (id / $L)", MAX_CASES_PER_SWITCH);
+
+ ImmutableList.Builder<MethodSpec> getMethods = ImmutableList.builder();
+ for (int i = 0; i < switchCodeBlockPartitions.size(); i++) {
+ MethodSpec method =
+ methodBuilder("get" + i)
+ .addModifiers(PRIVATE)
+ .addAnnotation(suppressWarnings(UNCHECKED))
+ .returns(T)
+ .addCode(switchCodeBlockPartitions.get(i))
+ .build();
+ getMethods.add(method);
+ routerMethod.addStatement("case $L: return $N()", i, method);
+ }
+
+ routerMethod.addStatement("default: throw new $T(id)", AssertionError.class).endControlFlow();
+
+ return getMethods.add(routerMethod.build()).build();
+ }
+
+ private ImmutableList<CodeBlock> switchCodeBlockPartitions() {
+ return Lists.partition(ImmutableList.copyOf(switchCases.values()), MAX_CASES_PER_SWITCH)
+ .stream()
+ .map(
+ partitionCases ->
+ CodeBlock.builder()
+ .beginControlFlow("switch (id)")
+ .add(CodeBlocks.concat(partitionCases))
+ .addStatement("default: throw new $T(id)", AssertionError.class)
+ .endControlFlow()
+ .build())
+ .collect(toImmutableList());
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/FactoryGenerator.java b/java/dagger/internal/codegen/writing/FactoryGenerator.java
index 03ad27cbb..ea83778b0 100644
--- a/java/dagger/internal/codegen/writing/FactoryGenerator.java
+++ b/java/dagger/internal/codegen/writing/FactoryGenerator.java
@@ -17,35 +17,41 @@
package dagger.internal.codegen.writing;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Maps.transformValues;
import static com.squareup.javapoet.MethodSpec.constructorBuilder;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
import static com.squareup.javapoet.TypeSpec.classBuilder;
import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedParameters;
-import static dagger.internal.codegen.binding.ContributionBinding.FactoryCreationStrategy.DELEGATE;
-import static dagger.internal.codegen.binding.ContributionBinding.FactoryCreationStrategy.SINGLETON_INSTANCE;
import static dagger.internal.codegen.binding.SourceFiles.bindingTypeElementTypeVariableNames;
import static dagger.internal.codegen.binding.SourceFiles.frameworkFieldUsages;
import static dagger.internal.codegen.binding.SourceFiles.frameworkTypeUsageStatement;
import static dagger.internal.codegen.binding.SourceFiles.generateBindingFieldsForDependencies;
import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
import static dagger.internal.codegen.binding.SourceFiles.parameterizedGeneratedTypeNameForBinding;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.extension.DaggerStreams.presentValues;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.suppressWarnings;
import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
import static dagger.internal.codegen.javapoet.TypeNames.factoryOf;
import static dagger.internal.codegen.writing.GwtCompatibility.gwtIncompatibleAnnotation;
-import static dagger.model.BindingKind.PROVISION;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static dagger.spi.model.BindingKind.INJECTION;
+import static dagger.spi.model.BindingKind.PROVISION;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.compat.XConverters;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
+import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
@@ -56,22 +62,27 @@ import com.squareup.javapoet.TypeSpec;
import dagger.internal.Factory;
import dagger.internal.codegen.base.SourceFileGenerator;
import dagger.internal.codegen.base.UniqueNameSet;
+import dagger.internal.codegen.binding.Binding;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.javapoet.CodeBlocks;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
import dagger.internal.codegen.writing.InjectionMethods.InjectionSiteMethod;
import dagger.internal.codegen.writing.InjectionMethods.ProvisionMethod;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.DaggerAnnotation;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
+import dagger.spi.model.Scope;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
-import javax.annotation.processing.Filer;
+import java.util.stream.Stream;
import javax.inject.Inject;
import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
+import javax.lang.model.element.VariableElement;
/**
* Generates {@link Factory} implementations from {@link ProvisionBinding} instances for {@link
@@ -84,7 +95,7 @@ public final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding
@Inject
FactoryGenerator(
- Filer filer,
+ XFiler filer,
SourceVersion sourceVersion,
DaggerTypes types,
DaggerElements elements,
@@ -97,7 +108,7 @@ public final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding
}
@Override
- public Element originatingElement(ProvisionBinding binding) {
+ public XElement originatingElement(ProvisionBinding binding) {
// we only create factories for bindings that have a binding element
return binding.bindingElement().get();
}
@@ -108,7 +119,7 @@ public final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding
checkArgument(!binding.unresolved().isPresent());
checkArgument(binding.bindingElement().isPresent());
- if (binding.factoryCreationStrategy().equals(DELEGATE)) {
+ if (binding.kind() == BindingKind.DELEGATE) {
return ImmutableList.of();
}
@@ -121,6 +132,13 @@ public final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding
.addModifiers(PUBLIC, FINAL)
.addTypeVariables(bindingTypeElementTypeVariableNames(binding));
+ if (binding.kind() == BindingKind.INJECTION
+ || binding.kind() == BindingKind.ASSISTED_INJECTION
+ || binding.kind() == BindingKind.PROVISION) {
+ factoryBuilder.addAnnotation(scopeMetadataAnnotation(binding));
+ factoryBuilder.addAnnotation(qualifierMetadataAnnotation(binding));
+ }
+
factoryTypeName(binding).ifPresent(factoryBuilder::addSuperinterface);
addConstructorAndFields(binding, factoryBuilder);
factoryBuilder.addMethod(getMethod(binding));
@@ -133,7 +151,7 @@ public final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding
}
private void addConstructorAndFields(ProvisionBinding binding, TypeSpec.Builder factoryBuilder) {
- if (binding.factoryCreationStrategy().equals(SINGLETON_INSTANCE)) {
+ if (FactoryCreationStrategy.of(binding) == FactoryCreationStrategy.SINGLETON_INSTANCE) {
return;
}
// TODO(bcorso): Make the constructor private?
@@ -157,7 +175,7 @@ public final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding
private Optional<ParameterSpec> moduleParameter(ProvisionBinding binding) {
if (binding.requiresModuleInstance()) {
// TODO(bcorso, dpb): Should this use contributingModule()?
- TypeName type = TypeName.get(binding.bindingTypeElement().get().asType());
+ TypeName type = binding.bindingTypeElement().get().getType().getTypeName();
return Optional.of(ParameterSpec.builder(type, "module").build());
}
return Optional.empty();
@@ -167,13 +185,16 @@ public final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding
UniqueNameSet uniqueFieldNames = new UniqueNameSet();
// TODO(bcorso, dpb): Add a test for the case when a Factory parameter is named "module".
moduleParameter(binding).ifPresent(module -> uniqueFieldNames.claim(module.name));
- return ImmutableMap.copyOf(
- transformValues(
- generateBindingFieldsForDependencies(binding),
- field ->
+ // We avoid Maps.transformValues here because it would implicitly depend on the order in which
+ // the transform function is evaluated on each entry in the map.
+ ImmutableMap.Builder<DependencyRequest, FieldSpec> builder = ImmutableMap.builder();
+ generateBindingFieldsForDependencies(binding).forEach(
+ (dependency, field) ->
+ builder.put(dependency,
FieldSpec.builder(
field.type(), uniqueFieldNames.getUniqueName(field.name()), PRIVATE, FINAL)
.build()));
+ return builder.build();
}
private void addCreateMethod(ProvisionBinding binding, TypeSpec.Builder factoryBuilder) {
@@ -186,7 +207,7 @@ public final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding
.returns(parameterizedGeneratedTypeNameForBinding(binding))
.addTypeVariables(bindingTypeElementTypeVariableNames(binding));
- switch (binding.factoryCreationStrategy()) {
+ switch (FactoryCreationStrategy.of(binding)) {
case SINGLETON_INSTANCE:
FieldSpec.Builder instanceFieldBuilder =
FieldSpec.builder(
@@ -223,28 +244,36 @@ public final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding
}
private MethodSpec getMethod(ProvisionBinding binding) {
+ UniqueNameSet uniqueFieldNames = new UniqueNameSet();
+ ImmutableMap<DependencyRequest, FieldSpec> frameworkFields = frameworkFields(binding);
+ frameworkFields.values().forEach(field -> uniqueFieldNames.claim(field.name));
+ Map<VariableElement, ParameterSpec> assistedParameters =
+ assistedParameters(binding).stream()
+ .collect(
+ toImmutableMap(
+ XConverters::toJavac,
+ element ->
+ ParameterSpec.builder(
+ element.getType().getTypeName(),
+ uniqueFieldNames.getUniqueName(getSimpleName(element)))
+ .build()));
TypeName providedTypeName = providedTypeName(binding);
MethodSpec.Builder getMethod =
methodBuilder("get")
.addModifiers(PUBLIC)
.returns(providedTypeName)
- .addParameters(
- // The 'get' method for an assisted injection type takes in the assisted parameters.
- assistedParameters(binding).stream()
- .map(ParameterSpec::get)
- .collect(toImmutableList()));
+ .addParameters(assistedParameters.values());
if (factoryTypeName(binding).isPresent()) {
getMethod.addAnnotation(Override.class);
}
-
- ImmutableMap<DependencyRequest, FieldSpec> frameworkFields = frameworkFields(binding);
CodeBlock invokeNewInstance =
ProvisionMethod.invoke(
binding,
request ->
frameworkTypeUsageStatement(
CodeBlock.of("$N", frameworkFields.get(request)), request.kind()),
+ param -> assistedParameters.get(param).name,
generatedClassNameForBinding(binding),
moduleParameter(binding).map(module -> CodeBlock.of("$N", module)),
compilerOptions,
@@ -253,7 +282,9 @@ public final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding
if (binding.kind().equals(PROVISION)) {
binding
.nullableType()
- .ifPresent(nullableType -> CodeBlocks.addAnnotation(getMethod, nullableType));
+ .map(XType::getTypeElement)
+ .map(XTypeElement::getClassName)
+ .ifPresent(getMethod::addAnnotation);
getMethod.addStatement("return $L", invokeNewInstance);
} else if (!binding.injectionSites().isEmpty()) {
CodeBlock instance = CodeBlock.of("instance");
@@ -264,7 +295,7 @@ public final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding
binding.injectionSites(),
generatedClassNameForBinding(binding),
instance,
- binding.key().type(),
+ binding.key().type().java(),
frameworkFieldUsages(binding.dependencies(), frameworkFields)::get,
types,
metadataUtil))
@@ -275,8 +306,33 @@ public final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding
return getMethod.build();
}
+ private AnnotationSpec scopeMetadataAnnotation(ProvisionBinding binding) {
+ AnnotationSpec.Builder builder = AnnotationSpec.builder(TypeNames.SCOPE_METADATA);
+ binding.scope()
+ .map(Scope::scopeAnnotation)
+ .map(DaggerAnnotation::className)
+ .map(ClassName::canonicalName)
+ .ifPresent(scopeCanonicalName -> builder.addMember("value", "$S", scopeCanonicalName));
+ return builder.build();
+ }
+
+ private AnnotationSpec qualifierMetadataAnnotation(ProvisionBinding binding) {
+ AnnotationSpec.Builder builder = AnnotationSpec.builder(TypeNames.QUALIFIER_METADATA);
+ // Collect all qualifiers on the binding itself or its dependencies
+ Stream.concat(
+ Stream.of(binding.key()),
+ binding.provisionDependencies().stream().map(DependencyRequest::key))
+ .map(Key::qualifier)
+ .flatMap(presentValues())
+ .map(DaggerAnnotation::className)
+ .map(ClassName::canonicalName)
+ .distinct()
+ .forEach(qualifier -> builder.addMember("value", "$S", qualifier));
+ return builder.build();
+ }
+
private static TypeName providedTypeName(ProvisionBinding binding) {
- return TypeName.get(binding.contributedType());
+ return binding.contributedType().getTypeName();
}
private static Optional<TypeName> factoryTypeName(ProvisionBinding binding) {
@@ -288,4 +344,31 @@ public final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding
private static ParameterSpec toParameter(FieldSpec field) {
return ParameterSpec.builder(field.type, field.name).build();
}
+
+ /** The strategy for getting an instance of a factory for a {@link Binding}. */
+ private enum FactoryCreationStrategy {
+ /** The factory class is a single instance. */
+ SINGLETON_INSTANCE,
+ /** The factory must be created by calling the constructor. */
+ CLASS_CONSTRUCTOR;
+
+ static FactoryCreationStrategy of(Binding binding) {
+ switch (binding.kind()) {
+ case DELEGATE:
+ throw new AssertionError("Delegate bindings don't have a factory.");
+ case PROVISION:
+ return binding.dependencies().isEmpty() && !binding.requiresModuleInstance()
+ ? SINGLETON_INSTANCE
+ : CLASS_CONSTRUCTOR;
+ case INJECTION:
+ case MULTIBOUND_SET:
+ case MULTIBOUND_MAP:
+ return binding.dependencies().isEmpty()
+ ? SINGLETON_INSTANCE
+ : CLASS_CONSTRUCTOR;
+ default:
+ return CLASS_CONSTRUCTOR;
+ }
+ }
+ }
}
diff --git a/java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java b/java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java
index c17ff8e53..811866bcd 100644
--- a/java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java
+++ b/java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java
@@ -34,8 +34,9 @@ import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.binding.FrameworkField;
import dagger.internal.codegen.javapoet.AnnotationSpecs;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.model.BindingKind;
-import dagger.producers.internal.DelegateProducer;
+import dagger.internal.codegen.writing.ComponentImplementation.CompilerMode;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
+import dagger.spi.model.BindingKind;
import java.util.Optional;
/**
@@ -59,23 +60,12 @@ class FrameworkFieldInitializer implements FrameworkInstanceSupplier {
default Optional<ClassName> alternativeFrameworkClass() {
return Optional.empty();
}
-
- /**
- * Returns {@code true} if instead of using {@link #creationExpression()} to create a framework
- * instance, a case in {@link InnerSwitchingProviders} should be created for this binding.
- */
- // TODO(ronshapiro): perhaps this isn't the right approach. Instead of saying "Use
- // SetFactory.EMPTY because you will only get 1 class for all types of bindings that use
- // SetFactory", maybe we should still use an inner switching provider but the same switching
- // provider index for all cases.
- default boolean useInnerSwitchingProvider() {
- return true;
- }
}
- private final ComponentImplementation componentImplementation;
+ private final ShardImplementation shardImplementation;
private final ContributionBinding binding;
private final FrameworkInstanceCreationExpression frameworkInstanceCreationExpression;
+ private final CompilerMode compilerMode;
private FieldSpec fieldSpec;
private InitializationState fieldInitializationState = InitializationState.UNINITIALIZED;
@@ -83,8 +73,9 @@ class FrameworkFieldInitializer implements FrameworkInstanceSupplier {
ComponentImplementation componentImplementation,
ContributionBinding binding,
FrameworkInstanceCreationExpression frameworkInstanceCreationExpression) {
- this.componentImplementation = checkNotNull(componentImplementation);
this.binding = checkNotNull(binding);
+ this.compilerMode = componentImplementation.compilerMode();
+ this.shardImplementation = checkNotNull(componentImplementation).shardImplementation(binding);
this.frameworkInstanceCreationExpression = checkNotNull(frameworkInstanceCreationExpression);
}
@@ -95,14 +86,14 @@ class FrameworkFieldInitializer implements FrameworkInstanceSupplier {
@Override
public final MemberSelect memberSelect() {
initializeField();
- return MemberSelect.localField(componentImplementation.name(), checkNotNull(fieldSpec).name);
+ return MemberSelect.localField(shardImplementation, checkNotNull(fieldSpec).name);
}
/** Adds the field and its initialization code to the component. */
private void initializeField() {
switch (fieldInitializationState) {
case UNINITIALIZED:
- // Change our state in case we are recursively invoked via initializeBindingExpression
+ // Change our state in case we are recursively invoked via initializeRequestRepresentation
fieldInitializationState = InitializationState.INITIALIZING;
CodeBlock.Builder codeBuilder = CodeBlock.builder();
CodeBlock fieldInitialization = frameworkInstanceCreationExpression.creationExpression();
@@ -114,16 +105,24 @@ class FrameworkFieldInitializer implements FrameworkInstanceSupplier {
} else {
codeBuilder.add(initCode);
}
- componentImplementation.addInitialization(codeBuilder.build());
+ shardImplementation.addInitialization(codeBuilder.build());
fieldInitializationState = InitializationState.INITIALIZED;
break;
case INITIALIZING:
- // We were recursively invoked, so create a delegate factory instead
+ fieldSpec = getOrCreateField();
+ // We were recursively invoked, so create a delegate factory instead to break the loop.
+ // However, because SwitchingProvider takes no dependencies, even if they are recursively
+ // invoked, we don't need to delegate it since there is no dependency cycle.
+ if (FrameworkInstanceKind.from(binding, compilerMode)
+ .equals(FrameworkInstanceKind.SWITCHING_PROVIDER)) {
+ break;
+ }
+
fieldInitializationState = InitializationState.DELEGATED;
- componentImplementation.addInitialization(
- CodeBlock.of("this.$N = new $T<>();", getOrCreateField(), delegateType()));
+ shardImplementation.addInitialization(
+ CodeBlock.of("this.$N = new $T<>();", fieldSpec, delegateType()));
break;
case DELEGATED:
@@ -140,7 +139,7 @@ class FrameworkFieldInitializer implements FrameworkInstanceSupplier {
if (fieldSpec != null) {
return fieldSpec;
}
- boolean useRawType = !componentImplementation.isTypeAccessible(binding.key().type());
+ boolean useRawType = !shardImplementation.isTypeAccessible(binding.key().type().java());
FrameworkField contributionBindingField =
FrameworkField.forBinding(
binding, frameworkInstanceCreationExpression.alternativeFrameworkClass());
@@ -152,7 +151,7 @@ class FrameworkFieldInitializer implements FrameworkInstanceSupplier {
// An assisted injection factory doesn't extend Provider, so we reference the generated
// factory type directly (i.e. Foo_Factory<T> instead of Provider<Foo<T>>).
TypeName[] typeParameters =
- MoreTypes.asDeclared(binding.key().type()).getTypeArguments().stream()
+ MoreTypes.asDeclared(binding.key().type().java()).getTypeArguments().stream()
.map(TypeName::get)
.toArray(TypeName[]::new);
fieldType =
@@ -163,20 +162,20 @@ class FrameworkFieldInitializer implements FrameworkInstanceSupplier {
FieldSpec.Builder contributionField =
FieldSpec.builder(
- fieldType, componentImplementation.getUniqueFieldName(contributionBindingField.name()));
+ fieldType, shardImplementation.getUniqueFieldName(contributionBindingField.name()));
contributionField.addModifiers(PRIVATE);
if (useRawType) {
contributionField.addAnnotation(AnnotationSpecs.suppressWarnings(RAWTYPES));
}
fieldSpec = contributionField.build();
- componentImplementation.addField(FRAMEWORK_FIELD, fieldSpec);
+ shardImplementation.addField(FRAMEWORK_FIELD, fieldSpec);
return fieldSpec;
}
- private Class<?> delegateType() {
- return isProvider() ? DelegateFactory.class : DelegateProducer.class;
+ private ClassName delegateType() {
+ return isProvider() ? TypeNames.DELEGATE_FACTORY : TypeNames.DELEGATE_PRODUCER;
}
private boolean isProvider() {
diff --git a/java/dagger/internal/codegen/writing/FrameworkInstanceBindingRepresentation.java b/java/dagger/internal/codegen/writing/FrameworkInstanceBindingRepresentation.java
new file mode 100644
index 000000000..d4fb497d3
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/FrameworkInstanceBindingRepresentation.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
+import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
+import static dagger.internal.codegen.writing.ProvisionBindingRepresentation.needsCaching;
+import static dagger.spi.model.BindingKind.DELEGATE;
+
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.binding.BindingGraph;
+import dagger.internal.codegen.binding.BindingRequest;
+import dagger.internal.codegen.binding.FrameworkType;
+import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.spi.model.RequestKind;
+import java.util.HashMap;
+import java.util.Map;
+
+/** Returns request representation that wraps a framework instance expression */
+final class FrameworkInstanceBindingRepresentation {
+ private final ProvisionBinding binding;
+ private final DerivedFromFrameworkInstanceRequestRepresentation.Factory
+ derivedFromFrameworkInstanceRequestRepresentationFactory;
+ private final ImmediateFutureRequestRepresentation.Factory
+ immediateFutureRequestRepresentationFactory;
+ private final Map<BindingRequest, RequestRepresentation> requestRepresentations = new HashMap<>();
+ private final RequestRepresentation providerRequestRepresentation;
+ private final RequestRepresentation producerFromProviderRepresentation;
+
+ @AssistedInject
+ FrameworkInstanceBindingRepresentation(
+ @Assisted ProvisionBinding binding,
+ BindingGraph graph,
+ @Assisted FrameworkInstanceSupplier providerField,
+ ComponentImplementation componentImplementation,
+ DelegateRequestRepresentation.Factory delegateRequestRepresentationFactory,
+ DerivedFromFrameworkInstanceRequestRepresentation.Factory
+ derivedFromFrameworkInstanceRequestRepresentationFactory,
+ ImmediateFutureRequestRepresentation.Factory immediateFutureRequestRepresentationFactory,
+ ProducerNodeInstanceRequestRepresentation.Factory
+ producerNodeInstanceRequestRepresentationFactory,
+ ProviderInstanceRequestRepresentation.Factory providerInstanceRequestRepresentationFactory,
+ ProducerFromProviderCreationExpression.Factory
+ producerFromProviderCreationExpressionFactory) {
+ this.binding = binding;
+ this.derivedFromFrameworkInstanceRequestRepresentationFactory =
+ derivedFromFrameworkInstanceRequestRepresentationFactory;
+ this.immediateFutureRequestRepresentationFactory = immediateFutureRequestRepresentationFactory;
+ this.providerRequestRepresentation =
+ binding.kind().equals(DELEGATE) && !needsCaching(binding, graph)
+ ? delegateRequestRepresentationFactory.create(binding, RequestKind.PROVIDER)
+ : providerInstanceRequestRepresentationFactory.create(binding, providerField);
+ this.producerFromProviderRepresentation =
+ producerNodeInstanceRequestRepresentationFactory.create(
+ binding,
+ new FrameworkFieldInitializer(
+ componentImplementation,
+ binding,
+ producerFromProviderCreationExpressionFactory.create(
+ providerRequestRepresentation,
+ componentImplementation.shardImplementation(binding).name())));
+ }
+
+ public RequestRepresentation getRequestRepresentation(BindingRequest request) {
+ return reentrantComputeIfAbsent(
+ requestRepresentations, request, this::getRequestRepresentationUncached);
+ }
+
+ private RequestRepresentation getRequestRepresentationUncached(BindingRequest request) {
+ switch (request.requestKind()) {
+ case INSTANCE:
+ case LAZY:
+ case PRODUCED:
+ case PROVIDER_OF_LAZY:
+ return derivedFromFrameworkInstanceRequestRepresentationFactory.create(
+ binding, providerRequestRepresentation, request.requestKind(), FrameworkType.PROVIDER);
+ case PROVIDER:
+ return providerRequestRepresentation;
+ case PRODUCER:
+ return producerFromProviderRepresentation;
+
+ case FUTURE:
+ return immediateFutureRequestRepresentationFactory.create(
+ getRequestRepresentation(bindingRequest(binding.key(), RequestKind.INSTANCE)),
+ binding.key().type().java());
+
+ default:
+ throw new AssertionError(
+ String.format("Invalid binding request kind: %s", request.requestKind()));
+ }
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ FrameworkInstanceBindingRepresentation create(
+ ProvisionBinding binding, FrameworkInstanceSupplier providerField);
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/FrameworkInstanceKind.java b/java/dagger/internal/codegen/writing/FrameworkInstanceKind.java
new file mode 100644
index 000000000..8bceddc11
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/FrameworkInstanceKind.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static dagger.spi.model.BindingKind.DELEGATE;
+
+import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.writing.ComponentImplementation.CompilerMode;
+import dagger.spi.model.BindingKind;
+
+/** Generation mode for satisfying framework request to Provision Binding. */
+enum FrameworkInstanceKind {
+ SWITCHING_PROVIDER,
+ EXPERIMENTAL_SWITCHING_PROVIDER,
+ STATIC_FACTORY,
+ PROVIDER_FIELD;
+
+ public static FrameworkInstanceKind from(ContributionBinding binding, CompilerMode compilerMode) {
+ if (usesSwitchingProvider(binding, compilerMode)) {
+ if (compilerMode.isExperimentalMergedMode()) {
+ return EXPERIMENTAL_SWITCHING_PROVIDER;
+ } else if (compilerMode.isFastInit()) {
+ return SWITCHING_PROVIDER;
+ } else {
+ throw new IllegalStateException(
+ "Compiler mode " + compilerMode + " cannot use Switching Provider.");
+ }
+ } else if (usesStaticFactoryCreation(binding, compilerMode)) {
+ return STATIC_FACTORY;
+ } else {
+ return PROVIDER_FIELD;
+ }
+ }
+
+ private static boolean usesSwitchingProvider(
+ ContributionBinding binding, CompilerMode compilerMode) {
+ if (!compilerMode.isFastInit() && !compilerMode.isExperimentalMergedMode()) {
+ return false;
+ }
+ // TODO(wanyingd): remove this check once we allow inaccessible types in merged mode.
+ if (compilerMode.isExperimentalMergedMode()
+ && binding.kind().equals(BindingKind.ASSISTED_FACTORY)) {
+ return false;
+ }
+ switch (binding.kind()) {
+ case ASSISTED_INJECTION:
+ case BOUND_INSTANCE:
+ case COMPONENT:
+ case COMPONENT_DEPENDENCY:
+ case DELEGATE:
+ case MEMBERS_INJECTOR: // TODO(b/199889259): Consider optimizing this for fastInit mode.
+ // These binding kinds avoid SwitchingProvider when the backing instance already exists,
+ // e.g. a component provider can use FactoryInstance.create(this).
+ return false;
+ case MULTIBOUND_SET:
+ case MULTIBOUND_MAP:
+ case OPTIONAL:
+ // These binding kinds avoid SwitchingProvider when their are no dependencies,
+ // e.g. a multibound set with no dependency can use a singleton, SetFactory.empty().
+ return !binding.dependencies().isEmpty();
+ case INJECTION:
+ case PROVISION:
+ case ASSISTED_FACTORY:
+ case COMPONENT_PROVISION:
+ case SUBCOMPONENT_CREATOR:
+ case PRODUCTION:
+ case COMPONENT_PRODUCTION:
+ case MEMBERS_INJECTION:
+ return true;
+ }
+ throw new AssertionError(String.format("No such binding kind: %s", binding.kind()));
+ }
+
+ private static boolean usesStaticFactoryCreation(
+ ContributionBinding binding, CompilerMode compilerMode) {
+ // If {@code binding} is an unscoped provision binding with no factory arguments, then
+ // we don't need a field to hold its factory. In that case, this method returns the static
+ // select that returns the factory.
+ // member
+ if (!binding.dependencies().isEmpty() || binding.scope().isPresent()) {
+ return false;
+ }
+ switch (binding.kind()) {
+ case MULTIBOUND_MAP:
+ case MULTIBOUND_SET:
+ return true;
+ case PROVISION:
+ return !compilerMode.isFastInit()
+ && !compilerMode.isExperimentalMergedMode()
+ && !binding.requiresModuleInstance();
+ case INJECTION:
+ return !compilerMode.isFastInit() && !compilerMode.isExperimentalMergedMode();
+ default:
+ return false;
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/FrameworkInstanceBindingExpression.java b/java/dagger/internal/codegen/writing/FrameworkInstanceRequestRepresentation.java
index 56a6ef3d6..e8120e832 100644
--- a/java/dagger/internal/codegen/writing/FrameworkInstanceBindingExpression.java
+++ b/java/dagger/internal/codegen/writing/FrameworkInstanceRequestRepresentation.java
@@ -20,8 +20,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.binding.FrameworkType;
import dagger.internal.codegen.javapoet.Expression;
@@ -31,13 +29,13 @@ import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
/** A binding expression that uses a {@link FrameworkType} field. */
-abstract class FrameworkInstanceBindingExpression extends BindingExpression {
+abstract class FrameworkInstanceRequestRepresentation extends RequestRepresentation {
private final ContributionBinding binding;
private final FrameworkInstanceSupplier frameworkInstanceSupplier;
private final DaggerTypes types;
private final DaggerElements elements;
- FrameworkInstanceBindingExpression(
+ FrameworkInstanceRequestRepresentation(
ContributionBinding binding,
FrameworkInstanceSupplier frameworkInstanceSupplier,
DaggerTypes types,
@@ -49,10 +47,8 @@ abstract class FrameworkInstanceBindingExpression extends BindingExpression {
}
/**
- * The expression for the framework instance for this binding. The field will be {@link
- * ComponentImplementation#addInitialization(CodeBlock) initialized} and {@link
- * ComponentImplementation#addField(ComponentImplementation.FieldSpecKind, FieldSpec) added} to
- * the component the first time this method is invoked.
+ * The expression for the framework instance for this binding. The field will be initialized and
+ * added to the component the first time this method is invoked.
*/
@Override
Expression getDependencyExpression(ClassName requestingClass) {
@@ -60,7 +56,7 @@ abstract class FrameworkInstanceBindingExpression extends BindingExpression {
TypeMirror expressionType =
isTypeAccessibleFrom(binding.contributedType(), requestingClass.packageName())
|| isInlinedFactoryCreation(memberSelect)
- ? types.wrapType(binding.contributedType(), frameworkType().frameworkClass())
+ ? types.wrapType(binding.contributedType(), frameworkType().frameworkClassName())
: rawFrameworkType();
return Expression.create(expressionType, memberSelect.getExpressionFor(requestingClass));
}
@@ -84,6 +80,6 @@ abstract class FrameworkInstanceBindingExpression extends BindingExpression {
}
private DeclaredType rawFrameworkType() {
- return types.getDeclaredType(elements.getTypeElement(frameworkType().frameworkClass()));
+ return types.getDeclaredType(elements.getTypeElement(frameworkType().frameworkClassName()));
}
}
diff --git a/java/dagger/internal/codegen/writing/GwtCompatibility.java b/java/dagger/internal/codegen/writing/GwtCompatibility.java
index 2df6a998a..1daa92fbc 100644
--- a/java/dagger/internal/codegen/writing/GwtCompatibility.java
+++ b/java/dagger/internal/codegen/writing/GwtCompatibility.java
@@ -16,6 +16,7 @@
package dagger.internal.codegen.writing;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.base.Preconditions.checkArgument;
import com.squareup.javapoet.AnnotationSpec;
@@ -33,7 +34,7 @@ final class GwtCompatibility {
*/
static Optional<AnnotationSpec> gwtIncompatibleAnnotation(Binding binding) {
checkArgument(binding.bindingElement().isPresent());
- Element element = binding.bindingElement().get();
+ Element element = toJavac(binding.bindingElement().get());
while (element != null) {
Optional<AnnotationSpec> gwtIncompatible =
element
diff --git a/java/dagger/internal/codegen/writing/HjarSourceFileGenerator.java b/java/dagger/internal/codegen/writing/HjarSourceFileGenerator.java
index d4dbde794..4bafb5aff 100644
--- a/java/dagger/internal/codegen/writing/HjarSourceFileGenerator.java
+++ b/java/dagger/internal/codegen/writing/HjarSourceFileGenerator.java
@@ -22,13 +22,13 @@ import static com.squareup.javapoet.TypeSpec.classBuilder;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static javax.lang.model.element.Modifier.PRIVATE;
+import androidx.room.compiler.processing.XElement;
import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import dagger.internal.codegen.base.SourceFileGenerator;
-import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
/**
@@ -48,7 +48,7 @@ public final class HjarSourceFileGenerator<T> extends SourceFileGenerator<T> {
}
@Override
- public Element originatingElement(T input) {
+ public XElement originatingElement(T input) {
return delegate.originatingElement(input);
}
diff --git a/java/dagger/internal/codegen/writing/ImmediateFutureBindingExpression.java b/java/dagger/internal/codegen/writing/ImmediateFutureRequestRepresentation.java
index dcd02faef..158c0959d 100644
--- a/java/dagger/internal/codegen/writing/ImmediateFutureBindingExpression.java
+++ b/java/dagger/internal/codegen/writing/ImmediateFutureRequestRepresentation.java
@@ -17,31 +17,33 @@
package dagger.internal.codegen.writing;
import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
-import dagger.model.RequestKind;
import javax.lang.model.SourceVersion;
+import javax.lang.model.type.TypeMirror;
-final class ImmediateFutureBindingExpression extends BindingExpression {
- private final Key key;
- private final ComponentBindingExpressions componentBindingExpressions;
+final class ImmediateFutureRequestRepresentation extends RequestRepresentation {
+ private final RequestRepresentation instanceRequestRepresentation;
+ private final TypeMirror type;
private final DaggerTypes types;
private final SourceVersion sourceVersion;
- ImmediateFutureBindingExpression(
- Key key,
- ComponentBindingExpressions componentBindingExpressions,
+ @AssistedInject
+ ImmediateFutureRequestRepresentation(
+ @Assisted RequestRepresentation instanceRequestRepresentation,
+ @Assisted TypeMirror type,
DaggerTypes types,
SourceVersion sourceVersion) {
- this.key = key;
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ this.instanceRequestRepresentation = instanceRequestRepresentation;
+ this.type = type;
this.types = checkNotNull(types);
this.sourceVersion = checkNotNull(sourceVersion);
}
@@ -49,25 +51,29 @@ final class ImmediateFutureBindingExpression extends BindingExpression {
@Override
Expression getDependencyExpression(ClassName requestingClass) {
return Expression.create(
- types.wrapType(key.type(), ListenableFuture.class),
+ types.wrapType(type, TypeNames.LISTENABLE_FUTURE),
CodeBlock.of("$T.immediateFuture($L)", Futures.class, instanceExpression(requestingClass)));
}
private CodeBlock instanceExpression(ClassName requestingClass) {
- Expression expression =
- componentBindingExpressions.getDependencyExpression(
- bindingRequest(key, RequestKind.INSTANCE), requestingClass);
+ Expression expression = instanceRequestRepresentation.getDependencyExpression(requestingClass);
if (sourceVersion.compareTo(SourceVersion.RELEASE_7) <= 0) {
// Java 7 type inference is not as strong as in Java 8, and therefore some generated code must
// cast.
//
// For example, javac7 cannot detect that Futures.immediateFuture(ImmutableSet.of("T"))
// can safely be assigned to ListenableFuture<Set<T>>.
- if (!types.isSameType(expression.type(), key.type())) {
+ if (!types.isSameType(expression.type(), type)) {
return CodeBlock.of(
- "($T) $L", types.accessibleType(key.type(), requestingClass), expression.codeBlock());
+ "($T) $L", types.accessibleType(type, requestingClass), expression.codeBlock());
}
}
return expression.codeBlock();
}
+
+ @AssistedFactory
+ static interface Factory {
+ ImmediateFutureRequestRepresentation create(
+ RequestRepresentation instanceRequestRepresentation, TypeMirror type);
+ }
}
diff --git a/java/dagger/internal/codegen/writing/InaccessibleMapKeyProxyGenerator.java b/java/dagger/internal/codegen/writing/InaccessibleMapKeyProxyGenerator.java
index 889f8985c..f48fd3647 100644
--- a/java/dagger/internal/codegen/writing/InaccessibleMapKeyProxyGenerator.java
+++ b/java/dagger/internal/codegen/writing/InaccessibleMapKeyProxyGenerator.java
@@ -22,17 +22,17 @@ import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XProcessingEnv;
import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.TypeSpec;
import dagger.internal.codegen.base.SourceFileGenerator;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.binding.MapKeys;
import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import javax.annotation.processing.Filer;
import javax.inject.Inject;
import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
/**
* Generates a class that exposes a non-{@code public} {@link
@@ -40,26 +40,27 @@ import javax.lang.model.element.Element;
*/
public final class InaccessibleMapKeyProxyGenerator
extends SourceFileGenerator<ContributionBinding> {
- private final DaggerTypes types;
- private final DaggerElements elements;
+ private final XProcessingEnv processingEnv;
@Inject
InaccessibleMapKeyProxyGenerator(
- Filer filer, DaggerTypes types, DaggerElements elements, SourceVersion sourceVersion) {
+ XProcessingEnv processingEnv,
+ XFiler filer,
+ DaggerElements elements,
+ SourceVersion sourceVersion) {
super(filer, elements, sourceVersion);
- this.types = types;
- this.elements = elements;
+ this.processingEnv = processingEnv;
}
@Override
- public Element originatingElement(ContributionBinding binding) {
+ public XElement originatingElement(ContributionBinding binding) {
// a map key is only ever present on bindings that have a binding element
return binding.bindingElement().get();
}
@Override
public ImmutableList<TypeSpec.Builder> topLevelTypes(ContributionBinding binding) {
- return MapKeys.mapKeyFactoryMethod(binding, types, elements)
+ return MapKeys.mapKeyFactoryMethod(binding, processingEnv)
.map(
method ->
classBuilder(MapKeys.mapKeyProxyClassName(binding))
diff --git a/java/dagger/internal/codegen/writing/InjectionMethods.java b/java/dagger/internal/codegen/writing/InjectionMethods.java
index 7cebc10db..97d085f50 100644
--- a/java/dagger/internal/codegen/writing/InjectionMethods.java
+++ b/java/dagger/internal/codegen/writing/InjectionMethods.java
@@ -16,6 +16,7 @@
package dagger.internal.codegen.writing;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.auto.common.MoreElements.asExecutable;
import static com.google.auto.common.MoreElements.asType;
import static com.google.auto.common.MoreElements.asVariable;
@@ -23,7 +24,7 @@ import static com.google.common.base.CaseFormat.LOWER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_CAMEL;
import static com.google.common.base.Preconditions.checkArgument;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static dagger.internal.codegen.base.RequestKinds.requestTypeName;
+import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedParameter;
import static dagger.internal.codegen.binding.ConfigurationAnnotations.getNullableType;
import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
import static dagger.internal.codegen.binding.SourceFiles.memberInjectedFieldSignatureForVariable;
@@ -38,11 +39,15 @@ import static dagger.internal.codegen.langmodel.Accessibility.isElementAccessibl
import static dagger.internal.codegen.langmodel.Accessibility.isRawTypeAccessible;
import static dagger.internal.codegen.langmodel.Accessibility.isRawTypePubliclyAccessible;
import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+import static dagger.internal.codegen.xprocessing.XElements.asExecutable;
+import static dagger.internal.codegen.xprocessing.XElements.asMethodParameter;
import static java.util.stream.Collectors.toList;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
import static javax.lang.model.type.TypeKind.VOID;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XExecutableParameterElement;
import com.google.auto.common.MoreElements;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -56,7 +61,6 @@ import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeVariableName;
import dagger.internal.Preconditions;
import dagger.internal.codegen.base.UniqueNameSet;
-import dagger.internal.codegen.binding.AssistedInjectionAnnotations;
import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.compileroption.CompilerOptions;
@@ -65,8 +69,8 @@ import dagger.internal.codegen.javapoet.CodeBlocks;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import dagger.model.RequestKind;
+import dagger.spi.model.DaggerAnnotation;
+import dagger.spi.model.DependencyRequest;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
@@ -76,7 +80,6 @@ import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Parameterizable;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
/** Convenience methods for creating and invoking {@link InjectionMethod}s. */
@@ -119,7 +122,7 @@ final class InjectionMethods {
ProvisionBinding binding,
CompilerOptions compilerOptions,
KotlinMetadataUtil metadataUtil) {
- ExecutableElement element = asExecutable(binding.bindingElement().get());
+ ExecutableElement element = asExecutable(toJavac(binding.bindingElement().get()));
switch (element.getKind()) {
case CONSTRUCTOR:
return constructorProxy(element);
@@ -142,13 +145,15 @@ final class InjectionMethods {
static CodeBlock invoke(
ProvisionBinding binding,
Function<DependencyRequest, CodeBlock> dependencyUsage,
+ Function<VariableElement, String> uniqueAssistedParameterName,
ClassName requestingClass,
Optional<CodeBlock> moduleReference,
CompilerOptions compilerOptions,
KotlinMetadataUtil metadataUtil) {
ImmutableList.Builder<CodeBlock> arguments = ImmutableList.builder();
moduleReference.ifPresent(arguments::add);
- invokeArguments(binding, dependencyUsage, requestingClass).forEach(arguments::add);
+ invokeArguments(binding, dependencyUsage, uniqueAssistedParameterName)
+ .forEach(arguments::add);
ClassName enclosingClass = generatedClassNameForBinding(binding);
MethodSpec methodSpec = create(binding, compilerOptions, metadataUtil);
@@ -158,23 +163,22 @@ final class InjectionMethods {
static ImmutableList<CodeBlock> invokeArguments(
ProvisionBinding binding,
Function<DependencyRequest, CodeBlock> dependencyUsage,
- ClassName requestingClass) {
- ImmutableMap<VariableElement, DependencyRequest> dependencyRequestMap =
+ Function<VariableElement, String> uniqueAssistedParameterName) {
+ ImmutableMap<XExecutableParameterElement, DependencyRequest> dependencyRequestMap =
binding.provisionDependencies().stream()
.collect(
toImmutableMap(
- request -> MoreElements.asVariable(request.requestElement().get()),
+ request -> asMethodParameter(request.requestElement().get().xprocessing()),
request -> request));
ImmutableList.Builder<CodeBlock> arguments = ImmutableList.builder();
- for (VariableElement parameter :
- asExecutable(binding.bindingElement().get()).getParameters()) {
- if (AssistedInjectionAnnotations.isAssistedParameter(parameter)) {
- arguments.add(CodeBlock.of("$L", parameter.getSimpleName()));
+ XExecutableElement method = asExecutable(binding.bindingElement().get());
+ for (XExecutableParameterElement parameter : method.getParameters()) {
+ if (isAssistedParameter(parameter)) {
+ arguments.add(CodeBlock.of("$L", uniqueAssistedParameterName.apply(toJavac(parameter))));
} else if (dependencyRequestMap.containsKey(parameter)) {
DependencyRequest request = dependencyRequestMap.get(parameter);
- arguments.add(
- injectionMethodArgument(request, dependencyUsage.apply(request), requestingClass));
+ arguments.add(dependencyUsage.apply(request));
} else {
throw new AssertionError("Unexpected parameter: " + parameter);
}
@@ -205,7 +209,7 @@ final class InjectionMethods {
*/
static boolean requiresInjectionMethod(
ProvisionBinding binding, CompilerOptions compilerOptions, ClassName requestingClass) {
- ExecutableElement method = MoreElements.asExecutable(binding.bindingElement().get());
+ ExecutableElement method = asExecutable(toJavac(binding.bindingElement().get()));
return !binding.injectionSites().isEmpty()
|| binding.shouldCheckForNull(compilerOptions)
|| !isElementAccessibleFrom(method, requestingClass.packageName())
@@ -276,7 +280,8 @@ final class InjectionMethods {
// methods for fields have a single dependency request
.collect(DaggerCollectors.onlyElement())
.key()
- .qualifier();
+ .qualifier()
+ .map(DaggerAnnotation::java);
return fieldProxy(asVariable(injectionSite.element()), methodName, qualifier);
}
throw new AssertionError(injectionSite);
@@ -371,44 +376,6 @@ final class InjectionMethods {
}
}
- private static CodeBlock injectionMethodArgument(
- DependencyRequest dependency, CodeBlock argument, ClassName generatedTypeName) {
- TypeMirror keyType = dependency.key().type();
- CodeBlock.Builder codeBlock = CodeBlock.builder();
- if (!isRawTypeAccessible(keyType, generatedTypeName.packageName())
- && isTypeAccessibleFrom(keyType, generatedTypeName.packageName())) {
- if (!dependency.kind().equals(RequestKind.INSTANCE)) {
- TypeName usageTypeName = accessibleType(dependency);
- codeBlock.add("($T) ($T)", usageTypeName, rawTypeName(usageTypeName));
- } else if (dependency.requestElement().get().asType().getKind().equals(TypeKind.TYPEVAR)) {
- codeBlock.add("($T)", keyType);
- }
- }
- return codeBlock.add(argument).build();
- }
-
- /**
- * Returns the parameter type for {@code dependency}. If the raw type is not accessible, returns
- * {@link Object}.
- */
- private static TypeName accessibleType(DependencyRequest dependency) {
- TypeName typeName = requestTypeName(dependency.kind(), accessibleType(dependency.key().type()));
- return dependency
- .requestElement()
- .map(element -> element.asType().getKind().isPrimitive())
- .orElse(false)
- ? typeName.unbox()
- : typeName;
- }
-
- /**
- * Returns the accessible type for {@code type}. If the raw type is not accessible, returns {@link
- * Object}.
- */
- private static TypeName accessibleType(TypeMirror type) {
- return isRawTypePubliclyAccessible(type) ? TypeName.get(type) : TypeName.OBJECT;
- }
-
private enum InstanceCastPolicy {
CAST_IF_NOT_PUBLIC, IGNORE;
diff --git a/java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java b/java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java
index b5135b057..b9bc70b18 100644
--- a/java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java
@@ -18,11 +18,16 @@ package dagger.internal.codegen.writing;
import static com.google.common.base.Preconditions.checkNotNull;
import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
-import static dagger.model.BindingKind.INJECTION;
+import static dagger.spi.model.BindingKind.INJECTION;
import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.javapoet.CodeBlocks;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
import javax.inject.Provider;
@@ -35,12 +40,17 @@ final class InjectionOrProvisionProviderCreationExpression
implements FrameworkInstanceCreationExpression {
private final ContributionBinding binding;
- private final ComponentBindingExpressions componentBindingExpressions;
+ private final ShardImplementation shardImplementation;
+ private final ComponentRequestRepresentations componentRequestRepresentations;
+ @AssistedInject
InjectionOrProvisionProviderCreationExpression(
- ContributionBinding binding, ComponentBindingExpressions componentBindingExpressions) {
+ @Assisted ContributionBinding binding,
+ ComponentImplementation componentImplementation,
+ ComponentRequestRepresentations componentRequestRepresentations) {
this.binding = checkNotNull(binding);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ this.shardImplementation = componentImplementation.shardImplementation(binding);
+ this.componentRequestRepresentations = componentRequestRepresentations;
}
@Override
@@ -49,16 +59,22 @@ final class InjectionOrProvisionProviderCreationExpression
CodeBlock.of(
"$T.create($L)",
generatedClassNameForBinding(binding),
- componentBindingExpressions.getCreateMethodArgumentsCodeBlock(binding));
+ componentRequestRepresentations.getCreateMethodArgumentsCodeBlock(
+ binding, shardImplementation.name()));
// When scoping a parameterized factory for an @Inject class, Java 7 cannot always infer the
// type properly, so cast to a raw framework type before scoping.
if (binding.kind().equals(INJECTION)
&& binding.unresolved().isPresent()
&& binding.scope().isPresent()) {
- return CodeBlocks.cast(createFactory, Provider.class);
+ return CodeBlocks.cast(createFactory, TypeNames.PROVIDER);
} else {
return createFactory;
}
}
+
+ @AssistedFactory
+ static interface Factory {
+ InjectionOrProvisionProviderCreationExpression create(ContributionBinding binding);
+ }
}
diff --git a/java/dagger/internal/codegen/writing/InnerSwitchingProviders.java b/java/dagger/internal/codegen/writing/InnerSwitchingProviders.java
deleted file mode 100644
index c2f9893b7..000000000
--- a/java/dagger/internal/codegen/writing/InnerSwitchingProviders.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2018 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-import static dagger.model.RequestKind.INSTANCE;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
-import javax.inject.Provider;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * Generates {@linkplain BindingExpression binding expressions} for a binding that is represented by
- * an inner {@code SwitchingProvider} class.
- */
-final class InnerSwitchingProviders extends SwitchingProviders {
- private final ComponentBindingExpressions componentBindingExpressions;
- private final DaggerTypes types;
-
- InnerSwitchingProviders(
- ComponentImplementation componentImplementation,
- ComponentBindingExpressions componentBindingExpressions,
- DaggerTypes types) {
- super(componentImplementation, types);
- this.componentBindingExpressions = componentBindingExpressions;
- this.types = types;
- }
-
- /**
- * Returns the binding expression for a binding that satisfies a {@link Provider} requests with a
- * inner {@code SwitchingProvider} class.
- */
- BindingExpression newBindingExpression(ContributionBinding binding) {
- return new BindingExpression() {
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- return getProviderExpression(new SwitchCase(binding, requestingClass));
- }
- };
- }
-
- @Override
- protected TypeSpec createSwitchingProviderType(TypeSpec.Builder builder) {
- return builder
- .addModifiers(PRIVATE, FINAL)
- .addField(TypeName.INT, "id", PRIVATE, FINAL)
- .addMethod(
- constructorBuilder()
- .addParameter(TypeName.INT, "id")
- .addStatement("this.id = id")
- .build())
- .build();
- }
-
- private final class SwitchCase implements SwitchingProviders.SwitchCase {
- private final ContributionBinding binding;
- private final ClassName requestingClass;
-
- SwitchCase(ContributionBinding binding, ClassName requestingClass) {
- this.binding = binding;
- this.requestingClass = requestingClass;
- }
-
- @Override
- public Key key() {
- return binding.key();
- }
-
- @Override
- public Expression getProviderExpression(ClassName switchingProviderClass, int switchId) {
- TypeMirror instanceType = types.accessibleType(binding.contributedType(), requestingClass);
- return Expression.create(
- types.wrapType(instanceType, Provider.class),
- CodeBlock.of("new $T<>($L)", switchingProviderClass, switchId));
- }
-
- @Override
- public Expression getReturnExpression(ClassName switchingProviderClass) {
- return componentBindingExpressions.getDependencyExpression(
- bindingRequest(binding.key(), INSTANCE), switchingProviderClass);
- }
- }
-}
diff --git a/java/dagger/internal/codegen/writing/InstanceFactoryCreationExpression.java b/java/dagger/internal/codegen/writing/InstanceFactoryCreationExpression.java
index a7d6685be..807c64c58 100644
--- a/java/dagger/internal/codegen/writing/InstanceFactoryCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/InstanceFactoryCreationExpression.java
@@ -49,9 +49,4 @@ final class InstanceFactoryCreationExpression implements FrameworkInstanceCreati
nullable ? "createNullable" : "create",
instanceExpression.get());
}
-
- @Override
- public boolean useInnerSwitchingProvider() {
- return false;
- }
}
diff --git a/java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java b/java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java
index 104d48a1d..a326e0a05 100644
--- a/java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java
@@ -19,56 +19,57 @@ package dagger.internal.codegen.writing;
import static com.google.common.base.Preconditions.checkNotNull;
import static dagger.internal.codegen.binding.MapKeys.getMapKeyExpression;
import static dagger.internal.codegen.binding.SourceFiles.mapFactoryClassName;
+import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
-import com.google.common.collect.ImmutableSet;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.model.DependencyRequest;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import javax.inject.Provider;
-import javax.lang.model.type.TypeMirror;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.spi.model.DependencyRequest;
+import java.util.stream.Stream;
/** A factory creation expression for a multibound map. */
final class MapFactoryCreationExpression extends MultibindingFactoryCreationExpression {
+ private final XProcessingEnv processingEnv;
private final ComponentImplementation componentImplementation;
private final BindingGraph graph;
private final ContributionBinding binding;
- private final DaggerElements elements;
+ @AssistedInject
MapFactoryCreationExpression(
- ContributionBinding binding,
+ @Assisted ContributionBinding binding,
+ XProcessingEnv processingEnv,
ComponentImplementation componentImplementation,
- ComponentBindingExpressions componentBindingExpressions,
- BindingGraph graph,
- DaggerElements elements) {
- super(binding, componentImplementation, componentBindingExpressions);
+ ComponentRequestRepresentations componentRequestRepresentations,
+ BindingGraph graph) {
+ super(binding, componentImplementation, componentRequestRepresentations);
+ this.processingEnv = processingEnv;
this.binding = checkNotNull(binding);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.graph = checkNotNull(graph);
- this.elements = checkNotNull(elements);
+ this.componentImplementation = componentImplementation;
+ this.graph = graph;
}
@Override
public CodeBlock creationExpression() {
CodeBlock.Builder builder = CodeBlock.builder().add("$T.", mapFactoryClassName(binding));
if (!useRawType()) {
- MapType mapType = MapType.from(binding.key().type());
+ MapType mapType = MapType.from(binding.key());
// TODO(ronshapiro): either inline this into mapFactoryClassName, or add a
// mapType.unwrappedValueType() method that doesn't require a framework type
- TypeMirror valueType = mapType.valueType();
- for (Class<?> frameworkClass :
- ImmutableSet.of(Provider.class, Producer.class, Produced.class)) {
- if (mapType.valuesAreTypeOf(frameworkClass)) {
- valueType = mapType.unwrappedValueType(frameworkClass);
- break;
- }
- }
- builder.add("<$T, $T>", mapType.keyType(), valueType);
+ XType valueType =
+ Stream.of(TypeNames.PROVIDER, TypeNames.PRODUCER, TypeNames.PRODUCED)
+ .filter(mapType::valuesAreTypeOf)
+ .map(mapType::unwrappedValueType)
+ .collect(toOptional())
+ .orElseGet(mapType::valueType);
+ builder.add("<$T, $T>", mapType.keyType().getTypeName(), valueType.getTypeName());
}
builder.add("builder($L)", binding.dependencies().size());
@@ -77,11 +78,16 @@ final class MapFactoryCreationExpression extends MultibindingFactoryCreationExpr
ContributionBinding contributionBinding = graph.contributionBinding(dependency.key());
builder.add(
".put($L, $L)",
- getMapKeyExpression(contributionBinding, componentImplementation.name(), elements),
+ getMapKeyExpression(contributionBinding, componentImplementation.name(), processingEnv),
multibindingDependencyExpression(dependency));
}
builder.add(".build()");
return builder.build();
}
+
+ @AssistedFactory
+ static interface Factory {
+ MapFactoryCreationExpression create(ContributionBinding binding);
+ }
}
diff --git a/java/dagger/internal/codegen/writing/MapBindingExpression.java b/java/dagger/internal/codegen/writing/MapRequestRepresentation.java
index 255e85d9c..876c24832 100644
--- a/java/dagger/internal/codegen/writing/MapBindingExpression.java
+++ b/java/dagger/internal/codegen/writing/MapRequestRepresentation.java
@@ -22,53 +22,57 @@ import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import static dagger.internal.codegen.binding.MapKeys.getMapKeyExpression;
import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-import static dagger.model.BindingKind.MULTIBOUND_MAP;
-import static javax.lang.model.util.ElementFilter.methodsIn;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static dagger.spi.model.BindingKind.MULTIBOUND_MAP;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.MapBuilder;
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.DependencyRequest;
import java.util.Collections;
-import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
-/** A {@link BindingExpression} for multibound maps. */
-final class MapBindingExpression extends SimpleInvocationBindingExpression {
+/** A {@link RequestRepresentation} for multibound maps. */
+final class MapRequestRepresentation extends RequestRepresentation {
/** Maximum number of key-value pairs that can be passed to ImmutableMap.of(K, V, K, V, ...). */
private static final int MAX_IMMUTABLE_MAP_OF_KEY_VALUE_PAIRS = 5;
+ private final XProcessingEnv processingEnv;
private final ProvisionBinding binding;
private final ImmutableMap<DependencyRequest, ContributionBinding> dependencies;
- private final ComponentBindingExpressions componentBindingExpressions;
- private final DaggerTypes types;
- private final DaggerElements elements;
+ private final ComponentRequestRepresentations componentRequestRepresentations;
+ private final boolean isExperimentalMergedMode;
- MapBindingExpression(
- ProvisionBinding binding,
+ @AssistedInject
+ MapRequestRepresentation(
+ @Assisted ProvisionBinding binding,
+ XProcessingEnv processingEnv,
BindingGraph graph,
- ComponentBindingExpressions componentBindingExpressions,
- DaggerTypes types,
- DaggerElements elements) {
- super(binding);
+ ComponentImplementation componentImplementation,
+ ComponentRequestRepresentations componentRequestRepresentations) {
this.binding = binding;
+ this.processingEnv = processingEnv;
BindingKind bindingKind = this.binding.kind();
checkArgument(bindingKind.equals(MULTIBOUND_MAP), bindingKind);
- this.componentBindingExpressions = componentBindingExpressions;
- this.types = types;
- this.elements = elements;
+ this.componentRequestRepresentations = componentRequestRepresentations;
this.dependencies =
Maps.toMap(binding.dependencies(), dep -> graph.contributionBinding(dep.key()));
+ this.isExperimentalMergedMode =
+ componentImplementation.compilerMode().isExperimentalMergedMode();
}
@Override
@@ -116,30 +120,38 @@ final class MapBindingExpression extends SimpleInvocationBindingExpression {
instantiation.add(".put($L)", keyAndValueExpression(dependency, requestingClass));
}
return Expression.create(
- isImmutableMapAvailable ? immutableMapType() : binding.key().type(),
+ isImmutableMapAvailable ? immutableMapType() : binding.key().type().xprocessing(),
instantiation.add(".build()").build());
}
}
- private DeclaredType immutableMapType() {
+ private XType immutableMapType() {
MapType mapType = MapType.from(binding.key());
- return types.getDeclaredType(
- elements.getTypeElement(ImmutableMap.class), mapType.keyType(), mapType.valueType());
+ return processingEnv.getDeclaredType(
+ processingEnv.requireTypeElement(TypeNames.IMMUTABLE_MAP),
+ mapType.keyType(),
+ mapType.valueType());
}
private CodeBlock keyAndValueExpression(DependencyRequest dependency, ClassName requestingClass) {
return CodeBlock.of(
"$L, $L",
- getMapKeyExpression(dependencies.get(dependency), requestingClass, elements),
- componentBindingExpressions
- .getDependencyExpression(bindingRequest(dependency), requestingClass)
- .codeBlock());
+ getMapKeyExpression(dependencies.get(dependency), requestingClass, processingEnv),
+ isExperimentalMergedMode
+ ? componentRequestRepresentations
+ .getExperimentalSwitchingProviderDependencyRepresentation(
+ bindingRequest(dependency))
+ .getDependencyExpression(dependency.kind(), binding)
+ .codeBlock()
+ : componentRequestRepresentations
+ .getDependencyExpression(bindingRequest(dependency), requestingClass)
+ .codeBlock());
}
private Expression collectionsStaticFactoryInvocation(
ClassName requestingClass, CodeBlock methodInvocation) {
return Expression.create(
- binding.key().type(),
+ binding.key().type().java(),
CodeBlock.builder()
.add("$T.", Collections.class)
.add(maybeTypeParameters(requestingClass))
@@ -148,23 +160,26 @@ final class MapBindingExpression extends SimpleInvocationBindingExpression {
}
private CodeBlock maybeTypeParameters(ClassName requestingClass) {
- TypeMirror bindingKeyType = binding.key().type();
+ TypeMirror bindingKeyType = binding.key().type().java();
MapType mapType = MapType.from(binding.key());
return isTypeAccessibleFrom(bindingKeyType, requestingClass.packageName())
- ? CodeBlock.of("<$T, $T>", mapType.keyType(), mapType.valueType())
+ ? CodeBlock.of(
+ "<$T, $T>", mapType.keyType().getTypeName(), mapType.valueType().getTypeName())
: CodeBlock.of("");
}
private boolean isImmutableMapBuilderWithExpectedSizeAvailable() {
- if (isImmutableMapAvailable()) {
- return methodsIn(elements.getTypeElement(ImmutableMap.class).getEnclosedElements())
- .stream()
- .anyMatch(method -> method.getSimpleName().contentEquals("builderWithExpectedSize"));
- }
- return false;
+ return isImmutableMapAvailable()
+ && processingEnv.requireTypeElement(TypeNames.IMMUTABLE_MAP).getDeclaredMethods().stream()
+ .anyMatch(method -> getSimpleName(method).contentEquals("builderWithExpectedSize"));
}
private boolean isImmutableMapAvailable() {
- return elements.getTypeElement(ImmutableMap.class) != null;
+ return processingEnv.findTypeElement(TypeNames.IMMUTABLE_MAP) != null;
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ MapRequestRepresentation create(ProvisionBinding binding);
}
}
diff --git a/java/dagger/internal/codegen/writing/MemberSelect.java b/java/dagger/internal/codegen/writing/MemberSelect.java
index b04e21be0..d4e675018 100644
--- a/java/dagger/internal/codegen/writing/MemberSelect.java
+++ b/java/dagger/internal/codegen/writing/MemberSelect.java
@@ -17,32 +17,10 @@
package dagger.internal.codegen.writing;
import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.ContributionBinding.FactoryCreationStrategy.SINGLETON_INSTANCE;
-import static dagger.internal.codegen.binding.SourceFiles.bindingTypeElementTypeVariableNames;
-import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
-import static dagger.internal.codegen.binding.SourceFiles.setFactoryClassName;
-import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
-import static dagger.internal.codegen.javapoet.TypeNames.FACTORY;
-import static dagger.internal.codegen.javapoet.TypeNames.MAP_FACTORY;
-import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER;
-import static dagger.internal.codegen.javapoet.TypeNames.PRODUCERS;
-import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER;
-import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-import static javax.lang.model.type.TypeKind.DECLARED;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.TypeVariableName;
-import dagger.internal.codegen.base.SetType;
-import dagger.internal.codegen.binding.BindingType;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.javapoet.CodeBlocks;
-import java.util.List;
-import java.util.Optional;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
/**
* Represents a {@link com.sun.source.tree.MemberSelectTree} as a {@link CodeBlock}.
@@ -51,20 +29,22 @@ abstract class MemberSelect {
/**
* Returns a {@link MemberSelect} that accesses the field given by {@code fieldName} owned by
- * {@code owningClass}. In this context "local" refers to the fact that the field is owned by the
- * type (or an enclosing type) from which the code block will be used. The returned
- * {@link MemberSelect} will not be valid for accessing the field from a different class
- * (regardless of accessibility).
+ * {@code owningClass}. In this context "local" refers to the fact that the field is owned by the
+ * type (or an enclosing type) from which the code block will be used. The returned {@link
+ * MemberSelect} will not be valid for accessing the field from a different class (regardless of
+ * accessibility).
*/
- static MemberSelect localField(ClassName owningClass, String fieldName) {
- return new LocalField(owningClass, fieldName);
+ static MemberSelect localField(ShardImplementation owningShard, String fieldName) {
+ return new LocalField(owningShard, fieldName);
}
private static final class LocalField extends MemberSelect {
+ final ShardImplementation owningShard;
final String fieldName;
- LocalField(ClassName owningClass, String fieldName) {
- super(owningClass, false);
+ LocalField(ShardImplementation owningShard, String fieldName) {
+ super(owningShard.name(), false);
+ this.owningShard = owningShard;
this.fieldName = checkNotNull(fieldName);
}
@@ -72,165 +52,7 @@ abstract class MemberSelect {
CodeBlock getExpressionFor(ClassName usingClass) {
return owningClass().equals(usingClass)
? CodeBlock.of("$N", fieldName)
- : CodeBlock.of("$T.this.$N", owningClass(), fieldName);
- }
- }
-
- /**
- * Returns a {@link MemberSelect} that accesses the method given by {@code methodName} owned by
- * {@code owningClass}. In this context "local" refers to the fact that the method is owned by the
- * type (or an enclosing type) from which the code block will be used. The returned {@link
- * MemberSelect} will not be valid for accessing the method from a different class (regardless of
- * accessibility).
- */
- static MemberSelect localMethod(ClassName owningClass, String methodName) {
- return new LocalMethod(owningClass, methodName);
- }
-
- private static final class LocalMethod extends MemberSelect {
- final String methodName;
-
- LocalMethod(ClassName owningClass, String methodName) {
- super(owningClass, false);
- this.methodName = checkNotNull(methodName);
- }
-
- @Override
- CodeBlock getExpressionFor(ClassName usingClass) {
- return owningClass().equals(usingClass)
- ? CodeBlock.of("$N()", methodName)
- : CodeBlock.of("$T.this.$N()", owningClass(), methodName);
- }
- }
-
- /**
- * If {@code resolvedBindings} is an unscoped provision binding with no factory arguments or a
- * no-op members injection binding, then we don't need a field to hold its factory. In that case,
- * this method returns the static member select that returns the factory or no-op members
- * injector.
- */
- static Optional<MemberSelect> staticFactoryCreation(ContributionBinding contributionBinding) {
- if (contributionBinding.factoryCreationStrategy().equals(SINGLETON_INSTANCE)
- && !contributionBinding.scope().isPresent()) {
- switch (contributionBinding.kind()) {
- case MULTIBOUND_MAP:
- return Optional.of(emptyMapFactory(contributionBinding));
-
- case MULTIBOUND_SET:
- return Optional.of(emptySetFactory(contributionBinding));
-
- case INJECTION:
- case PROVISION:
- TypeMirror keyType = contributionBinding.key().type();
- if (keyType.getKind().equals(DECLARED)) {
- ImmutableList<TypeVariableName> typeVariables =
- bindingTypeElementTypeVariableNames(contributionBinding);
- if (!typeVariables.isEmpty()) {
- List<? extends TypeMirror> typeArguments =
- ((DeclaredType) keyType).getTypeArguments();
- return Optional.of(
- MemberSelect.parameterizedFactoryCreateMethod(
- generatedClassNameForBinding(contributionBinding), typeArguments));
- }
- }
- // fall through
-
- default:
- return Optional.of(
- new StaticMethod(
- generatedClassNameForBinding(contributionBinding), CodeBlock.of("create()")));
- }
- }
-
- return Optional.empty();
- }
-
- /**
- * Returns a {@link MemberSelect} for the instance of a {@code create()} method on a factory. This
- * only applies for factories that do not have any dependencies.
- */
- private static MemberSelect parameterizedFactoryCreateMethod(
- ClassName owningClass, List<? extends TypeMirror> parameters) {
- return new ParameterizedStaticMethod(
- owningClass, ImmutableList.copyOf(parameters), CodeBlock.of("create()"), FACTORY);
- }
-
- private static final class StaticMethod extends MemberSelect {
- final CodeBlock methodCodeBlock;
-
- StaticMethod(ClassName owningClass, CodeBlock methodCodeBlock) {
- super(owningClass, true);
- this.methodCodeBlock = checkNotNull(methodCodeBlock);
- }
-
- @Override
- CodeBlock getExpressionFor(ClassName usingClass) {
- return owningClass().equals(usingClass)
- ? methodCodeBlock
- : CodeBlock.of("$T.$L", owningClass(), methodCodeBlock);
- }
- }
-
- /** A {@link MemberSelect} for a factory of an empty map. */
- private static MemberSelect emptyMapFactory(ContributionBinding contributionBinding) {
- BindingType bindingType = contributionBinding.bindingType();
- ImmutableList<TypeMirror> typeParameters =
- ImmutableList.copyOf(
- MoreTypes.asDeclared(contributionBinding.key().type()).getTypeArguments());
- if (bindingType.equals(BindingType.PRODUCTION)) {
- return new ParameterizedStaticMethod(
- PRODUCERS, typeParameters, CodeBlock.of("emptyMapProducer()"), PRODUCER);
- } else {
- return new ParameterizedStaticMethod(
- MAP_FACTORY, typeParameters, CodeBlock.of("emptyMapProvider()"), PROVIDER);
- }
- }
-
- /**
- * A static member select for an empty set factory. Calls {@link
- * dagger.internal.SetFactory#empty()}, {@link dagger.producers.internal.SetProducer#empty()}, or
- * {@link dagger.producers.internal.SetOfProducedProducer#empty()}, depending on the set bindings.
- */
- private static MemberSelect emptySetFactory(ContributionBinding binding) {
- return new ParameterizedStaticMethod(
- setFactoryClassName(binding),
- ImmutableList.of(SetType.from(binding.key()).elementType()),
- CodeBlock.of("empty()"),
- FACTORY);
- }
-
- private static final class ParameterizedStaticMethod extends MemberSelect {
- final ImmutableList<TypeMirror> typeParameters;
- final CodeBlock methodCodeBlock;
- final ClassName rawReturnType;
-
- ParameterizedStaticMethod(
- ClassName owningClass,
- ImmutableList<TypeMirror> typeParameters,
- CodeBlock methodCodeBlock,
- ClassName rawReturnType) {
- super(owningClass, true);
- this.typeParameters = typeParameters;
- this.methodCodeBlock = methodCodeBlock;
- this.rawReturnType = rawReturnType;
- }
-
- @Override
- CodeBlock getExpressionFor(ClassName usingClass) {
- boolean accessible = true;
- for (TypeMirror typeParameter : typeParameters) {
- accessible &= isTypeAccessibleFrom(typeParameter, usingClass.packageName());
- }
-
- if (accessible) {
- return CodeBlock.of(
- "$T.<$L>$L",
- owningClass(),
- typeParameters.stream().map(CodeBlocks::type).collect(toParametersCodeBlock()),
- methodCodeBlock);
- } else {
- return CodeBlock.of("(($T) $T.$L)", rawReturnType, owningClass(), methodCodeBlock);
- }
+ : CodeBlock.of("$L.$N", owningShard.shardFieldReference(), fieldName);
}
}
diff --git a/java/dagger/internal/codegen/writing/MembersInjectionBindingRepresentation.java b/java/dagger/internal/codegen/writing/MembersInjectionBindingRepresentation.java
new file mode 100644
index 000000000..cfad7458c
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/MembersInjectionBindingRepresentation.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.binding.BindingRequest;
+import dagger.internal.codegen.binding.MembersInjectionBinding;
+import dagger.spi.model.RequestKind;
+
+/**
+ * A binding representation that wraps code generation methods that satisfy all kinds of request for
+ * that binding.
+ */
+final class MembersInjectionBindingRepresentation implements BindingRepresentation {
+ private final MembersInjectionBinding binding;
+ private final MembersInjectionRequestRepresentation membersInjectionRequestRepresentation;
+
+ @AssistedInject
+ MembersInjectionBindingRepresentation(
+ @Assisted MembersInjectionBinding binding,
+ MembersInjectionRequestRepresentation.Factory membersInjectionRequestRepresentationFactory) {
+ this.binding = binding;
+ this.membersInjectionRequestRepresentation =
+ membersInjectionRequestRepresentationFactory.create(binding);
+ }
+
+ @Override
+ public RequestRepresentation getRequestRepresentation(BindingRequest request) {
+ checkArgument(request.isRequestKind(RequestKind.MEMBERS_INJECTION), binding);
+ return membersInjectionRequestRepresentation;
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ MembersInjectionBindingRepresentation create(MembersInjectionBinding binding);
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/MembersInjectionMethods.java b/java/dagger/internal/codegen/writing/MembersInjectionMethods.java
index 3d602b3d6..ce332f5d1 100644
--- a/java/dagger/internal/codegen/writing/MembersInjectionMethods.java
+++ b/java/dagger/internal/codegen/writing/MembersInjectionMethods.java
@@ -17,11 +17,15 @@
package dagger.internal.codegen.writing;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
+import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.MEMBERS_INJECTION_METHOD;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.STATIC;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
@@ -34,30 +38,35 @@ import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.MembersInjectionBinding;
import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.javapoet.Expression;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.internal.codegen.writing.InjectionMethods.InjectionSiteMethod;
-import dagger.model.Key;
+import dagger.spi.model.Key;
import java.util.LinkedHashMap;
import java.util.Map;
-import javax.lang.model.element.Name;
+import javax.inject.Inject;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
/** Manages the member injection methods for a component. */
+@PerComponentImplementation
final class MembersInjectionMethods {
- private final Map<Key, MethodSpec> membersInjectionMethods = new LinkedHashMap<>();
+ private final Map<Key, Expression> injectMethodExpressions = new LinkedHashMap<>();
+ private final Map<Key, Expression> experimentalInjectMethodExpressions = new LinkedHashMap<>();
private final ComponentImplementation componentImplementation;
- private final ComponentBindingExpressions bindingExpressions;
+ private final ComponentRequestRepresentations bindingExpressions;
private final BindingGraph graph;
private final DaggerElements elements;
private final DaggerTypes types;
private final KotlinMetadataUtil metadataUtil;
+ @Inject
MembersInjectionMethods(
ComponentImplementation componentImplementation,
- ComponentBindingExpressions bindingExpressions,
+ ComponentRequestRepresentations bindingExpressions,
BindingGraph graph,
DaggerElements elements,
DaggerTypes types,
@@ -71,34 +80,77 @@ final class MembersInjectionMethods {
}
/**
- * Returns the members injection {@link MethodSpec} for the given {@link Key}, creating it if
+ * Returns the members injection {@link Expression} for the given {@link Key}, creating it if
* necessary.
*/
- MethodSpec getOrCreate(Key key) {
- return reentrantComputeIfAbsent(membersInjectionMethods, key, this::membersInjectionMethod);
+ Expression getInjectExpression(Key key, CodeBlock instance, ClassName requestingClass) {
+ Binding binding =
+ graph.localMembersInjectionBinding(key).isPresent()
+ ? graph.localMembersInjectionBinding(key).get()
+ : graph.localContributionBinding(key).get();
+ Expression expression =
+ reentrantComputeIfAbsent(
+ injectMethodExpressions, key, k -> injectMethodExpression(binding, false));
+ ShardImplementation shardImplementation = componentImplementation.shardImplementation(binding);
+ return Expression.create(
+ expression.type(),
+ shardImplementation.name().equals(requestingClass)
+ ? CodeBlock.of("$L($L)", expression.codeBlock(), instance)
+ : CodeBlock.of(
+ "$L.$L($L)",
+ shardImplementation.shardFieldReference(),
+ expression.codeBlock(),
+ instance));
}
- private MethodSpec membersInjectionMethod(Key key) {
- Binding binding =
- graph.membersInjectionBinding(key).isPresent()
- ? graph.membersInjectionBinding(key).get()
- : graph.contributionBinding(key);
- TypeMirror keyType = binding.key().type();
+ /**
+ * Returns the members injection {@link Expression} for the given {@link Key}, creating it if
+ * necessary.
+ */
+ Expression getInjectExpressionExperimental(
+ ProvisionBinding provisionBinding, CodeBlock instance, ClassName requestingClass) {
+ checkState(
+ componentImplementation.compilerMode().isExperimentalMergedMode(),
+ "Compiler mode should be experimentalMergedMode!");
+ Expression expression =
+ reentrantComputeIfAbsent(
+ experimentalInjectMethodExpressions,
+ provisionBinding.key(),
+ k -> injectMethodExpression(provisionBinding, true));
+ return Expression.create(
+ expression.type(), CodeBlock.of("$L($L, dependencies)", expression.codeBlock(), instance));
+ }
+
+ private Expression injectMethodExpression(Binding binding, boolean useStaticInjectionMethod) {
+ // TODO(wanyingd): move Switching Providers and injection methods to Shard classes to avoid
+ // exceeding component class constant pool limit.
+ // Add to Component Shard so that is can be accessible from Switching Providers.
+ ShardImplementation shardImplementation =
+ useStaticInjectionMethod
+ ? componentImplementation.getComponentShard()
+ : componentImplementation.shardImplementation(binding);
+ TypeMirror keyType = binding.key().type().java();
TypeMirror membersInjectedType =
- isTypeAccessibleFrom(keyType, componentImplementation.name().packageName())
+ isTypeAccessibleFrom(keyType, shardImplementation.name().packageName())
? keyType
- : elements.getTypeElement(Object.class).asType();
+ : elements.getTypeElement(TypeName.OBJECT).asType();
TypeName membersInjectedTypeName = TypeName.get(membersInjectedType);
- Name bindingTypeName = binding.bindingTypeElement().get().getSimpleName();
+ String bindingTypeName = getSimpleName(binding.bindingTypeElement().get());
// TODO(ronshapiro): include type parameters in this name e.g. injectFooOfT, and outer class
// simple names Foo.Builder -> injectFooBuilder
- String methodName = componentImplementation.getUniqueMethodName("inject" + bindingTypeName);
+ String methodName = shardImplementation.getUniqueMethodName("inject" + bindingTypeName);
ParameterSpec parameter = ParameterSpec.builder(membersInjectedTypeName, "instance").build();
MethodSpec.Builder methodBuilder =
- methodBuilder(methodName)
- .addModifiers(PRIVATE)
- .returns(membersInjectedTypeName)
- .addParameter(parameter);
+ useStaticInjectionMethod
+ ? methodBuilder(methodName)
+ .addModifiers(PRIVATE, STATIC)
+ .returns(membersInjectedTypeName)
+ .addParameter(parameter)
+ .addParameter(Object[].class, "dependencies")
+ : methodBuilder(methodName)
+ .addModifiers(PRIVATE)
+ .returns(membersInjectedTypeName)
+ .addParameter(parameter);
TypeElement canIgnoreReturnValue =
elements.getTypeElement("com.google.errorprone.annotations.CanIgnoreReturnValue");
if (canIgnoreReturnValue != null) {
@@ -108,20 +160,25 @@ final class MembersInjectionMethods {
methodBuilder.addCode(
InjectionSiteMethod.invokeAll(
injectionSites(binding),
- componentImplementation.name(),
+ shardImplementation.name(),
instance,
membersInjectedType,
request ->
- bindingExpressions
- .getDependencyArgumentExpression(request, componentImplementation.name())
+ (useStaticInjectionMethod
+ ? bindingExpressions
+ .getExperimentalSwitchingProviderDependencyRepresentation(
+ bindingRequest(request))
+ .getDependencyExpression(request.kind(), (ProvisionBinding) binding)
+ : bindingExpressions.getDependencyArgumentExpression(
+ request, shardImplementation.name()))
.codeBlock(),
types,
metadataUtil));
methodBuilder.addStatement("return $L", instance);
MethodSpec method = methodBuilder.build();
- componentImplementation.addMethod(MEMBERS_INJECTION_METHOD, method);
- return method;
+ shardImplementation.addMethod(MEMBERS_INJECTION_METHOD, method);
+ return Expression.create(membersInjectedType, CodeBlock.of("$N", method));
}
private static ImmutableSet<InjectionSite> injectionSites(Binding binding) {
diff --git a/java/dagger/internal/codegen/writing/MembersInjectionBindingExpression.java b/java/dagger/internal/codegen/writing/MembersInjectionRequestRepresentation.java
index abf9d03d3..748be8007 100644
--- a/java/dagger/internal/codegen/writing/MembersInjectionBindingExpression.java
+++ b/java/dagger/internal/codegen/writing/MembersInjectionRequestRepresentation.java
@@ -16,27 +16,32 @@
package dagger.internal.codegen.writing;
+import static androidx.room.compiler.processing.XTypeKt.isVoid;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.collect.Iterables.getOnlyElement;
-import static javax.lang.model.type.TypeKind.VOID;
+import androidx.room.compiler.processing.XMethodElement;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.ParameterSpec;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
import dagger.internal.codegen.binding.MembersInjectionBinding;
import dagger.internal.codegen.javapoet.Expression;
-import javax.lang.model.element.ExecutableElement;
/**
* A binding expression for members injection component methods. See {@link
* MembersInjectionMethods}.
*/
-final class MembersInjectionBindingExpression extends BindingExpression {
+final class MembersInjectionRequestRepresentation extends RequestRepresentation {
private final MembersInjectionBinding binding;
private final MembersInjectionMethods membersInjectionMethods;
- MembersInjectionBindingExpression(
- MembersInjectionBinding binding, MembersInjectionMethods membersInjectionMethods) {
+ @AssistedInject
+ MembersInjectionRequestRepresentation(
+ @Assisted MembersInjectionBinding binding, MembersInjectionMethods membersInjectionMethods) {
this.binding = binding;
this.membersInjectionMethods = membersInjectionMethods;
}
@@ -46,27 +51,36 @@ final class MembersInjectionBindingExpression extends BindingExpression {
throw new UnsupportedOperationException(binding.toString());
}
- // TODO(ronshapiro): This class doesn't need to be a BindingExpression, as
+ // TODO(ronshapiro): This class doesn't need to be a RequestRepresentation, as
// getDependencyExpression() should never be called for members injection methods. It's probably
// better suited as a method on MembersInjectionMethods
@Override
protected CodeBlock getComponentMethodImplementation(
ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
- ExecutableElement methodElement = componentMethod.methodElement();
- ParameterSpec parameter = ParameterSpec.get(getOnlyElement(methodElement.getParameters()));
+ XMethodElement methodElement = componentMethod.methodElement();
+ ParameterSpec parameter =
+ ParameterSpec.get(toJavac(getOnlyElement(methodElement.getParameters())));
if (binding.injectionSites().isEmpty()) {
- return methodElement.getReturnType().getKind().equals(VOID)
+ return isVoid(methodElement.getReturnType())
? CodeBlock.of("")
: CodeBlock.of("return $N;", parameter);
} else {
- return methodElement.getReturnType().getKind().equals(VOID)
- ? CodeBlock.of("$L;", membersInjectionInvocation(parameter))
- : CodeBlock.of("return $L;", membersInjectionInvocation(parameter));
+ ClassName requestingClass = component.name();
+ return isVoid(methodElement.getReturnType())
+ ? CodeBlock.of("$L;", membersInjectionInvocation(parameter, requestingClass).codeBlock())
+ : CodeBlock.of(
+ "return $L;", membersInjectionInvocation(parameter, requestingClass).codeBlock());
}
}
- CodeBlock membersInjectionInvocation(ParameterSpec target) {
- return CodeBlock.of("$N($N)", membersInjectionMethods.getOrCreate(binding.key()), target);
+ private Expression membersInjectionInvocation(ParameterSpec target, ClassName requestingClass) {
+ return membersInjectionMethods.getInjectExpression(
+ binding.key(), CodeBlock.of("$N", target), requestingClass);
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ MembersInjectionRequestRepresentation create(MembersInjectionBinding binding);
}
}
diff --git a/java/dagger/internal/codegen/writing/MembersInjectorGenerator.java b/java/dagger/internal/codegen/writing/MembersInjectorGenerator.java
index 8630ce6ca..b90693604 100644
--- a/java/dagger/internal/codegen/writing/MembersInjectorGenerator.java
+++ b/java/dagger/internal/codegen/writing/MembersInjectorGenerator.java
@@ -16,6 +16,7 @@
package dagger.internal.codegen.writing;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.base.Preconditions.checkState;
import static com.squareup.javapoet.MethodSpec.constructorBuilder;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
@@ -27,6 +28,7 @@ import static dagger.internal.codegen.binding.SourceFiles.frameworkFieldUsages;
import static dagger.internal.codegen.binding.SourceFiles.generateBindingFieldsForDependencies;
import static dagger.internal.codegen.binding.SourceFiles.membersInjectorNameForType;
import static dagger.internal.codegen.binding.SourceFiles.parameterizedGeneratedTypeNameForBinding;
+import static dagger.internal.codegen.extension.DaggerStreams.presentValues;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.suppressWarnings;
@@ -39,8 +41,11 @@ import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
@@ -55,16 +60,17 @@ import dagger.internal.codegen.base.UniqueNameSet;
import dagger.internal.codegen.binding.FrameworkField;
import dagger.internal.codegen.binding.MembersInjectionBinding;
import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
import dagger.internal.codegen.writing.InjectionMethods.InjectionSiteMethod;
-import dagger.model.DependencyRequest;
+import dagger.spi.model.DaggerAnnotation;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
import java.util.Map.Entry;
-import javax.annotation.processing.Filer;
import javax.inject.Inject;
import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
/**
* Generates {@link MembersInjector} implementations from {@link MembersInjectionBinding} instances.
@@ -75,7 +81,7 @@ public final class MembersInjectorGenerator extends SourceFileGenerator<MembersI
@Inject
MembersInjectorGenerator(
- Filer filer,
+ XFiler filer,
DaggerElements elements,
DaggerTypes types,
SourceVersion sourceVersion,
@@ -86,7 +92,7 @@ public final class MembersInjectorGenerator extends SourceFileGenerator<MembersI
}
@Override
- public Element originatingElement(MembersInjectionBinding binding) {
+ public XElement originatingElement(MembersInjectionBinding binding) {
return binding.membersInjectedType();
}
@@ -117,9 +123,10 @@ public final class MembersInjectorGenerator extends SourceFileGenerator<MembersI
TypeSpec.Builder injectorTypeBuilder =
classBuilder(generatedTypeName)
.addModifiers(PUBLIC, FINAL)
- .addTypeVariables(typeParameters);
+ .addTypeVariables(typeParameters)
+ .addAnnotation(qualifierMetadataAnnotation(binding));
- TypeName injectedTypeName = TypeName.get(binding.key().type());
+ TypeName injectedTypeName = TypeName.get(binding.key().type().java());
TypeName implementedType = membersInjectorOf(injectedTypeName);
injectorTypeBuilder.addSuperinterface(implementedType);
@@ -159,7 +166,7 @@ public final class MembersInjectorGenerator extends SourceFileGenerator<MembersI
// If the dependency type is not visible to this members injector, then use the raw framework
// type for the field.
boolean useRawFrameworkType =
- !isTypeAccessibleFrom(dependency.key().type(), generatedTypeName.packageName());
+ !isTypeAccessibleFrom(dependency.key().type().java(), generatedTypeName.packageName());
String fieldName = fieldNames.getUniqueName(bindingField.name());
TypeName fieldType = useRawFrameworkType ? bindingField.type().rawType : bindingField.type();
@@ -198,7 +205,7 @@ public final class MembersInjectorGenerator extends SourceFileGenerator<MembersI
binding.injectionSites(),
generatedTypeName,
CodeBlock.of("instance"),
- binding.key().type(),
+ binding.key().type().java(),
frameworkFieldUsages(binding.dependencies(), dependencyFields)::get,
types,
metadataUtil));
@@ -209,7 +216,10 @@ public final class MembersInjectorGenerator extends SourceFileGenerator<MembersI
injectorTypeBuilder.addMethod(injectMembersBuilder.build());
for (InjectionSite injectionSite : binding.injectionSites()) {
- if (injectionSite.element().getEnclosingElement().equals(binding.membersInjectedType())) {
+ if (injectionSite
+ .element()
+ .getEnclosingElement()
+ .equals(toJavac(binding.membersInjectedType()))) {
injectorTypeBuilder.addMethod(InjectionSiteMethod.create(injectionSite, metadataUtil));
}
}
@@ -218,4 +228,26 @@ public final class MembersInjectorGenerator extends SourceFileGenerator<MembersI
return ImmutableList.of(injectorTypeBuilder);
}
+
+ private AnnotationSpec qualifierMetadataAnnotation(MembersInjectionBinding binding) {
+ AnnotationSpec.Builder builder = AnnotationSpec.builder(TypeNames.QUALIFIER_METADATA);
+ binding.injectionSites().stream()
+ // filter out non-local injection sites. Injection sites for super types will be in their
+ // own generated _MembersInjector class.
+ .filter(
+ injectionSite ->
+ injectionSite
+ .element()
+ .getEnclosingElement()
+ .equals(toJavac(binding.membersInjectedType())))
+ .flatMap(injectionSite -> injectionSite.dependencies().stream())
+ .map(DependencyRequest::key)
+ .map(Key::qualifier)
+ .flatMap(presentValues())
+ .map(DaggerAnnotation::className)
+ .map(ClassName::canonicalName)
+ .distinct()
+ .forEach(qualifier -> builder.addMember("value", "$S", qualifier));
+ return builder.build();
+ }
}
diff --git a/java/dagger/internal/codegen/writing/MembersInjectorProviderCreationExpression.java b/java/dagger/internal/codegen/writing/MembersInjectorProviderCreationExpression.java
index 534c0573b..e00db0176 100644
--- a/java/dagger/internal/codegen/writing/MembersInjectorProviderCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/MembersInjectorProviderCreationExpression.java
@@ -24,7 +24,11 @@ import static dagger.internal.codegen.javapoet.TypeNames.MEMBERS_INJECTORS;
import com.google.auto.common.MoreTypes;
import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
@@ -33,19 +37,24 @@ import javax.lang.model.type.TypeMirror;
final class MembersInjectorProviderCreationExpression
implements FrameworkInstanceCreationExpression {
- private final ComponentBindingExpressions componentBindingExpressions;
+ private final ShardImplementation shardImplementation;
+ private final ComponentRequestRepresentations componentRequestRepresentations;
private final ProvisionBinding binding;
+ @AssistedInject
MembersInjectorProviderCreationExpression(
- ProvisionBinding binding, ComponentBindingExpressions componentBindingExpressions) {
+ @Assisted ProvisionBinding binding,
+ ComponentImplementation componentImplementation,
+ ComponentRequestRepresentations componentRequestRepresentations) {
this.binding = checkNotNull(binding);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ this.shardImplementation = componentImplementation.shardImplementation(binding);
+ this.componentRequestRepresentations = checkNotNull(componentRequestRepresentations);
}
@Override
public CodeBlock creationExpression() {
TypeMirror membersInjectedType =
- getOnlyElement(MoreTypes.asDeclared(binding.key().type()).getTypeArguments());
+ getOnlyElement(MoreTypes.asDeclared(binding.key().type().java()).getTypeArguments());
boolean castThroughRawType = false;
CodeBlock membersInjector;
@@ -60,13 +69,16 @@ final class MembersInjectorProviderCreationExpression
injectedTypeElement = MoreTypes.asTypeElement(injectedTypeElement.getSuperclass());
}
- membersInjector = CodeBlock.of(
- "$T.create($L)",
- membersInjectorNameForType(injectedTypeElement),
- componentBindingExpressions.getCreateMethodArgumentsCodeBlock(binding));
+ membersInjector =
+ CodeBlock.of(
+ "$T.create($L)",
+ membersInjectorNameForType(injectedTypeElement),
+ componentRequestRepresentations.getCreateMethodArgumentsCodeBlock(
+ binding, shardImplementation.name()));
}
- // TODO(ronshapiro): consider adding a MembersInjectorBindingExpression to return this directly
+ // TODO(ronshapiro): consider adding a MembersInjectorRequestRepresentation to return this
+ // directly
// (as it's rarely requested as a Provider).
CodeBlock providerExpression = CodeBlock.of("$T.create($L)", INSTANCE_FACTORY, membersInjector);
// If needed we cast through raw type around the InstanceFactory type as opposed to the
@@ -75,19 +87,19 @@ final class MembersInjectorProviderCreationExpression
// a second cast. If we just cast to the raw type InstanceFactory though, that becomes
// assignable.
return castThroughRawType
- ? CodeBlock.of("($T) $L", INSTANCE_FACTORY, providerExpression) : providerExpression;
+ ? CodeBlock.of("($T) $L", INSTANCE_FACTORY, providerExpression)
+ : providerExpression;
}
private boolean hasLocalInjectionSites(TypeElement injectedTypeElement) {
- return binding.injectionSites()
- .stream()
+ return binding.injectionSites().stream()
.anyMatch(
injectionSite ->
injectionSite.element().getEnclosingElement().equals(injectedTypeElement));
}
- @Override
- public boolean useInnerSwitchingProvider() {
- return !binding.injectionSites().isEmpty();
+ @AssistedFactory
+ static interface Factory {
+ MembersInjectorProviderCreationExpression create(ProvisionBinding binding);
}
}
diff --git a/java/dagger/internal/codegen/writing/MethodBindingExpression.java b/java/dagger/internal/codegen/writing/MethodBindingExpression.java
deleted file mode 100644
index 9c0c74aca..000000000
--- a/java/dagger/internal/codegen/writing/MethodBindingExpression.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright (C) 2018 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedParameterSpecs;
-import static dagger.internal.codegen.javapoet.CodeBlocks.parameterNames;
-import static dagger.internal.codegen.writing.ComponentImplementation.FieldSpecKind.PRIVATE_METHOD_SCOPED_FIELD;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.VOLATILE;
-
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.TypeName;
-import dagger.internal.DoubleCheck;
-import dagger.internal.MemoizedSentinel;
-import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.FrameworkField;
-import dagger.internal.codegen.binding.KeyVariableNamer;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingKind;
-import dagger.model.RequestKind;
-import java.util.Optional;
-import javax.lang.model.type.TypeMirror;
-
-/** A binding expression that wraps another in a nullary method on the component. */
-abstract class MethodBindingExpression extends BindingExpression {
- private final BindingRequest request;
- private final ContributionBinding binding;
- private final BindingMethodImplementation bindingMethodImplementation;
- private final ComponentImplementation componentImplementation;
- private final ProducerEntryPointView producerEntryPointView;
- private final BindingExpression wrappedBindingExpression;
- private final DaggerTypes types;
-
- protected MethodBindingExpression(
- BindingRequest request,
- ContributionBinding binding,
- MethodImplementationStrategy methodImplementationStrategy,
- BindingExpression wrappedBindingExpression,
- ComponentImplementation componentImplementation,
- DaggerTypes types) {
- this.request = checkNotNull(request);
- this.binding = checkNotNull(binding);
- this.bindingMethodImplementation = bindingMethodImplementation(methodImplementationStrategy);
- this.wrappedBindingExpression = checkNotNull(wrappedBindingExpression);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.producerEntryPointView = new ProducerEntryPointView(types);
- this.types = checkNotNull(types);
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- if (request.frameworkType().isPresent()) {
- // Initializing a framework instance that participates in a cycle requires that the underlying
- // FrameworkInstanceBindingExpression is invoked in order for a cycle to be detected properly.
- // When a MethodBindingExpression wraps a FrameworkInstanceBindingExpression, the wrapped
- // expression will only be invoked once to implement the method body. This is a hack to work
- // around that weirdness - methodImplementation.body() will invoke the framework instance
- // initialization again in case the field is not fully initialized.
- // TODO(b/121196706): use a less hacky approach to fix this bug
- Object unused = methodBody();
- }
-
- addMethod();
-
- CodeBlock methodCall =
- binding.kind() == BindingKind.ASSISTED_INJECTION
- // Private methods for assisted injection take assisted parameters as input.
- ? CodeBlock.of(
- "$N($L)", methodName(), parameterNames(assistedParameterSpecs(binding, types)))
- : CodeBlock.of("$N()", methodName());
-
- return Expression.create(
- returnType(),
- requestingClass.equals(componentImplementation.name())
- ? methodCall
- : CodeBlock.of("$L.$L", componentImplementation.externalReferenceBlock(), methodCall));
- }
-
- @Override
- Expression getDependencyExpressionForComponentMethod(ComponentMethodDescriptor componentMethod,
- ComponentImplementation component) {
- return producerEntryPointView
- .getProducerEntryPointField(this, componentMethod, component)
- .orElseGet(
- () -> super.getDependencyExpressionForComponentMethod(componentMethod, component));
- }
-
- /** Adds the method to the component (if necessary) the first time it's called. */
- protected abstract void addMethod();
-
- /** Returns the name of the method to call. */
- protected abstract String methodName();
-
- /** The method's body. */
- protected final CodeBlock methodBody() {
- return implementation(
- wrappedBindingExpression.getDependencyExpression(componentImplementation.name())
- ::codeBlock);
- }
-
- /** The method's body if this method is a component method. */
- protected final CodeBlock methodBodyForComponentMethod(
- ComponentMethodDescriptor componentMethod) {
- return implementation(
- wrappedBindingExpression.getDependencyExpressionForComponentMethod(
- componentMethod, componentImplementation)
- ::codeBlock);
- }
-
- private CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression) {
- return bindingMethodImplementation.implementation(simpleBindingExpression);
- }
-
- private BindingMethodImplementation bindingMethodImplementation(
- MethodImplementationStrategy methodImplementationStrategy) {
- switch (methodImplementationStrategy) {
- case SIMPLE:
- return new SimpleMethodImplementation();
- case SINGLE_CHECK:
- return new SingleCheckedMethodImplementation();
- case DOUBLE_CHECK:
- return new DoubleCheckedMethodImplementation();
- }
- throw new AssertionError(methodImplementationStrategy);
- }
-
- /** Returns the return type for the dependency request. */
- protected TypeMirror returnType() {
- if (request.isRequestKind(RequestKind.INSTANCE)
- && binding.contributedPrimitiveType().isPresent()) {
- return binding.contributedPrimitiveType().get();
- }
-
- if (matchingComponentMethod().isPresent()) {
- // Component methods are part of the user-defined API, and thus we must use the user-defined
- // type.
- return matchingComponentMethod().get().resolvedReturnType(types);
- }
-
- TypeMirror requestedType = request.requestedType(binding.contributedType(), types);
- return types.accessibleType(requestedType, componentImplementation.name());
- }
-
- private Optional<ComponentMethodDescriptor> matchingComponentMethod() {
- return componentImplementation.componentDescriptor().firstMatchingComponentMethod(request);
- }
-
- /** Strateg for implementing the body of this method. */
- enum MethodImplementationStrategy {
- SIMPLE,
- SINGLE_CHECK,
- DOUBLE_CHECK,
- ;
- }
-
- private abstract static class BindingMethodImplementation {
- /**
- * Returns the method body, which contains zero or more statements (including semicolons).
- *
- * <p>If the implementation has a non-void return type, the body will also include the {@code
- * return} statement.
- *
- * @param simpleBindingExpression the expression to retrieve an instance of this binding without
- * the wrapping method.
- */
- abstract CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression);
- }
-
- /** Returns the {@code wrappedBindingExpression} directly. */
- private static final class SimpleMethodImplementation extends BindingMethodImplementation {
- @Override
- CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression) {
- return CodeBlock.of("return $L;", simpleBindingExpression.get());
- }
- }
-
- /**
- * Defines a method body for single checked caching of the given {@code wrappedBindingExpression}.
- */
- private final class SingleCheckedMethodImplementation extends BindingMethodImplementation {
- private final Supplier<FieldSpec> field = Suppliers.memoize(this::createField);
-
- @Override
- CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression) {
- String fieldExpression = field.get().name.equals("local") ? "this.local" : field.get().name;
-
- CodeBlock.Builder builder = CodeBlock.builder()
- .addStatement("Object local = $N", fieldExpression);
-
- if (isNullable()) {
- builder.beginControlFlow("if (local instanceof $T)", MemoizedSentinel.class);
- } else {
- builder.beginControlFlow("if (local == null)");
- }
-
- return builder
- .addStatement("local = $L", simpleBindingExpression.get())
- .addStatement("$N = ($T) local", fieldExpression, returnType())
- .endControlFlow()
- .addStatement("return ($T) local", returnType())
- .build();
- }
-
- FieldSpec createField() {
- String name =
- componentImplementation.getUniqueFieldName(
- request.isRequestKind(RequestKind.INSTANCE)
- ? KeyVariableNamer.name(binding.key())
- : FrameworkField.forBinding(binding, Optional.empty()).name());
-
- FieldSpec.Builder builder = FieldSpec.builder(fieldType(), name, PRIVATE, VOLATILE);
- if (isNullable()) {
- builder.initializer("new $T()", MemoizedSentinel.class);
- }
-
- FieldSpec field = builder.build();
- componentImplementation.addField(PRIVATE_METHOD_SCOPED_FIELD, field);
- return field;
- }
-
- TypeName fieldType() {
- if (isNullable()) {
- // Nullable instances use `MemoizedSentinel` instead of `null` as the initialization value,
- // so the field type must accept that and the return type
- return TypeName.OBJECT;
- }
- TypeName returnType = TypeName.get(returnType());
- return returnType.isPrimitive() ? returnType.box() : returnType;
- }
-
- private boolean isNullable() {
- return request.isRequestKind(RequestKind.INSTANCE) && binding.isNullable();
- }
- }
-
- /**
- * Defines a method body for double checked caching of the given {@code wrappedBindingExpression}.
- */
- private final class DoubleCheckedMethodImplementation extends BindingMethodImplementation {
- private final Supplier<String> fieldName = Suppliers.memoize(this::createField);
-
- @Override
- CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression) {
- String fieldExpression = fieldName.get().equals("local") ? "this.local" : fieldName.get();
- return CodeBlock.builder()
- .addStatement("$T local = $L", TypeName.OBJECT, fieldExpression)
- .beginControlFlow("if (local instanceof $T)", MemoizedSentinel.class)
- .beginControlFlow("synchronized (local)")
- .addStatement("local = $L", fieldExpression)
- .beginControlFlow("if (local instanceof $T)", MemoizedSentinel.class)
- .addStatement("local = $L", simpleBindingExpression.get())
- .addStatement("$1L = $2T.reentrantCheck($1L, local)", fieldExpression, DoubleCheck.class)
- .endControlFlow()
- .endControlFlow()
- .endControlFlow()
- .addStatement("return ($T) local", returnType())
- .build();
- }
-
- private String createField() {
- String name =
- componentImplementation.getUniqueFieldName(KeyVariableNamer.name(binding.key()));
- componentImplementation.addField(
- PRIVATE_METHOD_SCOPED_FIELD,
- FieldSpec.builder(TypeName.OBJECT, name, PRIVATE, VOLATILE)
- .initializer("new $T()", MemoizedSentinel.class)
- .build());
- return name;
- }
- }
-
-}
diff --git a/java/dagger/internal/codegen/writing/MethodRequestRepresentation.java b/java/dagger/internal/codegen/writing/MethodRequestRepresentation.java
new file mode 100644
index 000000000..714e5f074
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/MethodRequestRepresentation.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
+import javax.lang.model.type.TypeMirror;
+
+/** A binding expression that wraps another in a nullary method on the component. */
+abstract class MethodRequestRepresentation extends RequestRepresentation {
+ private final ShardImplementation shardImplementation;
+ private final ProducerEntryPointView producerEntryPointView;
+
+ protected MethodRequestRepresentation(
+ ShardImplementation shardImplementation, DaggerTypes types) {
+ this.shardImplementation = shardImplementation;
+ this.producerEntryPointView = new ProducerEntryPointView(shardImplementation, types);
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ return Expression.create(
+ returnType(),
+ requestingClass.equals(shardImplementation.name())
+ ? methodCall()
+ : CodeBlock.of("$L.$L", shardImplementation.shardFieldReference(), methodCall()));
+ }
+
+ @Override
+ Expression getDependencyExpressionForComponentMethod(
+ ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
+ return producerEntryPointView
+ .getProducerEntryPointField(this, componentMethod, component.name())
+ .orElseGet(
+ () -> super.getDependencyExpressionForComponentMethod(componentMethod, component));
+ }
+
+ /** Returns the return type for the dependency request. */
+ protected abstract TypeMirror returnType();
+
+ /** Returns the method call. */
+ protected abstract CodeBlock methodCall();
+}
diff --git a/java/dagger/internal/codegen/writing/ModuleProxies.java b/java/dagger/internal/codegen/writing/ModuleProxies.java
index 6d174f824..a88f6edb3 100644
--- a/java/dagger/internal/codegen/writing/ModuleProxies.java
+++ b/java/dagger/internal/codegen/writing/ModuleProxies.java
@@ -16,98 +16,92 @@
package dagger.internal.codegen.writing;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.squareup.javapoet.MethodSpec.constructorBuilder;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
import static com.squareup.javapoet.TypeSpec.classBuilder;
import static dagger.internal.codegen.langmodel.Accessibility.isElementAccessibleFrom;
-import static javax.lang.model.element.Modifier.ABSTRACT;
+import static dagger.internal.codegen.xprocessing.XTypeElements.isNested;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
import static javax.lang.model.util.ElementFilter.constructorsIn;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.TypeSpec;
+import dagger.internal.codegen.base.ModuleKind;
import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.binding.ModuleKind;
import dagger.internal.codegen.binding.SourceFiles;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
import dagger.internal.codegen.langmodel.Accessibility;
import dagger.internal.codegen.langmodel.DaggerElements;
import java.util.Optional;
-import javax.annotation.processing.Filer;
import javax.inject.Inject;
import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
/** Convenience methods for generating and using module constructor proxy methods. */
public final class ModuleProxies {
private final DaggerElements elements;
- private final KotlinMetadataUtil metadataUtil;
-
@Inject
- public ModuleProxies(DaggerElements elements, KotlinMetadataUtil metadataUtil) {
+ ModuleProxies(DaggerElements elements) {
this.elements = elements;
- this.metadataUtil = metadataUtil;
}
/** Generates a {@code public static} proxy method for constructing module instances. */
// TODO(dpb): See if this can become a SourceFileGenerator<ModuleDescriptor> instead. Doing so may
// cause ModuleProcessingStep to defer elements multiple times.
public static final class ModuleConstructorProxyGenerator
- extends SourceFileGenerator<TypeElement> {
+ extends SourceFileGenerator<XTypeElement> {
private final ModuleProxies moduleProxies;
- private final KotlinMetadataUtil metadataUtil;
@Inject
ModuleConstructorProxyGenerator(
- Filer filer,
+ XFiler filer,
DaggerElements elements,
SourceVersion sourceVersion,
- ModuleProxies moduleProxies,
- KotlinMetadataUtil metadataUtil) {
+ ModuleProxies moduleProxies) {
super(filer, elements, sourceVersion);
this.moduleProxies = moduleProxies;
- this.metadataUtil = metadataUtil;
}
@Override
- public Element originatingElement(TypeElement moduleElement) {
+ public XElement originatingElement(XTypeElement moduleElement) {
return moduleElement;
}
@Override
- public ImmutableList<TypeSpec.Builder> topLevelTypes(TypeElement moduleElement) {
- ModuleKind.checkIsModule(moduleElement, metadataUtil);
+ public ImmutableList<TypeSpec.Builder> topLevelTypes(XTypeElement moduleElement) {
+ ModuleKind.checkIsModule(moduleElement);
return moduleProxies.nonPublicNullaryConstructor(moduleElement).isPresent()
? ImmutableList.of(buildProxy(moduleElement))
: ImmutableList.of();
}
- private TypeSpec.Builder buildProxy(TypeElement moduleElement) {
+ private TypeSpec.Builder buildProxy(XTypeElement moduleElement) {
return classBuilder(moduleProxies.constructorProxyTypeName(moduleElement))
.addModifiers(PUBLIC, FINAL)
.addMethod(constructorBuilder().addModifiers(PRIVATE).build())
.addMethod(
methodBuilder("newInstance")
.addModifiers(PUBLIC, STATIC)
- .returns(ClassName.get(moduleElement))
- .addStatement("return new $T()", moduleElement)
+ .returns(moduleElement.getClassName())
+ .addStatement("return new $T()", moduleElement.getClassName())
.build());
}
}
/** The name of the class that hosts the module constructor proxy method. */
- private ClassName constructorProxyTypeName(TypeElement moduleElement) {
- ModuleKind.checkIsModule(moduleElement, metadataUtil);
- ClassName moduleClassName = ClassName.get(moduleElement);
+ private ClassName constructorProxyTypeName(XTypeElement moduleElement) {
+ ModuleKind.checkIsModule(moduleElement);
+ ClassName moduleClassName = moduleElement.getClassName();
return moduleClassName
.topLevelClassName()
.peerClass(SourceFiles.classFileName(moduleClassName) + "_Proxy");
@@ -118,14 +112,12 @@ public final class ModuleProxies {
* has no arguments. If an implicit reference to the enclosing class exists, or the module is
* abstract, no proxy method can be generated.
*/
- private Optional<ExecutableElement> nonPublicNullaryConstructor(TypeElement moduleElement) {
- ModuleKind.checkIsModule(moduleElement, metadataUtil);
- if (moduleElement.getModifiers().contains(ABSTRACT)
- || (moduleElement.getNestingKind().isNested()
- && !moduleElement.getModifiers().contains(STATIC))) {
+ private Optional<ExecutableElement> nonPublicNullaryConstructor(XTypeElement moduleElement) {
+ ModuleKind.checkIsModule(moduleElement);
+ if (moduleElement.isAbstract() || (isNested(moduleElement) && !moduleElement.isStatic())) {
return Optional.empty();
}
- return constructorsIn(elements.getAllMembers(moduleElement)).stream()
+ return constructorsIn(elements.getAllMembers(toJavac(moduleElement))).stream()
.filter(constructor -> !Accessibility.isElementPubliclyAccessible(constructor))
.filter(constructor -> !constructor.getModifiers().contains(PRIVATE))
.filter(constructor -> constructor.getParameters().isEmpty())
@@ -137,14 +129,14 @@ public final class ModuleProxies {
* constructor if it's accessible from {@code requestingClass} or else by invoking the
* constructor's generated proxy method.
*/
- public CodeBlock newModuleInstance(TypeElement moduleElement, ClassName requestingClass) {
- ModuleKind.checkIsModule(moduleElement, metadataUtil);
+ public CodeBlock newModuleInstance(XTypeElement moduleElement, ClassName requestingClass) {
+ ModuleKind.checkIsModule(moduleElement);
String packageName = requestingClass.packageName();
return nonPublicNullaryConstructor(moduleElement)
.filter(constructor -> !isElementAccessibleFrom(constructor, packageName))
.map(
constructor ->
CodeBlock.of("$T.newInstance()", constructorProxyTypeName(moduleElement)))
- .orElse(CodeBlock.of("new $T()", moduleElement));
+ .orElse(CodeBlock.of("new $T()", moduleElement.getClassName()));
}
}
diff --git a/java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java b/java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java
index 64e008ee1..034e835cc 100644
--- a/java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java
@@ -22,36 +22,37 @@ import com.squareup.javapoet.CodeBlock;
import dagger.internal.codegen.binding.BindingRequest;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.javapoet.CodeBlocks;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import dagger.model.DependencyRequest;
+import dagger.spi.model.DependencyRequest;
/** An abstract factory creation expression for multibindings. */
abstract class MultibindingFactoryCreationExpression
implements FrameworkInstanceCreationExpression {
- private final ComponentImplementation componentImplementation;
- private final ComponentBindingExpressions componentBindingExpressions;
+ private final ShardImplementation shardImplementation;
+ private final ComponentRequestRepresentations componentRequestRepresentations;
private final ContributionBinding binding;
MultibindingFactoryCreationExpression(
ContributionBinding binding,
ComponentImplementation componentImplementation,
- ComponentBindingExpressions componentBindingExpressions) {
+ ComponentRequestRepresentations componentRequestRepresentations) {
this.binding = checkNotNull(binding);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ this.shardImplementation = checkNotNull(componentImplementation).shardImplementation(binding);
+ this.componentRequestRepresentations = checkNotNull(componentRequestRepresentations);
}
/** Returns the expression for a dependency of this multibinding. */
protected final CodeBlock multibindingDependencyExpression(DependencyRequest dependency) {
CodeBlock expression =
- componentBindingExpressions
+ componentRequestRepresentations
.getDependencyExpression(
BindingRequest.bindingRequest(dependency.key(), binding.frameworkType()),
- componentImplementation.name())
+ shardImplementation.name())
.codeBlock();
return useRawType()
- ? CodeBlocks.cast(expression, binding.frameworkType().frameworkClass())
+ ? CodeBlocks.cast(expression, binding.frameworkType().frameworkClassName())
: expression;
}
@@ -65,11 +66,6 @@ abstract class MultibindingFactoryCreationExpression
* component, and therefore a raw type must be used.
*/
protected final boolean useRawType() {
- return !componentImplementation.isTypeAccessible(binding.key().type());
- }
-
- @Override
- public final boolean useInnerSwitchingProvider() {
- return !binding.dependencies().isEmpty();
+ return !shardImplementation.isTypeAccessible(binding.key().type().java());
}
}
diff --git a/java/dagger/internal/codegen/writing/OptionalFactories.java b/java/dagger/internal/codegen/writing/OptionalFactories.java
index 2d809633f..07b497bcd 100644
--- a/java/dagger/internal/codegen/writing/OptionalFactories.java
+++ b/java/dagger/internal/codegen/writing/OptionalFactories.java
@@ -27,7 +27,6 @@ import static com.squareup.javapoet.TypeSpec.classBuilder;
import static dagger.internal.codegen.base.RequestKinds.requestTypeName;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
-import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER;
import static dagger.internal.codegen.javapoet.TypeNames.abstractProducerOf;
import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf;
import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
@@ -61,9 +60,11 @@ import dagger.internal.codegen.binding.BindingType;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.binding.FrameworkType;
import dagger.internal.codegen.javapoet.AnnotationSpecs;
-import dagger.model.RequestKind;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.producers.Producer;
import dagger.producers.internal.Producers;
+import dagger.spi.model.RequestKind;
import java.util.Comparator;
import java.util.Map;
import java.util.Optional;
@@ -74,37 +75,50 @@ import javax.inject.Provider;
/** The nested class and static methods required by the component to implement optional bindings. */
// TODO(dpb): Name members simply if a component uses only one of Guava or JDK Optional.
-@PerGeneratedFile
final class OptionalFactories {
- private final ComponentImplementation componentImplementation;
-
- @Inject OptionalFactories(@TopLevel ComponentImplementation componentImplementation) {
- this.componentImplementation = componentImplementation;
+ /** Keeps track of the fields, methods, and classes already added to the generated file. */
+ @PerGeneratedFile
+ static final class PerGeneratedFileCache {
+ /**
+ * The factory classes that implement {@code Provider<Optional<T>>} or {@code
+ * Producer<Optional<T>>} for present optional bindings for a given kind of dependency request
+ * within the component.
+ *
+ * <p>The key is the {@code Provider<Optional<T>>} type.
+ */
+ private final Map<PresentFactorySpec, TypeSpec> presentFactoryClasses =
+ new TreeMap<>(
+ Comparator.comparing(PresentFactorySpec::valueKind)
+ .thenComparing(PresentFactorySpec::frameworkType)
+ .thenComparing(PresentFactorySpec::optionalKind));
+
+ /**
+ * The static methods that return a {@code Provider<Optional<T>>} that always returns an absent
+ * value.
+ */
+ private final Map<OptionalKind, MethodSpec> absentOptionalProviderMethods = new TreeMap<>();
+
+ /**
+ * The static fields for {@code Provider<Optional<T>>} objects that always return an absent
+ * value.
+ */
+ private final Map<OptionalKind, FieldSpec> absentOptionalProviderFields = new TreeMap<>();
+
+ @Inject
+ PerGeneratedFileCache() {}
}
- /**
- * The factory classes that implement {@code Provider<Optional<T>>} or {@code
- * Producer<Optional<T>>} for present optional bindings for a given kind of dependency request
- * within the component.
- *
- * <p>The key is the {@code Provider<Optional<T>>} type.
- */
- private final Map<PresentFactorySpec, TypeSpec> presentFactoryClasses =
- new TreeMap<>(
- Comparator.comparing(PresentFactorySpec::valueKind)
- .thenComparing(PresentFactorySpec::frameworkType)
- .thenComparing(PresentFactorySpec::optionalKind));
+ private final PerGeneratedFileCache perGeneratedFileCache;
+ private final ShardImplementation rootComponentShard;
- /**
- * The static methods that return a {@code Provider<Optional<T>>} that always returns an absent
- * value.
- */
- private final Map<OptionalKind, MethodSpec> absentOptionalProviderMethods = new TreeMap<>();
-
- /**
- * The static fields for {@code Provider<Optional<T>>} objects that always return an absent value.
- */
- private final Map<OptionalKind, FieldSpec> absentOptionalProviderFields = new TreeMap<>();
+ @Inject
+ OptionalFactories(
+ PerGeneratedFileCache perGeneratedFileCache,
+ ComponentImplementation componentImplementation) {
+ this.perGeneratedFileCache = perGeneratedFileCache;
+ this.rootComponentShard =
+ componentImplementation.rootComponentImplementation().getComponentShard();
+ }
/**
* Returns an expression that calls a static method that returns a {@code Provider<Optional<T>>}
@@ -118,11 +132,11 @@ final class OptionalFactories {
OptionalKind optionalKind = OptionalType.from(binding.key()).kind();
return CodeBlock.of(
"$N()",
- absentOptionalProviderMethods.computeIfAbsent(
+ perGeneratedFileCache.absentOptionalProviderMethods.computeIfAbsent(
optionalKind,
kind -> {
MethodSpec method = absentOptionalProviderMethod(kind);
- componentImplementation.addMethod(ABSENT_OPTIONAL_METHOD, method);
+ rootComponentShard.addMethod(ABSENT_OPTIONAL_METHOD, method);
return method;
}));
}
@@ -141,20 +155,20 @@ final class OptionalFactories {
.returns(providerOf(optionalKind.of(typeVariable)))
.addJavadoc(
"Returns a {@link $T} that returns {@code $L}.",
- Provider.class,
+ TypeNames.PROVIDER,
optionalKind.absentValueExpression())
.addCode("$L // safe covariant cast\n", AnnotationSpecs.suppressWarnings(UNCHECKED))
- .addCode(
- "$1T provider = ($1T) $2N;",
+ .addStatement(
+ "$1T provider = ($1T) $2N",
providerOf(optionalKind.of(typeVariable)),
- absentOptionalProviderFields.computeIfAbsent(
+ perGeneratedFileCache.absentOptionalProviderFields.computeIfAbsent(
optionalKind,
kind -> {
FieldSpec field = absentOptionalProviderField(kind);
- componentImplementation.addField(ABSENT_OPTIONAL_FIELD, field);
+ rootComponentShard.addField(ABSENT_OPTIONAL_FIELD, field);
return field;
}))
- .addCode("return provider;")
+ .addStatement("return provider")
.build();
}
@@ -164,7 +178,7 @@ final class OptionalFactories {
*/
private FieldSpec absentOptionalProviderField(OptionalKind optionalKind) {
return FieldSpec.builder(
- PROVIDER,
+ TypeNames.PROVIDER,
String.format("ABSENT_%s_PROVIDER", optionalKind.name()),
PRIVATE,
STATIC,
@@ -173,7 +187,7 @@ final class OptionalFactories {
.initializer("$T.create($L)", InstanceFactory.class, optionalKind.absentValueExpression())
.addJavadoc(
"A {@link $T} that returns {@code $L}.",
- Provider.class,
+ TypeNames.PROVIDER,
optionalKind.absentValueExpression())
.build();
}
@@ -258,7 +272,7 @@ final class OptionalFactories {
return new StringBuilder("Present")
.append(UPPER_UNDERSCORE.to(UPPER_CAMEL, optionalKind().name()))
.append(UPPER_UNDERSCORE.to(UPPER_CAMEL, valueKind().toString()))
- .append(frameworkType().frameworkClass().getSimpleName())
+ .append(frameworkType().frameworkClassName().simpleName())
.toString();
}
@@ -296,11 +310,11 @@ final class OptionalFactories {
CodeBlock presentOptionalFactory(ContributionBinding binding, CodeBlock delegateFactory) {
return CodeBlock.of(
"$N.of($L)",
- presentFactoryClasses.computeIfAbsent(
+ perGeneratedFileCache.presentFactoryClasses.computeIfAbsent(
PresentFactorySpec.of(binding),
spec -> {
TypeSpec type = presentOptionalFactoryClass(spec);
- componentImplementation.addType(PRESENT_FACTORY, type);
+ rootComponentShard.addType(PRESENT_FACTORY, type);
return type;
}),
delegateFactory);
diff --git a/java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java b/java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java
index 593921ef9..df9d15ef6 100644
--- a/java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java
@@ -20,11 +20,14 @@ import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
/**
- * A {@link FrameworkInstanceCreationExpression} for {@link dagger.model.BindingKind#OPTIONAL
+ * A {@link FrameworkInstanceCreationExpression} for {@link dagger.spi.model.BindingKind#OPTIONAL
* optional bindings}.
*/
final class OptionalFactoryInstanceCreationExpression
@@ -32,17 +35,18 @@ final class OptionalFactoryInstanceCreationExpression
private final OptionalFactories optionalFactories;
private final ContributionBinding binding;
private final ComponentImplementation componentImplementation;
- private final ComponentBindingExpressions componentBindingExpressions;
+ private final ComponentRequestRepresentations componentRequestRepresentations;
+ @AssistedInject
OptionalFactoryInstanceCreationExpression(
+ @Assisted ContributionBinding binding,
OptionalFactories optionalFactories,
- ContributionBinding binding,
ComponentImplementation componentImplementation,
- ComponentBindingExpressions componentBindingExpressions) {
+ ComponentRequestRepresentations componentRequestRepresentations) {
this.optionalFactories = optionalFactories;
this.binding = binding;
this.componentImplementation = componentImplementation;
- this.componentBindingExpressions = componentBindingExpressions;
+ this.componentRequestRepresentations = componentRequestRepresentations;
}
@Override
@@ -51,18 +55,16 @@ final class OptionalFactoryInstanceCreationExpression
? optionalFactories.absentOptionalProvider(binding)
: optionalFactories.presentOptionalFactory(
binding,
- componentBindingExpressions
+ componentRequestRepresentations
.getDependencyExpression(
bindingRequest(
getOnlyElement(binding.dependencies()).key(), binding.frameworkType()),
- componentImplementation.name())
+ componentImplementation.shardImplementation(binding).name())
.codeBlock());
}
- @Override
- public boolean useInnerSwitchingProvider() {
- // Share providers for empty optionals from OptionalFactories so we don't have numerous
- // switch cases that all return Optional.empty().
- return !binding.dependencies().isEmpty();
+ @AssistedFactory
+ static interface Factory {
+ OptionalFactoryInstanceCreationExpression create(ContributionBinding binding);
}
}
diff --git a/java/dagger/internal/codegen/writing/OptionalBindingExpression.java b/java/dagger/internal/codegen/writing/OptionalRequestRepresentation.java
index 4faf3fa6f..caef3a694 100644
--- a/java/dagger/internal/codegen/writing/OptionalBindingExpression.java
+++ b/java/dagger/internal/codegen/writing/OptionalRequestRepresentation.java
@@ -22,33 +22,38 @@ import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFr
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.base.OptionalType;
import dagger.internal.codegen.base.OptionalType.OptionalKind;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.javapoet.Expression;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import javax.inject.Inject;
+import dagger.spi.model.DependencyRequest;
import javax.lang.model.SourceVersion;
/** A binding expression for optional bindings. */
-final class OptionalBindingExpression extends SimpleInvocationBindingExpression {
+final class OptionalRequestRepresentation extends RequestRepresentation {
private final ProvisionBinding binding;
- private final ComponentBindingExpressions componentBindingExpressions;
+ private final ComponentRequestRepresentations componentRequestRepresentations;
private final DaggerTypes types;
private final SourceVersion sourceVersion;
+ private final boolean isExperimentalMergedMode;
- @Inject
- OptionalBindingExpression(
- ProvisionBinding binding,
- ComponentBindingExpressions componentBindingExpressions,
+ @AssistedInject
+ OptionalRequestRepresentation(
+ @Assisted ProvisionBinding binding,
+ ComponentImplementation componentImplementation,
+ ComponentRequestRepresentations componentRequestRepresentations,
DaggerTypes types,
SourceVersion sourceVersion) {
- super(binding);
this.binding = binding;
- this.componentBindingExpressions = componentBindingExpressions;
+ this.componentRequestRepresentations = componentRequestRepresentations;
this.types = types;
this.sourceVersion = sourceVersion;
+ this.isExperimentalMergedMode =
+ componentImplementation.compilerMode().isExperimentalMergedMode();
}
@Override
@@ -62,33 +67,39 @@ final class OptionalBindingExpression extends SimpleInvocationBindingExpression
// issues
// when used as an argument to some members injection proxy methods (see
// https://github.com/google/dagger/issues/916)
- if (isTypeAccessibleFrom(binding.key().type(), requestingClass.packageName())) {
+ if (isTypeAccessibleFrom(binding.key().type().java(), requestingClass.packageName())) {
return Expression.create(
- binding.key().type(), optionalKind.parameterizedAbsentValueExpression(optionalType));
+ binding.key().type().java(),
+ optionalKind.parameterizedAbsentValueExpression(optionalType));
}
}
- return Expression.create(binding.key().type(), optionalKind.absentValueExpression());
+ return Expression.create(binding.key().type().java(), optionalKind.absentValueExpression());
}
DependencyRequest dependency = getOnlyElement(binding.dependencies());
CodeBlock dependencyExpression =
- componentBindingExpressions
- .getDependencyExpression(bindingRequest(dependency), requestingClass)
- .codeBlock();
+ isExperimentalMergedMode
+ ? componentRequestRepresentations
+ .getExperimentalSwitchingProviderDependencyRepresentation(
+ bindingRequest(dependency))
+ .getDependencyExpression(dependency.kind(), binding)
+ .codeBlock()
+ : componentRequestRepresentations
+ .getDependencyExpression(bindingRequest(dependency), requestingClass)
+ .codeBlock();
// If the dependency type is inaccessible, then we have to use Optional.<Object>of(...), or else
// we will get "incompatible types: inference variable has incompatible bounds.
- return isTypeAccessibleFrom(dependency.key().type(), requestingClass.packageName())
+ return isTypeAccessibleFrom(dependency.key().type().java(), requestingClass.packageName())
? Expression.create(
- binding.key().type(), optionalKind.presentExpression(dependencyExpression))
+ binding.key().type().java(), optionalKind.presentExpression(dependencyExpression))
: Expression.create(
- types.erasure(binding.key().type()),
+ types.erasure(binding.key().type().java()),
optionalKind.presentObjectExpression(dependencyExpression));
}
- @Override
- boolean requiresMethodEncapsulation() {
- // TODO(dpb): Maybe require it for present bindings.
- return false;
+ @AssistedFactory
+ static interface Factory {
+ OptionalRequestRepresentation create(ProvisionBinding binding);
}
}
diff --git a/java/dagger/internal/codegen/writing/PrivateMethodBindingExpression.java b/java/dagger/internal/codegen/writing/PrivateMethodRequestRepresentation.java
index b6502ea3f..1a828ba77 100644
--- a/java/dagger/internal/codegen/writing/PrivateMethodBindingExpression.java
+++ b/java/dagger/internal/codegen/writing/PrivateMethodRequestRepresentation.java
@@ -16,81 +16,98 @@
package dagger.internal.codegen.writing;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedParameterSpecs;
import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.PRIVATE_METHOD;
import static javax.lang.model.element.Modifier.PRIVATE;
-import com.google.common.collect.ImmutableList;
+import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.TypeName;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.BindingRequest;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingKind;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
+import dagger.spi.model.RequestKind;
+import javax.lang.model.type.TypeMirror;
/**
* A binding expression that wraps the dependency expressions in a private, no-arg method.
*
* <p>Dependents of this binding expression will just call the no-arg private method.
*/
-final class PrivateMethodBindingExpression extends MethodBindingExpression {
+final class PrivateMethodRequestRepresentation extends MethodRequestRepresentation {
+ private final ShardImplementation shardImplementation;
private final ContributionBinding binding;
private final BindingRequest request;
- private final ComponentImplementation componentImplementation;
+ private final RequestRepresentation wrappedRequestRepresentation;
private final CompilerOptions compilerOptions;
private final DaggerTypes types;
private String methodName;
- PrivateMethodBindingExpression(
- BindingRequest request,
- ContributionBinding binding,
- MethodImplementationStrategy methodImplementationStrategy,
- BindingExpression wrappedBindingExpression,
+ @AssistedInject
+ PrivateMethodRequestRepresentation(
+ @Assisted BindingRequest request,
+ @Assisted ContributionBinding binding,
+ @Assisted RequestRepresentation wrappedRequestRepresentation,
ComponentImplementation componentImplementation,
DaggerTypes types,
CompilerOptions compilerOptions) {
- super(
- request,
- binding,
- methodImplementationStrategy,
- wrappedBindingExpression,
- componentImplementation,
- types);
- this.binding = binding;
+ super(componentImplementation.shardImplementation(binding), types);
+ this.binding = checkNotNull(binding);
this.request = checkNotNull(request);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.compilerOptions = checkNotNull(compilerOptions);
+ this.wrappedRequestRepresentation = checkNotNull(wrappedRequestRepresentation);
+ this.shardImplementation = componentImplementation.shardImplementation(binding);
+ this.compilerOptions = compilerOptions;
this.types = types;
}
@Override
- protected void addMethod() {
+ protected CodeBlock methodCall() {
+ return CodeBlock.of("$N()", methodName());
+ }
+
+ @Override
+ protected TypeMirror returnType() {
+ if (request.isRequestKind(RequestKind.INSTANCE)
+ && binding.contributedPrimitiveType().isPresent()) {
+ return toJavac(binding.contributedPrimitiveType().get());
+ }
+
+ TypeMirror requestedType = request.requestedType(binding.contributedType(), types);
+ return types.accessibleType(requestedType, shardImplementation.name());
+ }
+
+ private String methodName() {
if (methodName == null) {
// Have to set methodName field before implementing the method in order to handle recursion.
- methodName = componentImplementation.getUniqueMethodName(request);
+ methodName = shardImplementation.getUniqueMethodName(request);
// TODO(bcorso): Fix the order that these generated methods are written to the component.
- componentImplementation.addMethod(
+ shardImplementation.addMethod(
PRIVATE_METHOD,
methodBuilder(methodName)
.addModifiers(PRIVATE)
- .addParameters(
- // Private methods for assisted injection take assisted parameters as input.
- binding.kind() == BindingKind.ASSISTED_INJECTION
- ? assistedParameterSpecs(binding, types)
- : ImmutableList.of())
.returns(TypeName.get(returnType()))
- .addCode(methodBody())
+ .addStatement(
+ "return $L",
+ wrappedRequestRepresentation
+ .getDependencyExpression(shardImplementation.name())
+ .codeBlock())
.build());
}
+ return methodName;
}
- @Override
- protected String methodName() {
- checkState(methodName != null, "addMethod() must be called before methodName()");
- return methodName;
+ @AssistedFactory
+ static interface Factory {
+ PrivateMethodRequestRepresentation create(
+ BindingRequest request,
+ ContributionBinding binding,
+ RequestRepresentation wrappedRequestRepresentation);
}
}
diff --git a/java/dagger/internal/codegen/writing/ProducerCreationExpression.java b/java/dagger/internal/codegen/writing/ProducerCreationExpression.java
index 0d1ccf3b8..8e8c27197 100644
--- a/java/dagger/internal/codegen/writing/ProducerCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/ProducerCreationExpression.java
@@ -20,7 +20,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
/**
@@ -30,13 +34,18 @@ import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstan
// TODO(dpb): Resolve with InjectionOrProvisionProviderCreationExpression.
final class ProducerCreationExpression implements FrameworkInstanceCreationExpression {
- private final ComponentBindingExpressions componentBindingExpressions;
+ private final ShardImplementation shardImplementation;
+ private final ComponentRequestRepresentations componentRequestRepresentations;
private final ContributionBinding binding;
+ @AssistedInject
ProducerCreationExpression(
- ContributionBinding binding, ComponentBindingExpressions componentBindingExpressions) {
+ @Assisted ContributionBinding binding,
+ ComponentImplementation componentImplementation,
+ ComponentRequestRepresentations componentRequestRepresentations) {
this.binding = checkNotNull(binding);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ this.shardImplementation = componentImplementation.shardImplementation(binding);
+ this.componentRequestRepresentations = checkNotNull(componentRequestRepresentations);
}
@Override
@@ -44,6 +53,12 @@ final class ProducerCreationExpression implements FrameworkInstanceCreationExpre
return CodeBlock.of(
"$T.create($L)",
generatedClassNameForBinding(binding),
- componentBindingExpressions.getCreateMethodArgumentsCodeBlock(binding));
+ componentRequestRepresentations.getCreateMethodArgumentsCodeBlock(
+ binding, shardImplementation.name()));
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ ProducerCreationExpression create(ContributionBinding binding);
}
}
diff --git a/java/dagger/internal/codegen/writing/ProducerEntryPointView.java b/java/dagger/internal/codegen/writing/ProducerEntryPointView.java
index c58f4e0bf..271da51e3 100644
--- a/java/dagger/internal/codegen/writing/ProducerEntryPointView.java
+++ b/java/dagger/internal/codegen/writing/ProducerEntryPointView.java
@@ -17,18 +17,22 @@
package dagger.internal.codegen.writing;
import static dagger.internal.codegen.writing.ComponentImplementation.FieldSpecKind.FRAMEWORK_FIELD;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import static javax.lang.model.element.Modifier.PRIVATE;
+import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.TypeName;
import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.RequestKind;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.producers.Producer;
import dagger.producers.internal.CancellationListener;
import dagger.producers.internal.Producers;
+import dagger.spi.model.RequestKind;
import java.util.Optional;
import javax.lang.model.type.TypeMirror;
@@ -37,9 +41,11 @@ import javax.lang.model.type.TypeMirror;
* views} of {@link Producer}s.
*/
final class ProducerEntryPointView {
+ private final ShardImplementation shardImplementation;
private final DaggerTypes types;
- ProducerEntryPointView(DaggerTypes types) {
+ ProducerEntryPointView(ShardImplementation shardImplementation, DaggerTypes types) {
+ this.shardImplementation = shardImplementation;
this.types = types;
}
@@ -49,22 +55,20 @@ final class ProducerEntryPointView {
* Producer} or {@link com.google.common.util.concurrent.ListenableFuture}.
*
* <p>This is intended to be a replacement implementation for {@link
- * dagger.internal.codegen.writing.BindingExpression#getDependencyExpressionForComponentMethod(ComponentMethodDescriptor,
+ * dagger.internal.codegen.writing.RequestRepresentation#getDependencyExpressionForComponentMethod(ComponentMethodDescriptor,
* ComponentImplementation)}, and in cases where {@link Optional#empty()} is returned, callers
* should call {@code super.getDependencyExpressionForComponentMethod()}.
*/
Optional<Expression> getProducerEntryPointField(
- BindingExpression producerExpression,
+ RequestRepresentation producerExpression,
ComponentMethodDescriptor componentMethod,
- ComponentImplementation component) {
- if (component.componentDescriptor().isProduction()
+ ClassName requestingClass) {
+ if (shardImplementation.componentDescriptor().isProduction()
&& (componentMethod.dependencyRequest().get().kind().equals(RequestKind.FUTURE)
|| componentMethod.dependencyRequest().get().kind().equals(RequestKind.PRODUCER))) {
+ MemberSelect field = createField(producerExpression, componentMethod);
return Optional.of(
- Expression.create(
- fieldType(componentMethod),
- "$N",
- createField(producerExpression, componentMethod, component)));
+ Expression.create(fieldType(componentMethod), field.getExpressionFor(requestingClass)));
} else {
// If the component isn't a production component, it won't implement CancellationListener and
// as such we can't create an entry point. But this binding must also just be a Producer from
@@ -75,36 +79,43 @@ final class ProducerEntryPointView {
}
}
- private FieldSpec createField(
- BindingExpression producerExpression,
- ComponentMethodDescriptor componentMethod,
- ComponentImplementation component) {
+ private MemberSelect createField(
+ RequestRepresentation producerExpression, ComponentMethodDescriptor componentMethod) {
// TODO(cgdecker): Use a FrameworkFieldInitializer for this?
// Though I don't think we need the once-only behavior of that, since I think
// getComponentMethodImplementation will only be called once anyway
- String methodName = componentMethod.methodElement().getSimpleName().toString();
+ String methodName = getSimpleName(componentMethod.methodElement());
FieldSpec field =
FieldSpec.builder(
TypeName.get(fieldType(componentMethod)),
- component.getUniqueFieldName(methodName + "EntryPoint"),
+ shardImplementation.getUniqueFieldName(methodName + "EntryPoint"),
PRIVATE)
.build();
- component.addField(FRAMEWORK_FIELD, field);
+ shardImplementation.addField(FRAMEWORK_FIELD, field);
CodeBlock fieldInitialization =
CodeBlock.of(
- "this.$N = $T.entryPointViewOf($L, this);",
+ "this.$N = $T.entryPointViewOf($L, $L);",
field,
Producers.class,
- producerExpression.getDependencyExpression(component.name()).codeBlock());
- component.addInitialization(fieldInitialization);
+ producerExpression.getDependencyExpression(shardImplementation.name()).codeBlock(),
+ // Always pass in the componentShard reference here rather than the owning shard for
+ // this key because this needs to be the root CancellationListener.
+ shardImplementation.isComponentShard()
+ ? "this"
+ : shardImplementation
+ .getComponentImplementation()
+ .getComponentShard()
+ .shardFieldReference());
+ shardImplementation.addInitialization(fieldInitialization);
- return field;
+ return MemberSelect.localField(shardImplementation, field.name);
}
// TODO(cgdecker): Can we use producerExpression.getDependencyExpression().type() instead of
// needing to (re)compute this?
private TypeMirror fieldType(ComponentMethodDescriptor componentMethod) {
- return types.wrapType(componentMethod.dependencyRequest().get().key().type(), Producer.class);
+ return types.wrapType(
+ componentMethod.dependencyRequest().get().key().type().java(), TypeNames.PRODUCER);
}
}
diff --git a/java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java b/java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java
index a013be940..1a92ba639 100644
--- a/java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java
+++ b/java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java
@@ -16,6 +16,7 @@
package dagger.internal.codegen.writing;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Verify.verifyNotNull;
import static com.squareup.javapoet.ClassName.OBJECT;
@@ -40,13 +41,16 @@ import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf;
import static dagger.internal.codegen.javapoet.TypeNames.producedOf;
import static dagger.internal.codegen.writing.GwtCompatibility.gwtIncompatibleAnnotation;
import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PROTECTED;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
-import com.google.common.collect.FluentIterable;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XType;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -70,21 +74,18 @@ import dagger.internal.codegen.javapoet.AnnotationSpecs;
import dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.RequestKind;
import dagger.producers.Producer;
import dagger.producers.internal.AbstractProducesMethodProducer;
import dagger.producers.internal.Producers;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.Key;
+import dagger.spi.model.RequestKind;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Optional;
-import javax.annotation.processing.Filer;
import javax.inject.Inject;
import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.type.TypeMirror;
/** Generates {@link Producer} implementations from {@link ProductionBinding} instances. */
public final class ProducerFactoryGenerator extends SourceFileGenerator<ProductionBinding> {
@@ -93,7 +94,7 @@ public final class ProducerFactoryGenerator extends SourceFileGenerator<Producti
@Inject
ProducerFactoryGenerator(
- Filer filer,
+ XFiler filer,
DaggerElements elements,
SourceVersion sourceVersion,
CompilerOptions compilerOptions,
@@ -103,9 +104,8 @@ public final class ProducerFactoryGenerator extends SourceFileGenerator<Producti
this.keyFactory = keyFactory;
}
-
@Override
- public Element originatingElement(ProductionBinding binding) {
+ public XElement originatingElement(ProductionBinding binding) {
// we only create factories for bindings that have a binding element
return binding.bindingElement().get();
}
@@ -116,7 +116,7 @@ public final class ProducerFactoryGenerator extends SourceFileGenerator<Producti
checkArgument(!binding.unresolved().isPresent());
checkArgument(binding.bindingElement().isPresent());
- TypeName providedTypeName = TypeName.get(binding.contributedType());
+ TypeName providedTypeName = binding.contributedType().getTypeName();
TypeName futureTypeName = listenableFutureOf(providedTypeName);
ClassName generatedTypeName = generatedClassNameForBinding(binding);
@@ -137,7 +137,7 @@ public final class ProducerFactoryGenerator extends SourceFileGenerator<Producti
factoryBuilder,
constructorBuilder,
uniqueFieldNames.getUniqueName("module"),
- TypeName.get(binding.bindingTypeElement().get().asType())))
+ binding.bindingTypeElement().get().getType().getTypeName()))
: Optional.empty();
List<CodeBlock> frameworkFieldAssignments = new ArrayList<>();
@@ -206,7 +206,7 @@ public final class ProducerFactoryGenerator extends SourceFileGenerator<Producti
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(futureTransform.applyArgType(), futureTransform.applyArgName())
- .addExceptions(getThrownTypeNames(binding.thrownTypes()))
+ .addExceptions(binding.thrownTypes().stream().map(XType::getTypeName).collect(toList()))
.addCode(
getInvocationCodeBlock(
binding, providedTypeName, futureTransform.parameterCodeBlocks()));
@@ -295,15 +295,15 @@ public final class ProducerFactoryGenerator extends SourceFileGenerator<Producti
"$S",
String.format(
"%s#%s",
- ClassName.get(binding.bindingTypeElement().get()),
- binding.bindingElement().get().getSimpleName()))
+ binding.bindingTypeElement().get().getClassName(),
+ toJavac(binding.bindingElement().get()).getSimpleName()))
: CodeBlock.of("$T.class", generatedTypeName);
return CodeBlock.of("$T.create($L)", PRODUCER_TOKEN, producerTokenArgs);
}
/** Returns a name of the variable representing this dependency's future. */
private static String dependencyFutureName(DependencyRequest dependency) {
- return dependency.requestElement().get().getSimpleName() + "Future";
+ return dependency.requestElement().get().java().getSimpleName() + "Future";
}
/** Represents the transformation of an input future by a producer method. */
@@ -405,7 +405,7 @@ public final class ProducerFactoryGenerator extends SourceFileGenerator<Producti
@Override
String applyArgName() {
- String argName = asyncDependency.requestElement().get().getSimpleName().toString();
+ String argName = asyncDependency.requestElement().get().java().getSimpleName().toString();
if (argName.equals("module")) {
return "moduleArg";
}
@@ -495,7 +495,7 @@ public final class ProducerFactoryGenerator extends SourceFileGenerator<Producti
}
private static TypeName asyncDependencyType(DependencyRequest dependency) {
- TypeName keyName = TypeName.get(dependency.key().type());
+ TypeName keyName = TypeName.get(dependency.key().type().java());
switch (dependency.kind()) {
case INSTANCE:
return keyName;
@@ -523,8 +523,8 @@ public final class ProducerFactoryGenerator extends SourceFileGenerator<Producti
"$L.$L($L)",
binding.requiresModuleInstance()
? "module"
- : CodeBlock.of("$T", ClassName.get(binding.bindingTypeElement().get())),
- binding.bindingElement().get().getSimpleName(),
+ : CodeBlock.of("$T", binding.bindingTypeElement().get().getClassName()),
+ toJavac(binding.bindingElement().get()).getSimpleName(),
makeParametersCodeBlock(parameterCodeBlocks));
final CodeBlock returnCodeBlock;
@@ -545,16 +545,6 @@ public final class ProducerFactoryGenerator extends SourceFileGenerator<Producti
return CodeBlock.of("return $L;", returnCodeBlock);
}
- /**
- * Converts the list of thrown types into type names.
- *
- * @param thrownTypes the list of thrown types.
- */
- private FluentIterable<? extends TypeName> getThrownTypeNames(
- Iterable<? extends TypeMirror> thrownTypes) {
- return FluentIterable.from(thrownTypes).transform(TypeName::get);
- }
-
@Override
protected ImmutableSet<Suppression> warningSuppressions() {
// TODO(beder): examine if we can remove this or prevent subtypes of Future from being produced
diff --git a/java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java b/java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java
index 9b0d4e8ba..d38561395 100644
--- a/java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java
@@ -16,43 +16,37 @@
package dagger.internal.codegen.writing;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.FrameworkType;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import dagger.model.RequestKind;
import dagger.producers.Producer;
+import dagger.spi.model.RequestKind;
import java.util.Optional;
/** An {@link Producer} creation expression for provision bindings. */
final class ProducerFromProviderCreationExpression implements FrameworkInstanceCreationExpression {
- private final ContributionBinding binding;
- private final ComponentImplementation componentImplementation;
- private final ComponentBindingExpressions componentBindingExpressions;
+ private final RequestRepresentation providerRequestRepresentation;
+ private final ClassName requestingClass;
+ @AssistedInject
ProducerFromProviderCreationExpression(
- ContributionBinding binding,
- ComponentImplementation componentImplementation,
- ComponentBindingExpressions componentBindingExpressions) {
- this.binding = checkNotNull(binding);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ @Assisted RequestRepresentation providerRequestRepresentation,
+ @Assisted ClassName requestingClass) {
+ this.providerRequestRepresentation = providerRequestRepresentation;
+ this.requestingClass = requestingClass;
}
@Override
public CodeBlock creationExpression() {
return FrameworkType.PROVIDER.to(
RequestKind.PRODUCER,
- componentBindingExpressions
- .getDependencyExpression(
- bindingRequest(binding.key(), FrameworkType.PROVIDER),
- componentImplementation.name())
- .codeBlock());
+ providerRequestRepresentation.getDependencyExpression(requestingClass).codeBlock());
}
@Override
@@ -60,5 +54,9 @@ final class ProducerFromProviderCreationExpression implements FrameworkInstanceC
return Optional.of(TypeNames.PRODUCER);
}
- // TODO(ronshapiro): should this have a simple factory if the delegate expression is simple?
+ @AssistedFactory
+ static interface Factory {
+ ProducerFromProviderCreationExpression create(
+ RequestRepresentation providerRequestRepresentation, ClassName requestingClass);
+ }
}
diff --git a/java/dagger/internal/codegen/writing/ProducerNodeInstanceBindingExpression.java b/java/dagger/internal/codegen/writing/ProducerNodeInstanceRequestRepresentation.java
index 0d3f7e876..dafb05245 100644
--- a/java/dagger/internal/codegen/writing/ProducerNodeInstanceBindingExpression.java
+++ b/java/dagger/internal/codegen/writing/ProducerNodeInstanceRequestRepresentation.java
@@ -16,34 +16,39 @@
package dagger.internal.codegen.writing;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.binding.FrameworkType;
import dagger.internal.codegen.javapoet.Expression;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
+import dagger.producers.internal.Producers;
+import dagger.spi.model.Key;
/** Binding expression for producer node instances. */
-final class ProducerNodeInstanceBindingExpression extends FrameworkInstanceBindingExpression {
- /** The component defining this binding. */
- private final ComponentImplementation componentImplementation;
+final class ProducerNodeInstanceRequestRepresentation
+ extends FrameworkInstanceRequestRepresentation {
+ private final ShardImplementation shardImplementation;
private final Key key;
private final ProducerEntryPointView producerEntryPointView;
- ProducerNodeInstanceBindingExpression(
- ContributionBinding binding,
- FrameworkInstanceSupplier frameworkInstanceSupplier,
+ @AssistedInject
+ ProducerNodeInstanceRequestRepresentation(
+ @Assisted ContributionBinding binding,
+ @Assisted FrameworkInstanceSupplier frameworkInstanceSupplier,
DaggerTypes types,
DaggerElements elements,
ComponentImplementation componentImplementation) {
super(binding, frameworkInstanceSupplier, types, elements);
- this.componentImplementation = checkNotNull(componentImplementation);
+ this.shardImplementation = componentImplementation.shardImplementation(binding);
this.key = binding.key();
- this.producerEntryPointView = new ProducerEntryPointView(types);
+ this.producerEntryPointView = new ProducerEntryPointView(shardImplementation, types);
}
@Override
@@ -54,7 +59,13 @@ final class ProducerNodeInstanceBindingExpression extends FrameworkInstanceBindi
@Override
Expression getDependencyExpression(ClassName requestingClass) {
Expression result = super.getDependencyExpression(requestingClass);
- componentImplementation.addCancellableProducerKey(key);
+ shardImplementation.addCancellation(
+ key,
+ CodeBlock.of(
+ "$T.cancel($L, $N);",
+ Producers.class,
+ result.codeBlock(),
+ ComponentImplementation.MAY_INTERRUPT_IF_RUNNING_PARAM));
return result;
}
@@ -62,8 +73,14 @@ final class ProducerNodeInstanceBindingExpression extends FrameworkInstanceBindi
Expression getDependencyExpressionForComponentMethod(
ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
return producerEntryPointView
- .getProducerEntryPointField(this, componentMethod, component)
+ .getProducerEntryPointField(this, componentMethod, component.name())
.orElseGet(
() -> super.getDependencyExpressionForComponentMethod(componentMethod, component));
}
+
+ @AssistedFactory
+ static interface Factory {
+ ProducerNodeInstanceRequestRepresentation create(
+ ContributionBinding binding, FrameworkInstanceSupplier frameworkInstanceSupplier);
+ }
}
diff --git a/java/dagger/internal/codegen/writing/ProductionBindingRepresentation.java b/java/dagger/internal/codegen/writing/ProductionBindingRepresentation.java
new file mode 100644
index 000000000..f2da69083
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/ProductionBindingRepresentation.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
+import static dagger.internal.codegen.writing.BindingRepresentations.scope;
+import static dagger.spi.model.BindingKind.MULTIBOUND_MAP;
+import static dagger.spi.model.BindingKind.MULTIBOUND_SET;
+
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.binding.BindingRequest;
+import dagger.internal.codegen.binding.FrameworkType;
+import dagger.internal.codegen.binding.ProductionBinding;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * A binding representation that wraps code generation methods that satisfy all kinds of request for
+ * that binding.
+ */
+final class ProductionBindingRepresentation implements BindingRepresentation {
+ private final ProductionBinding binding;
+ private final DerivedFromFrameworkInstanceRequestRepresentation.Factory
+ derivedFromFrameworkInstanceRequestRepresentationFactory;
+ private final RequestRepresentation frameworkInstanceRequestRepresentation;
+ private final Map<BindingRequest, RequestRepresentation> requestRepresentations = new HashMap<>();
+
+ @AssistedInject
+ ProductionBindingRepresentation(
+ @Assisted ProductionBinding binding,
+ ComponentImplementation componentImplementation,
+ DerivedFromFrameworkInstanceRequestRepresentation.Factory
+ derivedFromFrameworkInstanceRequestRepresentationFactory,
+ ProducerNodeInstanceRequestRepresentation.Factory
+ producerNodeInstanceRequestRepresentationFactory,
+ UnscopedFrameworkInstanceCreationExpressionFactory
+ unscopedFrameworkInstanceCreationExpressionFactory,
+ DaggerTypes types) {
+ this.binding = binding;
+ this.derivedFromFrameworkInstanceRequestRepresentationFactory =
+ derivedFromFrameworkInstanceRequestRepresentationFactory;
+ Optional<MemberSelect> staticMethod = staticFactoryCreation();
+ FrameworkInstanceSupplier frameworkInstanceSupplier =
+ staticMethod.isPresent()
+ ? staticMethod::get
+ : new FrameworkFieldInitializer(
+ componentImplementation,
+ binding,
+ binding.scope().isPresent()
+ ? scope(
+ binding, unscopedFrameworkInstanceCreationExpressionFactory.create(binding))
+ : unscopedFrameworkInstanceCreationExpressionFactory.create(binding));
+ this.frameworkInstanceRequestRepresentation =
+ producerNodeInstanceRequestRepresentationFactory.create(binding, frameworkInstanceSupplier);
+ }
+
+ @Override
+ public RequestRepresentation getRequestRepresentation(BindingRequest request) {
+ return reentrantComputeIfAbsent(
+ requestRepresentations, request, this::getRequestRepresentationUncached);
+ }
+
+ private RequestRepresentation getRequestRepresentationUncached(BindingRequest request) {
+ return request.frameworkType().isPresent()
+ ? frameworkInstanceRequestRepresentation
+ : derivedFromFrameworkInstanceRequestRepresentationFactory.create(
+ binding,
+ frameworkInstanceRequestRepresentation,
+ request.requestKind(),
+ FrameworkType.PRODUCER_NODE);
+ }
+ /**
+ * If {@code resolvedBindings} is an unscoped provision binding with no factory arguments, then we
+ * don't need a field to hold its factory. In that case, this method returns the static member
+ * select that returns the factory.
+ */
+ private Optional<MemberSelect> staticFactoryCreation() {
+ if (binding.dependencies().isEmpty()) {
+ if (binding.kind().equals(MULTIBOUND_MAP)) {
+ return Optional.of(StaticMemberSelects.emptyMapFactory(binding));
+ }
+ if (binding.kind().equals(MULTIBOUND_SET)) {
+ return Optional.of(StaticMemberSelects.emptySetFactory(binding));
+ }
+ }
+ return Optional.empty();
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ ProductionBindingRepresentation create(ProductionBinding binding);
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/ProviderInstanceBindingExpression.java b/java/dagger/internal/codegen/writing/ProviderInstanceRequestRepresentation.java
index 400c6a259..53c49d1de 100644
--- a/java/dagger/internal/codegen/writing/ProviderInstanceBindingExpression.java
+++ b/java/dagger/internal/codegen/writing/ProviderInstanceRequestRepresentation.java
@@ -16,28 +16,34 @@
package dagger.internal.codegen.writing;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.binding.FrameworkType;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
/** Binding expression for provider instances. */
-final class ProviderInstanceBindingExpression extends FrameworkInstanceBindingExpression {
+final class ProviderInstanceRequestRepresentation extends FrameworkInstanceRequestRepresentation {
- ProviderInstanceBindingExpression(
- ContributionBinding binding,
- FrameworkInstanceSupplier frameworkInstanceSupplier,
+ @AssistedInject
+ ProviderInstanceRequestRepresentation(
+ @Assisted ContributionBinding binding,
+ @Assisted FrameworkInstanceSupplier frameworkInstanceSupplier,
DaggerTypes types,
DaggerElements elements) {
- super(
- binding,
- frameworkInstanceSupplier,
- types,
- elements);
+ super(binding, frameworkInstanceSupplier, types, elements);
}
@Override
protected FrameworkType frameworkType() {
return FrameworkType.PROVIDER;
}
+
+ @AssistedFactory
+ static interface Factory {
+ ProviderInstanceRequestRepresentation create(
+ ContributionBinding binding, FrameworkInstanceSupplier frameworkInstanceSupplier);
+ }
}
diff --git a/java/dagger/internal/codegen/writing/ProviderInstanceSupplier.java b/java/dagger/internal/codegen/writing/ProviderInstanceSupplier.java
new file mode 100644
index 000000000..d95d4e2e6
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/ProviderInstanceSupplier.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static dagger.internal.codegen.writing.BindingRepresentations.scope;
+
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+
+/** An object that initializes a framework-type component field for a binding. */
+final class ProviderInstanceSupplier implements FrameworkInstanceSupplier {
+ private final FrameworkInstanceSupplier frameworkInstanceSupplier;
+
+ @AssistedInject
+ ProviderInstanceSupplier(
+ @Assisted ProvisionBinding binding,
+ ComponentImplementation componentImplementation,
+ FrameworkInstanceBindingRepresentation.Factory frameworkInstanceBindingRepresentationFactory,
+ UnscopedFrameworkInstanceCreationExpressionFactory
+ unscopedFrameworkInstanceCreationExpressionFactory) {
+ FrameworkInstanceCreationExpression frameworkInstanceCreationExpression =
+ unscopedFrameworkInstanceCreationExpressionFactory.create(binding);
+ this.frameworkInstanceSupplier =
+ new FrameworkFieldInitializer(
+ componentImplementation,
+ binding,
+ binding.scope().isPresent()
+ ? scope(binding, frameworkInstanceCreationExpression)
+ : frameworkInstanceCreationExpression);
+ }
+
+ @Override
+ public MemberSelect memberSelect() {
+ return frameworkInstanceSupplier.memberSelect();
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ ProviderInstanceSupplier create(ProvisionBinding binding);
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java b/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java
new file mode 100644
index 000000000..0085d32cf
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static dagger.internal.codegen.writing.DelegateRequestRepresentation.isBindsScopeStrongerThanDependencyScope;
+import static dagger.spi.model.BindingKind.DELEGATE;
+
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.binding.BindingGraph;
+import dagger.internal.codegen.binding.BindingRequest;
+import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.writing.ComponentImplementation.CompilerMode;
+import dagger.spi.model.RequestKind;
+
+/**
+ * A binding representation that wraps code generation methods that satisfy all kinds of request for
+ * that binding.
+ */
+final class ProvisionBindingRepresentation implements BindingRepresentation {
+ private final BindingGraph graph;
+ private final CompilerMode compilerMode;
+ private final ProvisionBinding binding;
+ private final DirectInstanceBindingRepresentation directInstanceBindingRepresentation;
+ private final FrameworkInstanceBindingRepresentation frameworkInstanceBindingRepresentation;
+
+ @AssistedInject
+ ProvisionBindingRepresentation(
+ @Assisted ProvisionBinding binding,
+ BindingGraph graph,
+ ComponentImplementation componentImplementation,
+ DirectInstanceBindingRepresentation.Factory directInstanceBindingRepresentationFactory,
+ FrameworkInstanceBindingRepresentation.Factory frameworkInstanceBindingRepresentationFactory,
+ SwitchingProviderInstanceSupplier.Factory switchingProviderInstanceSupplierFactory,
+ ProviderInstanceSupplier.Factory providerInstanceSupplierFactory,
+ StaticFactoryInstanceSupplier.Factory staticFactoryInstanceSupplierFactory,
+ CompilerOptions compilerOptions,
+ DaggerTypes types) {
+ this.binding = binding;
+ this.graph = graph;
+ this.compilerMode = componentImplementation.compilerMode();
+ this.directInstanceBindingRepresentation =
+ directInstanceBindingRepresentationFactory.create(binding);
+ FrameworkInstanceSupplier frameworkInstanceSupplier = null;
+ switch (FrameworkInstanceKind.from(binding, compilerMode)) {
+ case SWITCHING_PROVIDER:
+ case EXPERIMENTAL_SWITCHING_PROVIDER:
+ frameworkInstanceSupplier = switchingProviderInstanceSupplierFactory.create(binding);
+ break;
+ case STATIC_FACTORY:
+ frameworkInstanceSupplier = staticFactoryInstanceSupplierFactory.create(binding);
+ break;
+ case PROVIDER_FIELD:
+ frameworkInstanceSupplier = providerInstanceSupplierFactory.create(binding);
+ break;
+ }
+ this.frameworkInstanceBindingRepresentation =
+ frameworkInstanceBindingRepresentationFactory.create(binding, frameworkInstanceSupplier);
+ }
+
+ @Override
+ public RequestRepresentation getRequestRepresentation(BindingRequest request) {
+ return usesDirectInstanceExpression(request.requestKind())
+ ? directInstanceBindingRepresentation.getRequestRepresentation(request)
+ : frameworkInstanceBindingRepresentation.getRequestRepresentation(request);
+ }
+
+ private boolean usesDirectInstanceExpression(RequestKind requestKind) {
+ if (compilerMode.isExperimentalMergedMode()) {
+ return false;
+ }
+ if (requestKind != RequestKind.INSTANCE && requestKind != RequestKind.FUTURE) {
+ return false;
+ }
+
+ // In fast init mode, we can avoid generating direct instance expressions if a framework
+ // instance expression already exists in the graph. Default mode has more edge cases, so can not
+ // be handled with simple pre-check in the graph. For example, a provider for a subcomponent
+ // builder is backed with its direct instance, returning framework instance for both cases will
+ // form a loop. There are also difficulties introduced by manually created framework requests.
+ // TODO(wanyingd): refactor framework instance so that we don't need to generate both direct
+ // instance and framework instance representation for the same binding.
+ if (compilerMode.isFastInit() && graph.topLevelBindingGraph().hasFrameworkRequest(binding)) {
+ return false;
+ }
+
+ switch (binding.kind()) {
+ case MEMBERS_INJECTOR:
+ // Currently, we always use a framework instance for MembersInjectors, e.g.
+ // InstanceFactory.create(Foo_MembersInjector.create(...)).
+ // TODO(b/199889259): Consider optimizing this for fastInit mode.
+ case ASSISTED_FACTORY:
+ // Assisted factory binding can be requested with framework request, and it is essentially a
+ // provider for assisted injection binding. So we will always return framework instance for
+ // assisted factory bindings.
+ return false;
+ case ASSISTED_INJECTION:
+ throw new IllegalStateException(
+ "Assisted injection binding shouldn't be requested with an instance request.");
+ default:
+ // We don't need to use Provider#get() if there's no caching, so use a direct instance.
+ // TODO(bcorso): This can be optimized in cases where we know a Provider field already
+ // exists, in which case even if it's not scoped we might as well call Provider#get().
+ return !needsCaching(binding, graph);
+ }
+ }
+
+ /**
+ * Returns {@code true} if the component needs to make sure the provided value is cached.
+ *
+ * <p>The component needs to cache the value for scoped bindings except for {@code @Binds}
+ * bindings whose scope is no stronger than their delegate's.
+ */
+ static boolean needsCaching(ProvisionBinding binding, BindingGraph graph) {
+ if (!binding.scope().isPresent()) {
+ return false;
+ }
+ if (binding.kind().equals(DELEGATE)) {
+ return isBindsScopeStrongerThanDependencyScope(binding, graph);
+ }
+ return true;
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ ProvisionBindingRepresentation create(ProvisionBinding binding);
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/BindingExpression.java b/java/dagger/internal/codegen/writing/RequestRepresentation.java
index bd45f603e..66c31dc62 100644
--- a/java/dagger/internal/codegen/writing/BindingExpression.java
+++ b/java/dagger/internal/codegen/writing/RequestRepresentation.java
@@ -23,7 +23,7 @@ import dagger.internal.codegen.javapoet.Expression;
/** A factory of code expressions used to access a single request for a binding in a component. */
// TODO(bcorso): Rename this to RequestExpression?
-abstract class BindingExpression {
+abstract class RequestRepresentation {
/**
* Returns an expression that evaluates to the value of a request based on the given requesting
@@ -43,11 +43,6 @@ abstract class BindingExpression {
return getDependencyExpression(component.name());
}
- /** Returns {@code true} if this binding expression should be encapsulated in a method. */
- boolean requiresMethodEncapsulation() {
- return false;
- }
-
/**
* Returns an expression for the implementation of a component method with the given request.
*
diff --git a/java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java b/java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java
index 754f909ad..624a41269 100644
--- a/java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java
@@ -20,27 +20,31 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static dagger.internal.codegen.binding.SourceFiles.setFactoryClassName;
import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.base.ContributionType;
import dagger.internal.codegen.base.SetType;
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.BindingType;
import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.model.DependencyRequest;
-import dagger.producers.Produced;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.spi.model.DependencyRequest;
/** A factory creation expression for a multibound set. */
final class SetFactoryCreationExpression extends MultibindingFactoryCreationExpression {
private final BindingGraph graph;
private final ContributionBinding binding;
+ @AssistedInject
SetFactoryCreationExpression(
- ContributionBinding binding,
+ @Assisted ContributionBinding binding,
ComponentImplementation componentImplementation,
- ComponentBindingExpressions componentBindingExpressions,
+ ComponentRequestRepresentations componentRequestRepresentations,
BindingGraph graph) {
- super(binding, componentImplementation, componentBindingExpressions);
+ super(binding, componentImplementation, componentRequestRepresentations);
this.binding = checkNotNull(binding);
- this.graph = checkNotNull(graph);
+ this.graph = graph;
}
@Override
@@ -50,9 +54,9 @@ final class SetFactoryCreationExpression extends MultibindingFactoryCreationExpr
SetType setType = SetType.from(binding.key());
builder.add(
"<$T>",
- setType.elementsAreTypeOf(Produced.class)
- ? setType.unwrappedElementType(Produced.class)
- : setType.elementType());
+ setType.elementsAreTypeOf(TypeNames.PRODUCED)
+ ? setType.unwrappedElementType(TypeNames.PRODUCED).getTypeName()
+ : setType.elementType().getTypeName());
}
int individualProviders = 0;
@@ -89,4 +93,9 @@ final class SetFactoryCreationExpression extends MultibindingFactoryCreationExpr
return builder.add(".build()").build();
}
+
+ @AssistedFactory
+ static interface Factory {
+ SetFactoryCreationExpression create(ContributionBinding binding);
+ }
}
diff --git a/java/dagger/internal/codegen/writing/SetBindingExpression.java b/java/dagger/internal/codegen/writing/SetRequestRepresentation.java
index 0b2e11a9a..7fec86aee 100644
--- a/java/dagger/internal/codegen/writing/SetBindingExpression.java
+++ b/java/dagger/internal/codegen/writing/SetRequestRepresentation.java
@@ -16,48 +16,58 @@
package dagger.internal.codegen.writing;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
import static javax.lang.model.util.ElementFilter.methodsIn;
+import androidx.room.compiler.processing.XType;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.SetBuilder;
import dagger.internal.codegen.base.ContributionType;
import dagger.internal.codegen.base.SetType;
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.javapoet.CodeBlocks;
import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
+import dagger.spi.model.DependencyRequest;
import java.util.Collections;
import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
/** A binding expression for multibound sets. */
-final class SetBindingExpression extends SimpleInvocationBindingExpression {
+final class SetRequestRepresentation extends RequestRepresentation {
private final ProvisionBinding binding;
private final BindingGraph graph;
- private final ComponentBindingExpressions componentBindingExpressions;
+ private final ComponentRequestRepresentations componentRequestRepresentations;
private final DaggerTypes types;
private final DaggerElements elements;
+ private final boolean isExperimentalMergedMode;
- SetBindingExpression(
- ProvisionBinding binding,
+ @AssistedInject
+ SetRequestRepresentation(
+ @Assisted ProvisionBinding binding,
BindingGraph graph,
- ComponentBindingExpressions componentBindingExpressions,
+ ComponentImplementation componentImplementation,
+ ComponentRequestRepresentations componentRequestRepresentations,
DaggerTypes types,
DaggerElements elements) {
- super(binding);
this.binding = binding;
this.graph = graph;
- this.componentBindingExpressions = componentBindingExpressions;
+ this.componentRequestRepresentations = componentRequestRepresentations;
this.types = types;
this.elements = elements;
+ this.isExperimentalMergedMode =
+ componentImplementation.compilerMode().isExperimentalMergedMode();
}
@Override
@@ -120,27 +130,48 @@ final class SetBindingExpression extends SimpleInvocationBindingExpression {
}
instantiation.add(".build()");
return Expression.create(
- isImmutableSetAvailable ? immutableSetType() : binding.key().type(),
+ isImmutableSetAvailable ? immutableSetType() : binding.key().type().java(),
instantiation.build());
}
}
private DeclaredType immutableSetType() {
return types.getDeclaredType(
- elements.getTypeElement(ImmutableSet.class), SetType.from(binding.key()).elementType());
+ elements.getTypeElement(TypeNames.IMMUTABLE_SET),
+ toJavac(SetType.from(binding.key()).elementType()));
}
private CodeBlock getContributionExpression(
DependencyRequest dependency, ClassName requestingClass) {
- return componentBindingExpressions
- .getDependencyExpression(bindingRequest(dependency), requestingClass)
- .codeBlock();
+ RequestRepresentation bindingExpression =
+ componentRequestRepresentations.getRequestRepresentation(bindingRequest(dependency));
+ CodeBlock expression =
+ isExperimentalMergedMode
+ ? componentRequestRepresentations
+ .getExperimentalSwitchingProviderDependencyRepresentation(
+ bindingRequest(dependency))
+ .getDependencyExpression(dependency.kind(), binding)
+ .codeBlock()
+ : bindingExpression.getDependencyExpression(requestingClass).codeBlock();
+
+ // TODO(b/211774331): Type casting should be Set after contributions to Set multibinding are
+ // limited to be Set.
+ // Add a cast to "(Collection)" when the contribution is a raw "Provider" type because the
+ // "addAll()" method expects a collection. For example, ".addAll((Collection)
+ // provideInaccessibleSetOfFoo.get())"
+ return (!isSingleValue(dependency)
+ && !isTypeAccessibleFrom(binding.key().type().java(), requestingClass.packageName())
+ // TODO(wanyingd): Replace instanceof checks with validation on the binding.
+ && (bindingExpression instanceof DerivedFromFrameworkInstanceRequestRepresentation
+ || bindingExpression instanceof DelegateRequestRepresentation))
+ ? CodeBlocks.cast(expression, TypeNames.COLLECTION)
+ : expression;
}
private Expression collectionsStaticFactoryInvocation(
ClassName requestingClass, CodeBlock methodInvocation) {
return Expression.create(
- binding.key().type(),
+ binding.key().type().java(),
CodeBlock.builder()
.add("$T.", Collections.class)
.add(maybeTypeParameter(requestingClass))
@@ -149,9 +180,9 @@ final class SetBindingExpression extends SimpleInvocationBindingExpression {
}
private CodeBlock maybeTypeParameter(ClassName requestingClass) {
- TypeMirror elementType = SetType.from(binding.key()).elementType();
- return isTypeAccessibleFrom(elementType, requestingClass.packageName())
- ? CodeBlock.of("<$T>", elementType)
+ XType elementType = SetType.from(binding.key()).elementType();
+ return isTypeAccessibleFrom(toJavac(elementType), requestingClass.packageName())
+ ? CodeBlock.of("<$T>", elementType.getTypeName())
: CodeBlock.of("");
}
@@ -163,7 +194,7 @@ final class SetBindingExpression extends SimpleInvocationBindingExpression {
private boolean isImmutableSetBuilderWithExpectedSizeAvailable() {
if (isImmutableSetAvailable()) {
- return methodsIn(elements.getTypeElement(ImmutableSet.class).getEnclosedElements())
+ return methodsIn(elements.getTypeElement(TypeNames.IMMUTABLE_SET).getEnclosedElements())
.stream()
.anyMatch(method -> method.getSimpleName().contentEquals("builderWithExpectedSize"));
}
@@ -171,6 +202,11 @@ final class SetBindingExpression extends SimpleInvocationBindingExpression {
}
private boolean isImmutableSetAvailable() {
- return elements.getTypeElement(ImmutableSet.class) != null;
+ return elements.getTypeElement(TypeNames.IMMUTABLE_SET) != null;
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ SetRequestRepresentation create(ProvisionBinding binding);
}
}
diff --git a/java/dagger/internal/codegen/writing/SimpleInvocationBindingExpression.java b/java/dagger/internal/codegen/writing/SimpleInvocationBindingExpression.java
deleted file mode 100644
index f2062f4e8..000000000
--- a/java/dagger/internal/codegen/writing/SimpleInvocationBindingExpression.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2016 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import dagger.internal.codegen.binding.ContributionBinding;
-
-/** A simple binding expression for instance requests. Does not scope. */
-abstract class SimpleInvocationBindingExpression extends BindingExpression {
- private final ContributionBinding binding;
-
- SimpleInvocationBindingExpression(ContributionBinding binding) {
- this.binding = checkNotNull(binding);
- }
-
- @Override
- boolean requiresMethodEncapsulation() {
- return !binding.dependencies().isEmpty();
- }
-}
diff --git a/java/dagger/internal/codegen/writing/SimpleMethodBindingExpression.java b/java/dagger/internal/codegen/writing/SimpleMethodRequestRepresentation.java
index 82e662857..20c6ac6cb 100644
--- a/java/dagger/internal/codegen/writing/SimpleMethodBindingExpression.java
+++ b/java/dagger/internal/codegen/writing/SimpleMethodRequestRepresentation.java
@@ -16,58 +16,64 @@
package dagger.internal.codegen.writing;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.auto.common.MoreElements.asExecutable;
import static com.google.auto.common.MoreElements.asType;
import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
import static dagger.internal.codegen.javapoet.TypeNames.rawTypeName;
import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
import static dagger.internal.codegen.writing.InjectionMethods.ProvisionMethod.requiresInjectionMethod;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.common.MoreTypes;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.ComponentRequirement;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.javapoet.Expression;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.internal.codegen.writing.InjectionMethods.ProvisionMethod;
-import dagger.model.DependencyRequest;
+import dagger.spi.model.DependencyRequest;
import java.util.Optional;
import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
/**
* A binding expression that invokes methods or constructors directly (without attempting to scope)
- * {@link dagger.model.RequestKind#INSTANCE} requests.
+ * {@link dagger.spi.model.RequestKind#INSTANCE} requests.
*/
-final class SimpleMethodBindingExpression extends SimpleInvocationBindingExpression {
+final class SimpleMethodRequestRepresentation extends RequestRepresentation {
private final CompilerOptions compilerOptions;
private final ProvisionBinding provisionBinding;
- private final ComponentBindingExpressions componentBindingExpressions;
+ private final ComponentRequestRepresentations componentRequestRepresentations;
private final MembersInjectionMethods membersInjectionMethods;
private final ComponentRequirementExpressions componentRequirementExpressions;
- private final DaggerElements elements;
private final SourceVersion sourceVersion;
private final KotlinMetadataUtil metadataUtil;
+ private final ShardImplementation shardImplementation;
+ private final boolean isExperimentalMergedMode;
- SimpleMethodBindingExpression(
- ProvisionBinding binding,
- CompilerOptions compilerOptions,
- ComponentBindingExpressions componentBindingExpressions,
+ @AssistedInject
+ SimpleMethodRequestRepresentation(
+ @Assisted ProvisionBinding binding,
MembersInjectionMethods membersInjectionMethods,
+ CompilerOptions compilerOptions,
+ ComponentRequestRepresentations componentRequestRepresentations,
ComponentRequirementExpressions componentRequirementExpressions,
- DaggerElements elements,
SourceVersion sourceVersion,
- KotlinMetadataUtil metadataUtil) {
- super(binding);
+ KotlinMetadataUtil metadataUtil,
+ ComponentImplementation componentImplementation,
+ ExperimentalSwitchingProviders switchingProviders) {
this.compilerOptions = compilerOptions;
this.provisionBinding = binding;
this.metadataUtil = metadataUtil;
@@ -75,11 +81,13 @@ final class SimpleMethodBindingExpression extends SimpleInvocationBindingExpress
provisionBinding.implicitDependencies().isEmpty(),
"framework deps are not currently supported");
checkArgument(provisionBinding.bindingElement().isPresent());
- this.componentBindingExpressions = componentBindingExpressions;
+ this.componentRequestRepresentations = componentRequestRepresentations;
this.membersInjectionMethods = membersInjectionMethods;
this.componentRequirementExpressions = componentRequirementExpressions;
- this.elements = elements;
this.sourceVersion = sourceVersion;
+ this.shardImplementation = componentImplementation.shardImplementation(binding);
+ this.isExperimentalMergedMode =
+ componentImplementation.compilerMode().isExperimentalMergedMode();
}
@Override
@@ -96,8 +104,8 @@ final class SimpleMethodBindingExpression extends SimpleInvocationBindingExpress
ProvisionMethod.invokeArguments(
provisionBinding,
request -> dependencyArgument(request, requestingClass).codeBlock(),
- requestingClass));
- ExecutableElement method = asExecutable(provisionBinding.bindingElement().get());
+ shardImplementation::getUniqueFieldNameForAssistedParam));
+ ExecutableElement method = asExecutable(toJavac(provisionBinding.bindingElement().get()));
CodeBlock invocation;
switch (method.getKind()) {
case CONSTRUCTOR:
@@ -111,9 +119,11 @@ final class SimpleMethodBindingExpression extends SimpleInvocationBindingExpress
} else if (metadataUtil.isObjectClass(asType(method.getEnclosingElement()))) {
// Call through the singleton instance.
// See: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#static-methods
- module = CodeBlock.of("$T.INSTANCE", provisionBinding.bindingTypeElement().get());
+ module =
+ CodeBlock.of(
+ "$T.INSTANCE", provisionBinding.bindingTypeElement().get().getClassName());
} else {
- module = CodeBlock.of("$T", provisionBinding.bindingTypeElement().get());
+ module = CodeBlock.of("$T", provisionBinding.bindingTypeElement().get().getClassName());
}
invocation = CodeBlock.of("$L.$L($L)", module, method.getSimpleName(), arguments);
break;
@@ -125,7 +135,7 @@ final class SimpleMethodBindingExpression extends SimpleInvocationBindingExpress
}
private TypeName constructorTypeName(ClassName requestingClass) {
- DeclaredType type = MoreTypes.asDeclared(provisionBinding.key().type());
+ DeclaredType type = MoreTypes.asDeclared(provisionBinding.key().type().java());
TypeName typeName = TypeName.get(type);
if (type.getTypeArguments().stream()
.allMatch(t -> isTypeAccessibleFrom(t, requestingClass.packageName()))) {
@@ -139,17 +149,24 @@ final class SimpleMethodBindingExpression extends SimpleInvocationBindingExpress
ProvisionMethod.invoke(
provisionBinding,
request -> dependencyArgument(request, requestingClass).codeBlock(),
+ shardImplementation::getUniqueFieldNameForAssistedParam,
requestingClass,
moduleReference(requestingClass),
compilerOptions,
- metadataUtil));
+ metadataUtil),
+ requestingClass);
}
private Expression dependencyArgument(DependencyRequest dependency, ClassName requestingClass) {
- return componentBindingExpressions.getDependencyArgumentExpression(dependency, requestingClass);
+ return isExperimentalMergedMode
+ ? componentRequestRepresentations
+ .getExperimentalSwitchingProviderDependencyRepresentation(bindingRequest(dependency))
+ .getDependencyExpression(dependency.kind(), provisionBinding)
+ : componentRequestRepresentations.getDependencyArgumentExpression(
+ dependency, requestingClass);
}
- private Expression injectMembers(CodeBlock instance) {
+ private Expression injectMembers(CodeBlock instance, ClassName requestingClass) {
if (provisionBinding.injectionSites().isEmpty()) {
return Expression.create(simpleMethodReturnType(), instance);
}
@@ -157,30 +174,42 @@ final class SimpleMethodBindingExpression extends SimpleInvocationBindingExpress
// Java 7 type inference can't figure out that instance in
// injectParameterized(Parameterized_Factory.newParameterized()) is Parameterized<T> and not
// Parameterized<Object>
- if (!MoreTypes.asDeclared(provisionBinding.key().type()).getTypeArguments().isEmpty()) {
- TypeName keyType = TypeName.get(provisionBinding.key().type());
+ if (!MoreTypes.asDeclared(provisionBinding.key().type().java())
+ .getTypeArguments()
+ .isEmpty()) {
+ TypeName keyType = TypeName.get(provisionBinding.key().type().java());
instance = CodeBlock.of("($T) ($T) $L", keyType, rawTypeName(keyType), instance);
}
}
- MethodSpec membersInjectionMethod = membersInjectionMethods.getOrCreate(provisionBinding.key());
- TypeMirror returnType =
- membersInjectionMethod.returnType.equals(TypeName.OBJECT)
- ? elements.getTypeElement(Object.class).asType()
- : provisionBinding.key().type();
- return Expression.create(returnType, CodeBlock.of("$N($L)", membersInjectionMethod, instance));
+ return isExperimentalMergedMode
+ ? membersInjectionMethods.getInjectExpressionExperimental(
+ provisionBinding, instance, requestingClass)
+ : membersInjectionMethods.getInjectExpression(
+ provisionBinding.key(), instance, requestingClass);
}
private Optional<CodeBlock> moduleReference(ClassName requestingClass) {
return provisionBinding.requiresModuleInstance()
? provisionBinding
.contributingModule()
- .map(Element::asType)
+ .map(XTypeElement::getType)
.map(ComponentRequirement::forModule)
- .map(module -> componentRequirementExpressions.getExpression(module, requestingClass))
+ .map(
+ module ->
+ isExperimentalMergedMode
+ ? CodeBlock.of("(($T) dependencies[0])", module.type().getTypeName())
+ : componentRequirementExpressions.getExpression(module, requestingClass))
: Optional.empty();
}
- private TypeMirror simpleMethodReturnType() {
- return provisionBinding.contributedPrimitiveType().orElse(provisionBinding.key().type());
+ private XType simpleMethodReturnType() {
+ return provisionBinding
+ .contributedPrimitiveType()
+ .orElse(provisionBinding.key().type().xprocessing());
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ SimpleMethodRequestRepresentation create(ProvisionBinding binding);
}
}
diff --git a/java/dagger/internal/codegen/writing/StaticFactoryInstanceSupplier.java b/java/dagger/internal/codegen/writing/StaticFactoryInstanceSupplier.java
new file mode 100644
index 000000000..5537c8f3c
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/StaticFactoryInstanceSupplier.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static dagger.spi.model.BindingKind.MULTIBOUND_MAP;
+import static dagger.spi.model.BindingKind.MULTIBOUND_SET;
+
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.binding.ContributionBinding;
+
+/** An object that returns static factory to satisfy framework instance request. */
+final class StaticFactoryInstanceSupplier implements FrameworkInstanceSupplier {
+ private final FrameworkInstanceSupplier frameworkInstanceSupplier;
+
+ @AssistedInject
+ StaticFactoryInstanceSupplier(
+ @Assisted ContributionBinding binding,
+ FrameworkInstanceBindingRepresentation.Factory
+ frameworkInstanceBindingRepresentationFactory) {
+ this.frameworkInstanceSupplier = () -> staticFactoryCreation(binding);
+ }
+
+ @Override
+ public MemberSelect memberSelect() {
+ return frameworkInstanceSupplier.memberSelect();
+ }
+
+ // TODO(wanyingd): no-op members injector is currently handled in
+ // `MembersInjectorProviderCreationExpression`, we should inline the logic here so we won't create
+ // an extra field for it.
+ private MemberSelect staticFactoryCreation(ContributionBinding binding) {
+ switch (binding.kind()) {
+ case MULTIBOUND_MAP:
+ return StaticMemberSelects.emptyMapFactory(binding);
+ case MULTIBOUND_SET:
+ return StaticMemberSelects.emptySetFactory(binding);
+ case PROVISION:
+ case INJECTION:
+ return StaticMemberSelects.factoryCreateNoArgumentMethod(binding);
+ default:
+ throw new AssertionError(String.format("Invalid binding kind: %s", binding.kind()));
+ }
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ StaticFactoryInstanceSupplier create(ContributionBinding binding);
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/StaticMemberSelects.java b/java/dagger/internal/codegen/writing/StaticMemberSelects.java
new file mode 100644
index 000000000..e547ab5c6
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/StaticMemberSelects.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.binding.SourceFiles.bindingTypeElementTypeVariableNames;
+import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
+import static dagger.internal.codegen.binding.SourceFiles.setFactoryClassName;
+import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
+import static dagger.internal.codegen.javapoet.TypeNames.FACTORY;
+import static dagger.internal.codegen.javapoet.TypeNames.MAP_FACTORY;
+import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER;
+import static dagger.internal.codegen.javapoet.TypeNames.PRODUCERS;
+import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER;
+import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+import static javax.lang.model.type.TypeKind.DECLARED;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableList;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.TypeVariableName;
+import dagger.internal.codegen.base.SetType;
+import dagger.internal.codegen.binding.Binding;
+import dagger.internal.codegen.binding.BindingType;
+import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.javapoet.CodeBlocks;
+import java.util.List;
+import javax.lang.model.type.TypeMirror;
+
+/** Helper class for static member select creation. */
+final class StaticMemberSelects {
+ /** A {@link MemberSelect} for a factory of an empty map. */
+ static MemberSelect emptyMapFactory(Binding binding) {
+ BindingType bindingType = binding.bindingType();
+ ImmutableList<TypeMirror> typeParameters =
+ ImmutableList.copyOf(MoreTypes.asDeclared(binding.key().type().java()).getTypeArguments());
+ if (bindingType.equals(BindingType.PRODUCTION)) {
+ return new ParameterizedStaticMethod(
+ PRODUCERS, typeParameters, CodeBlock.of("emptyMapProducer()"), PRODUCER);
+ } else {
+ return new ParameterizedStaticMethod(
+ MAP_FACTORY, typeParameters, CodeBlock.of("emptyMapProvider()"), PROVIDER);
+ }
+ }
+
+ /**
+ * A static member select for an empty set factory. Calls {@link
+ * dagger.internal.SetFactory#empty()}, {@link dagger.producers.internal.SetProducer#empty()}, or
+ * {@link dagger.producers.internal.SetOfProducedProducer#empty()}, depending on the set bindings.
+ */
+ static MemberSelect emptySetFactory(ContributionBinding binding) {
+ return new ParameterizedStaticMethod(
+ setFactoryClassName(binding),
+ ImmutableList.of(toJavac(SetType.from(binding.key()).elementType())),
+ CodeBlock.of("empty()"),
+ FACTORY);
+ }
+
+ /**
+ * Returns a {@link MemberSelect} for the instance of a {@code create()} method on a factory with
+ * no arguments.
+ */
+ static MemberSelect factoryCreateNoArgumentMethod(Binding binding) {
+ checkArgument(
+ binding.bindingType().equals(BindingType.PROVISION),
+ "Invalid binding type: %s",
+ binding.bindingType());
+ checkArgument(
+ binding.dependencies().isEmpty() && !binding.scope().isPresent(),
+ "%s should have no dependencies and be unscoped to create a no argument factory.",
+ binding);
+
+ ClassName factoryName = generatedClassNameForBinding(binding);
+ TypeMirror keyType = binding.key().type().java();
+ if (keyType.getKind().equals(DECLARED)) {
+ ImmutableList<TypeVariableName> typeVariables = bindingTypeElementTypeVariableNames(binding);
+ if (!typeVariables.isEmpty()) {
+ List<? extends TypeMirror> typeArguments = MoreTypes.asDeclared(keyType).getTypeArguments();
+ return new ParameterizedStaticMethod(
+ factoryName, ImmutableList.copyOf(typeArguments), CodeBlock.of("create()"), FACTORY);
+ }
+ }
+ return new StaticMethod(factoryName, CodeBlock.of("create()"));
+ }
+
+ private static final class StaticMethod extends MemberSelect {
+ private final CodeBlock methodCodeBlock;
+
+ StaticMethod(ClassName owningClass, CodeBlock methodCodeBlock) {
+ super(owningClass, true);
+ this.methodCodeBlock = checkNotNull(methodCodeBlock);
+ }
+
+ @Override
+ CodeBlock getExpressionFor(ClassName usingClass) {
+ return owningClass().equals(usingClass)
+ ? methodCodeBlock
+ : CodeBlock.of("$T.$L", owningClass(), methodCodeBlock);
+ }
+ }
+
+ private static final class ParameterizedStaticMethod extends MemberSelect {
+ private final ImmutableList<TypeMirror> typeParameters;
+ private final CodeBlock methodCodeBlock;
+ private final ClassName rawReturnType;
+
+ ParameterizedStaticMethod(
+ ClassName owningClass,
+ ImmutableList<TypeMirror> typeParameters,
+ CodeBlock methodCodeBlock,
+ ClassName rawReturnType) {
+ super(owningClass, true);
+ this.typeParameters = typeParameters;
+ this.methodCodeBlock = methodCodeBlock;
+ this.rawReturnType = rawReturnType;
+ }
+
+ @Override
+ CodeBlock getExpressionFor(ClassName usingClass) {
+ boolean accessible = true;
+ for (TypeMirror typeParameter : typeParameters) {
+ accessible &= isTypeAccessibleFrom(typeParameter, usingClass.packageName());
+ }
+
+ if (accessible) {
+ return CodeBlock.of(
+ "$T.<$L>$L",
+ owningClass(),
+ typeParameters.stream().map(CodeBlocks::type).collect(toParametersCodeBlock()),
+ methodCodeBlock);
+ } else {
+ return CodeBlock.of("(($T) $T.$L)", rawReturnType, owningClass(), methodCodeBlock);
+ }
+ }
+ }
+
+ private StaticMemberSelects() {}
+}
diff --git a/java/dagger/internal/codegen/writing/SubcomponentCreatorBindingExpression.java b/java/dagger/internal/codegen/writing/SubcomponentCreatorBindingExpression.java
deleted file mode 100644
index 3099048e6..000000000
--- a/java/dagger/internal/codegen/writing/SubcomponentCreatorBindingExpression.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import com.squareup.javapoet.ClassName;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.javapoet.Expression;
-import javax.lang.model.type.TypeMirror;
-
-/** A binding expression for a subcomponent creator that just invokes the constructor. */
-final class SubcomponentCreatorBindingExpression extends SimpleInvocationBindingExpression {
- private final TypeMirror creatorType;
- private final String creatorImplementationName;
-
- SubcomponentCreatorBindingExpression(
- ContributionBinding binding, String creatorImplementationName) {
- super(binding);
- this.creatorType = binding.key().type();
- this.creatorImplementationName = creatorImplementationName;
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- return Expression.create(creatorType, "new $L()", creatorImplementationName);
- }
-}
diff --git a/java/dagger/internal/codegen/writing/SubcomponentCreatorRequestRepresentation.java b/java/dagger/internal/codegen/writing/SubcomponentCreatorRequestRepresentation.java
new file mode 100644
index 000000000..74ebbad38
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/SubcomponentCreatorRequestRepresentation.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
+import java.util.ArrayList;
+import java.util.List;
+
+/** A binding expression for a subcomponent creator that just invokes the constructor. */
+final class SubcomponentCreatorRequestRepresentation extends RequestRepresentation {
+ private final ShardImplementation shardImplementation;
+ private final ContributionBinding binding;
+ private final boolean isExperimentalMergedMode;
+
+ @AssistedInject
+ SubcomponentCreatorRequestRepresentation(
+ @Assisted ContributionBinding binding, ComponentImplementation componentImplementation) {
+ this.binding = binding;
+ this.shardImplementation = componentImplementation.shardImplementation(binding);
+ this.isExperimentalMergedMode =
+ componentImplementation.compilerMode().isExperimentalMergedMode();
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ return Expression.create(
+ binding.key().type().java(),
+ "new $T($L)",
+ shardImplementation.getSubcomponentCreatorSimpleName(binding.key()),
+ isExperimentalMergedMode
+ ? getDependenciesExperimental()
+ : shardImplementation.componentFieldsByImplementation().values().stream()
+ .map(field -> CodeBlock.of("$N", field))
+ .collect(toParametersCodeBlock()));
+ }
+
+ private CodeBlock getDependenciesExperimental() {
+ List<CodeBlock> expressions = new ArrayList<>();
+ int index = 0;
+ for (FieldSpec field : shardImplementation.componentFieldsByImplementation().values()) {
+ expressions.add(CodeBlock.of("($T) dependencies[$L]", field.type, index++));
+ }
+ return expressions.stream().collect(toParametersCodeBlock());
+ }
+
+ CodeBlock getDependencyExpressionArguments() {
+ return shardImplementation.componentFieldsByImplementation().values().stream()
+ .map(field -> CodeBlock.of("$N", field))
+ .collect(toParametersCodeBlock());
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ SubcomponentCreatorRequestRepresentation create(ContributionBinding binding);
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/SubcomponentNames.java b/java/dagger/internal/codegen/writing/SubcomponentNames.java
deleted file mode 100644
index fa0037b67..000000000
--- a/java/dagger/internal/codegen/writing/SubcomponentNames.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
-import static java.lang.Character.isUpperCase;
-import static java.lang.String.format;
-
-import com.google.common.base.CharMatcher;
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Multimaps;
-import dagger.internal.codegen.base.UniqueNameSet;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ComponentCreatorDescriptor;
-import dagger.internal.codegen.binding.ComponentDescriptor;
-import dagger.internal.codegen.binding.KeyFactory;
-import dagger.model.Key;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import javax.lang.model.element.Name;
-import javax.lang.model.element.TypeElement;
-
-/**
- * Holds the unique simple names for all subcomponents, keyed by their {@link ComponentDescriptor}
- * and {@link Key} of the subcomponent builder.
- */
-public final class SubcomponentNames {
- private static final Splitter QUALIFIED_NAME_SPLITTER = Splitter.on('.');
-
- private final ImmutableMap<ComponentDescriptor, String> namesByDescriptor;
- private final ImmutableMap<Key, ComponentDescriptor> descriptorsByCreatorKey;
-
- public SubcomponentNames(BindingGraph graph, KeyFactory keyFactory) {
- this.namesByDescriptor = namesByDescriptor(graph);
- this.descriptorsByCreatorKey = descriptorsByCreatorKey(keyFactory, namesByDescriptor.keySet());
- }
-
- /** Returns the simple component name for the given {@link ComponentDescriptor}. */
- String get(ComponentDescriptor componentDescriptor) {
- return namesByDescriptor.get(componentDescriptor);
- }
-
- /**
- * Returns the simple name for the subcomponent creator implementation with the given {@link Key}.
- */
- String getCreatorName(Key key) {
- return getCreatorName(descriptorsByCreatorKey.get(key));
- }
-
- /**
- * Returns the simple name for the subcomponent creator implementation for the given {@link
- * ComponentDescriptor}.
- */
- String getCreatorName(ComponentDescriptor componentDescriptor) {
- checkArgument(componentDescriptor.creatorDescriptor().isPresent());
- ComponentCreatorDescriptor creatorDescriptor = componentDescriptor.creatorDescriptor().get();
- return get(componentDescriptor) + creatorDescriptor.kind().typeName();
- }
-
- private static ImmutableMap<ComponentDescriptor, String> namesByDescriptor(BindingGraph graph) {
- ImmutableListMultimap<String, ComponentDescriptor> componentDescriptorsBySimpleName =
- Multimaps.index(graph.componentDescriptors(), SubcomponentNames::simpleName);
- Map<ComponentDescriptor, String> subcomponentImplSimpleNames = new LinkedHashMap<>();
- componentDescriptorsBySimpleName
- .asMap()
- .values()
- .stream()
- .map(SubcomponentNames::disambiguateConflictingSimpleNames)
- .forEach(subcomponentImplSimpleNames::putAll);
- subcomponentImplSimpleNames.remove(graph.componentDescriptor());
- return ImmutableMap.copyOf(subcomponentImplSimpleNames);
- }
-
- private static ImmutableMap<Key, ComponentDescriptor> descriptorsByCreatorKey(
- KeyFactory keyFactory, ImmutableSet<ComponentDescriptor> subcomponents) {
- return subcomponents.stream()
- .filter(subcomponent -> subcomponent.creatorDescriptor().isPresent())
- .collect(
- toImmutableMap(
- subcomponent ->
- keyFactory.forSubcomponentCreator(
- subcomponent.creatorDescriptor().get().typeElement().asType()),
- subcomponent -> subcomponent));
- }
-
- private static ImmutableMap<ComponentDescriptor, String> disambiguateConflictingSimpleNames(
- Collection<ComponentDescriptor> componentsWithConflictingNames) {
- // If there's only 1 component there's nothing to disambiguate so return the simple name.
- if (componentsWithConflictingNames.size() == 1) {
- ComponentDescriptor component = Iterables.getOnlyElement(componentsWithConflictingNames);
- return ImmutableMap.of(component, simpleName(component));
- }
-
- // There are conflicting simple names, so disambiguate them with a unique prefix.
- // We keep them small to fix https://github.com/google/dagger/issues/421.
- UniqueNameSet nameSet = new UniqueNameSet();
- ImmutableMap.Builder<ComponentDescriptor, String> uniqueNames = ImmutableMap.builder();
- for (ComponentDescriptor component : componentsWithConflictingNames) {
- String simpleName = simpleName(component);
- String basePrefix = uniquingPrefix(component);
- uniqueNames.put(component, format("%s_%s", nameSet.getUniqueName(basePrefix), simpleName));
- }
- return uniqueNames.build();
- }
-
- private static String simpleName(ComponentDescriptor component) {
- return component.typeElement().getSimpleName().toString();
- }
-
- /** Returns a prefix that could make the component's simple name more unique. */
- private static String uniquingPrefix(ComponentDescriptor component) {
- TypeElement typeElement = component.typeElement();
- String containerName = typeElement.getEnclosingElement().getSimpleName().toString();
-
- // If parent element looks like a class, use its initials as a prefix.
- if (!containerName.isEmpty() && isUpperCase(containerName.charAt(0))) {
- return CharMatcher.javaLowerCase().removeFrom(containerName);
- }
-
- // Not in a normally named class. Prefix with the initials of the elements leading here.
- Name qualifiedName = typeElement.getQualifiedName();
- Iterator<String> pieces = QUALIFIED_NAME_SPLITTER.split(qualifiedName).iterator();
- StringBuilder b = new StringBuilder();
-
- while (pieces.hasNext()) {
- String next = pieces.next();
- if (pieces.hasNext()) {
- b.append(next.charAt(0));
- }
- }
-
- // Note that a top level class in the root package will be prefixed "$_".
- return b.length() > 0 ? b.toString() : "$";
- }
-}
diff --git a/java/dagger/internal/codegen/writing/SwitchingProviderInstanceSupplier.java b/java/dagger/internal/codegen/writing/SwitchingProviderInstanceSupplier.java
new file mode 100644
index 000000000..ef6bd499d
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/SwitchingProviderInstanceSupplier.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import static dagger.internal.codegen.javapoet.TypeNames.DOUBLE_CHECK;
+import static dagger.internal.codegen.javapoet.TypeNames.SINGLE_CHECK;
+
+import com.squareup.javapoet.CodeBlock;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.binding.Binding;
+import dagger.internal.codegen.binding.BindingGraph;
+import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.spi.model.BindingKind;
+
+/**
+ * An object that initializes a framework-type component field for a binding using instances created
+ * by switching providers.
+ */
+final class SwitchingProviderInstanceSupplier implements FrameworkInstanceSupplier {
+ private final FrameworkInstanceSupplier frameworkInstanceSupplier;
+
+ @AssistedInject
+ SwitchingProviderInstanceSupplier(
+ @Assisted ProvisionBinding binding,
+ SwitchingProviders switchingProviders,
+ ExperimentalSwitchingProviders experimentalSwitchingProviders,
+ BindingGraph graph,
+ ComponentImplementation componentImplementation,
+ UnscopedDirectInstanceRequestRepresentationFactory
+ unscopedDirectInstanceRequestRepresentationFactory) {
+ FrameworkInstanceCreationExpression frameworkInstanceCreationExpression =
+ componentImplementation.compilerMode().isExperimentalMergedMode()
+ ? experimentalSwitchingProviders.newFrameworkInstanceCreationExpression(
+ binding, unscopedDirectInstanceRequestRepresentationFactory.create(binding))
+ : switchingProviders.newFrameworkInstanceCreationExpression(
+ binding, unscopedDirectInstanceRequestRepresentationFactory.create(binding));
+ this.frameworkInstanceSupplier =
+ new FrameworkFieldInitializer(
+ componentImplementation, binding, scope(binding, frameworkInstanceCreationExpression));
+ }
+
+ @Override
+ public MemberSelect memberSelect() {
+ return frameworkInstanceSupplier.memberSelect();
+ }
+
+ private FrameworkInstanceCreationExpression scope(
+ Binding binding, FrameworkInstanceCreationExpression unscoped) {
+ // Caching assisted factory provider, so that there won't be new factory created for each
+ // provider.get() call.
+ if (!binding.scope().isPresent() && !binding.kind().equals(BindingKind.ASSISTED_FACTORY)) {
+ return unscoped;
+ }
+ return () ->
+ CodeBlock.of(
+ "$T.provider($L)",
+ binding.scope().isPresent()
+ ? (binding.scope().get().isReusable() ? SINGLE_CHECK : DOUBLE_CHECK)
+ : SINGLE_CHECK,
+ unscoped.creationExpression());
+ }
+
+ @AssistedFactory
+ static interface Factory {
+ SwitchingProviderInstanceSupplier create(ProvisionBinding binding);
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/SwitchingProviders.java b/java/dagger/internal/codegen/writing/SwitchingProviders.java
index d38b9d957..b922b1740 100644
--- a/java/dagger/internal/codegen/writing/SwitchingProviders.java
+++ b/java/dagger/internal/codegen/writing/SwitchingProviders.java
@@ -16,6 +16,7 @@
package dagger.internal.codegen.writing;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.getLast;
import static com.google.common.collect.Iterables.getOnlyElement;
@@ -25,57 +26,41 @@ import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.suppressWarnings;
import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
+import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
import dagger.internal.codegen.base.UniqueNameSet;
+import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.javapoet.CodeBlocks;
-import dagger.internal.codegen.javapoet.Expression;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
+import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
+import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.Key;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
+import javax.inject.Inject;
/**
* Keeps track of all provider expression requests for a component.
*
- * <p>The provider expression request will be satisfied by a single generated {@code Provider} inner
- * class that can provide instances for all types by switching on an id.
+ * <p>The provider expression request will be satisfied by a single generated {@code Provider} class
+ * that can provide instances for all types by switching on an id.
*/
-// TODO(ronshapiro): either merge this with InnerSwitchingProviders, or repurpose this for
-// SwitchingProducers
-abstract class SwitchingProviders {
- /**
- * Defines the {@linkplain Expression expressions} for a switch case in a {@code SwitchProvider}
- * for a particular binding.
- */
- // TODO(bcorso): Consider handling SwitchingProviders with dependency arguments in this class,
- // then we wouldn't need the getProviderExpression method.
- // TODO(bcorso): Consider making this an abstract class with equals/hashCode defined by the key
- // and then using this class directly in Map types instead of Key.
- interface SwitchCase {
- /** Returns the {@link Key} for this switch case. */
- Key key();
-
- /** Returns the {@link Expression} that returns the provided instance for this case. */
- Expression getReturnExpression(ClassName switchingProviderClass);
-
- /**
- * Returns the {@link Expression} that returns the {@code SwitchProvider} instance for this
- * case.
- */
- Expression getProviderExpression(ClassName switchingProviderClass, int switchId);
- }
-
+@PerComponentImplementation
+final class SwitchingProviders {
/**
* Each switch size is fixed at 100 cases each and put in its own method. This is to limit the
* size of the methods so that we don't reach the "huge" method size limit for Android that will
@@ -96,35 +81,36 @@ abstract class SwitchingProviders {
private final Map<Key, SwitchingProviderBuilder> switchingProviderBuilders =
new LinkedHashMap<>();
- private final ComponentImplementation componentImplementation;
- private final ClassName owningComponent;
+ private final ShardImplementation shardImplementation;
private final DaggerTypes types;
private final UniqueNameSet switchingProviderNames = new UniqueNameSet();
+ @Inject
SwitchingProviders(ComponentImplementation componentImplementation, DaggerTypes types) {
- this.componentImplementation = checkNotNull(componentImplementation);
+ // Currently, the SwitchingProviders types are only added to the componentShard.
+ this.shardImplementation = checkNotNull(componentImplementation).getComponentShard();
this.types = checkNotNull(types);
- this.owningComponent = checkNotNull(componentImplementation).name();
}
- /** Returns the {@link TypeSpec} for a {@code SwitchingProvider} based on the given builder. */
- protected abstract TypeSpec createSwitchingProviderType(TypeSpec.Builder builder);
-
- /**
- * Returns the {@link Expression} that returns the {@code SwitchProvider} instance for the case.
- */
- protected final Expression getProviderExpression(SwitchCase switchCase) {
- return switchingProviderBuilders
- .computeIfAbsent(switchCase.key(), key -> getSwitchingProviderBuilder())
- .getProviderExpression(switchCase);
+ /** Returns the framework instance creation expression for an inner switching provider class. */
+ FrameworkInstanceCreationExpression newFrameworkInstanceCreationExpression(
+ ContributionBinding binding, RequestRepresentation unscopedInstanceRequestRepresentation) {
+ return new FrameworkInstanceCreationExpression() {
+ @Override
+ public CodeBlock creationExpression() {
+ return switchingProviderBuilders
+ .computeIfAbsent(binding.key(), key -> getSwitchingProviderBuilder())
+ .getNewInstanceCodeBlock(binding, unscopedInstanceRequestRepresentation);
+ }
+ };
}
private SwitchingProviderBuilder getSwitchingProviderBuilder() {
if (switchingProviderBuilders.size() % MAX_CASES_PER_CLASS == 0) {
String name = switchingProviderNames.getUniqueName("SwitchingProvider");
SwitchingProviderBuilder switchingProviderBuilder =
- new SwitchingProviderBuilder(owningComponent.nestedClass(name));
- componentImplementation.addTypeSupplier(switchingProviderBuilder::build);
+ new SwitchingProviderBuilder(shardImplementation.name().nestedClass(name));
+ shardImplementation.addTypeSupplier(switchingProviderBuilder::build);
return switchingProviderBuilder;
}
return getLast(switchingProviderBuilders.values());
@@ -142,33 +128,72 @@ abstract class SwitchingProviders {
this.switchingProviderType = checkNotNull(switchingProviderType);
}
- Expression getProviderExpression(SwitchCase switchCase) {
- Key key = switchCase.key();
+ private CodeBlock getNewInstanceCodeBlock(
+ ContributionBinding binding, RequestRepresentation unscopedInstanceRequestRepresentation) {
+ Key key = binding.key();
if (!switchIds.containsKey(key)) {
int switchId = switchIds.size();
switchIds.put(key, switchId);
- switchCases.put(switchId, createSwitchCaseCodeBlock(switchCase));
+ switchCases.put(
+ switchId, createSwitchCaseCodeBlock(key, unscopedInstanceRequestRepresentation));
}
- return switchCase.getProviderExpression(switchingProviderType, switchIds.get(key));
+ return CodeBlock.of(
+ "new $T<$L>($L, $L)",
+ switchingProviderType,
+ // Add the type parameter explicitly when the binding is scoped because Java can't resolve
+ // the type when wrapped. For example, the following will error:
+ // fooProvider = DoubleCheck.provider(new SwitchingProvider<>(1));
+ (binding.scope().isPresent() || binding.kind().equals(BindingKind.ASSISTED_FACTORY))
+ ? CodeBlock.of(
+ "$T", shardImplementation.accessibleType(toJavac(binding.contributedType())))
+ : "",
+ shardImplementation.componentFieldsByImplementation().values().stream()
+ .map(field -> CodeBlock.of("$N", field))
+ .collect(CodeBlocks.toParametersCodeBlock()),
+ switchIds.get(key));
}
- private CodeBlock createSwitchCaseCodeBlock(SwitchCase switchCase) {
+ private CodeBlock createSwitchCaseCodeBlock(
+ Key key, RequestRepresentation unscopedInstanceRequestRepresentation) {
+ // TODO(bcorso): Try to delay calling getDependencyExpression() until we are writing out the
+ // SwitchingProvider because calling it here makes FrameworkFieldInitializer think there's a
+ // cycle when initializing SwitchingProviders which adds an uncessary DelegateFactory.
CodeBlock instanceCodeBlock =
- switchCase.getReturnExpression(switchingProviderType).box(types).codeBlock();
+ unscopedInstanceRequestRepresentation
+ .getDependencyExpression(switchingProviderType)
+ .box(types)
+ .codeBlock();
return CodeBlock.builder()
// TODO(bcorso): Is there something else more useful than the key?
- .add("case $L: // $L \n", switchIds.get(switchCase.key()), switchCase.key())
+ .add("case $L: // $L \n", switchIds.get(key), key)
.addStatement("return ($T) $L", T, instanceCodeBlock)
.build();
}
private TypeSpec build() {
- return createSwitchingProviderType(
+ TypeSpec.Builder builder =
classBuilder(switchingProviderType)
+ .addModifiers(PRIVATE, FINAL, STATIC)
.addTypeVariable(T)
.addSuperinterface(providerOf(T))
- .addMethods(getMethods()));
+ .addMethods(getMethods());
+
+ // The SwitchingProvider constructor lists all component parameters first and switch id last.
+ MethodSpec.Builder constructor = MethodSpec.constructorBuilder();
+ shardImplementation
+ .componentFieldsByImplementation()
+ .values()
+ .forEach(
+ field -> {
+ builder.addField(field);
+ constructor.addParameter(field.type, field.name);
+ constructor.addStatement("this.$1N = $1N", field);
+ });
+ builder.addField(TypeName.INT, "id", PRIVATE, FINAL);
+ constructor.addParameter(TypeName.INT, "id").addStatement("this.id = id");
+
+ return builder.addMethod(constructor.build()).build();
}
private ImmutableList<MethodSpec> getMethods() {
diff --git a/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java b/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java
new file mode 100644
index 000000000..28c23700f
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import dagger.internal.codegen.binding.ComponentRequirement;
+import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.spi.model.RequestKind;
+import javax.inject.Inject;
+
+/**
+ * A factory for creating a binding expression for an unscoped instance.
+ *
+ * <p>Note that these binding expressions are for getting "direct" instances -- i.e. instances that
+ * are created via constructors or modules (e.g. {@code new Foo()} or {@code
+ * FooModule.provideFoo()}) as opposed to an instance created from calling a getter on a framework
+ * type (e.g. {@code fooProvider.get()}). See {@link FrameworkInstanceRequestRepresentation} for
+ * binding expressions that are created from framework types.
+ */
+final class UnscopedDirectInstanceRequestRepresentationFactory {
+ private final AssistedFactoryRequestRepresentation.Factory
+ assistedFactoryRequestRepresentationFactory;
+ private final ComponentInstanceRequestRepresentation.Factory
+ componentInstanceRequestRepresentationFactory;
+ private final ComponentProvisionRequestRepresentation.Factory
+ componentProvisionRequestRepresentationFactory;
+ private final ComponentRequirementRequestRepresentation.Factory
+ componentRequirementRequestRepresentationFactory;
+ private final DelegateRequestRepresentation.Factory delegateRequestRepresentationFactory;
+ private final MapRequestRepresentation.Factory mapRequestRepresentationFactory;
+ private final OptionalRequestRepresentation.Factory optionalRequestRepresentationFactory;
+ private final SetRequestRepresentation.Factory setRequestRepresentationFactory;
+ private final SimpleMethodRequestRepresentation.Factory simpleMethodRequestRepresentationFactory;
+ private final SubcomponentCreatorRequestRepresentation.Factory
+ subcomponentCreatorRequestRepresentationFactory;
+
+ @Inject
+ UnscopedDirectInstanceRequestRepresentationFactory(
+ ComponentImplementation componentImplementation,
+ AssistedFactoryRequestRepresentation.Factory assistedFactoryRequestRepresentationFactory,
+ ComponentInstanceRequestRepresentation.Factory componentInstanceRequestRepresentationFactory,
+ ComponentProvisionRequestRepresentation.Factory
+ componentProvisionRequestRepresentationFactory,
+ ComponentRequirementRequestRepresentation.Factory
+ componentRequirementRequestRepresentationFactory,
+ DelegateRequestRepresentation.Factory delegateRequestRepresentationFactory,
+ MapRequestRepresentation.Factory mapRequestRepresentationFactory,
+ OptionalRequestRepresentation.Factory optionalRequestRepresentationFactory,
+ SetRequestRepresentation.Factory setRequestRepresentationFactory,
+ SimpleMethodRequestRepresentation.Factory simpleMethodRequestRepresentationFactory,
+ SubcomponentCreatorRequestRepresentation.Factory
+ subcomponentCreatorRequestRepresentationFactory) {
+ this.assistedFactoryRequestRepresentationFactory = assistedFactoryRequestRepresentationFactory;
+ this.componentInstanceRequestRepresentationFactory =
+ componentInstanceRequestRepresentationFactory;
+ this.componentProvisionRequestRepresentationFactory =
+ componentProvisionRequestRepresentationFactory;
+ this.componentRequirementRequestRepresentationFactory =
+ componentRequirementRequestRepresentationFactory;
+ this.delegateRequestRepresentationFactory = delegateRequestRepresentationFactory;
+ this.mapRequestRepresentationFactory = mapRequestRepresentationFactory;
+ this.optionalRequestRepresentationFactory = optionalRequestRepresentationFactory;
+ this.setRequestRepresentationFactory = setRequestRepresentationFactory;
+ this.simpleMethodRequestRepresentationFactory = simpleMethodRequestRepresentationFactory;
+ this.subcomponentCreatorRequestRepresentationFactory =
+ subcomponentCreatorRequestRepresentationFactory;
+ }
+
+ /** Returns a direct, unscoped binding expression for a {@link RequestKind#INSTANCE} request. */
+ RequestRepresentation create(ContributionBinding binding) {
+ switch (binding.kind()) {
+ case DELEGATE:
+ return delegateRequestRepresentationFactory.create(binding, RequestKind.INSTANCE);
+
+ case COMPONENT:
+ return componentInstanceRequestRepresentationFactory.create(binding);
+
+ case COMPONENT_DEPENDENCY:
+ return componentRequirementRequestRepresentationFactory.create(
+ binding, ComponentRequirement.forDependency(binding.key().type().xprocessing()));
+
+ case COMPONENT_PROVISION:
+ return componentProvisionRequestRepresentationFactory.create((ProvisionBinding) binding);
+
+ case SUBCOMPONENT_CREATOR:
+ return subcomponentCreatorRequestRepresentationFactory.create(binding);
+
+ case MULTIBOUND_SET:
+ return setRequestRepresentationFactory.create((ProvisionBinding) binding);
+
+ case MULTIBOUND_MAP:
+ return mapRequestRepresentationFactory.create((ProvisionBinding) binding);
+
+ case OPTIONAL:
+ return optionalRequestRepresentationFactory.create((ProvisionBinding) binding);
+
+ case BOUND_INSTANCE:
+ return componentRequirementRequestRepresentationFactory.create(
+ binding, ComponentRequirement.forBoundInstance(binding));
+
+ case ASSISTED_FACTORY:
+ return assistedFactoryRequestRepresentationFactory.create((ProvisionBinding) binding);
+
+ case INJECTION:
+ case PROVISION:
+ return simpleMethodRequestRepresentationFactory.create((ProvisionBinding) binding);
+
+ case ASSISTED_INJECTION:
+ case MEMBERS_INJECTOR:
+ case MEMBERS_INJECTION:
+ case COMPONENT_PRODUCTION:
+ case PRODUCTION:
+ // Fall through
+ }
+ throw new AssertionError("Unexpected binding kind: " + binding.kind());
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/UnscopedFrameworkInstanceCreationExpressionFactory.java b/java/dagger/internal/codegen/writing/UnscopedFrameworkInstanceCreationExpressionFactory.java
new file mode 100644
index 000000000..d77b14626
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/UnscopedFrameworkInstanceCreationExpressionFactory.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.writing;
+
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.binding.ComponentRequirement;
+import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import javax.inject.Inject;
+
+/**
+ * A factory for creating unscoped creation expressions for a provision or production binding.
+ *
+ * <p>A creation expression is responsible for creating the factory for a given binding (e.g. by
+ * calling the generated factory create method, {@code Foo_Factory.create(...)}). Note that this
+ * class does not handle scoping of these factories (e.g. wrapping in {@code
+ * DoubleCheck.provider()}).
+ */
+final class UnscopedFrameworkInstanceCreationExpressionFactory {
+ private final ComponentImplementation componentImplementation;
+ private final ComponentRequirementExpressions componentRequirementExpressions;
+ private final AnonymousProviderCreationExpression.Factory
+ anonymousProviderCreationExpressionFactory;
+ private final DelegatingFrameworkInstanceCreationExpression.Factory
+ delegatingFrameworkInstanceCreationExpressionFactory;
+ private final DependencyMethodProducerCreationExpression.Factory
+ dependencyMethodProducerCreationExpressionFactory;
+ private final DependencyMethodProviderCreationExpression.Factory
+ dependencyMethodProviderCreationExpressionFactory;
+ private final InjectionOrProvisionProviderCreationExpression.Factory
+ injectionOrProvisionProviderCreationExpressionFactory;
+ private final MapFactoryCreationExpression.Factory mapFactoryCreationExpressionFactory;
+ private final MembersInjectorProviderCreationExpression.Factory
+ membersInjectorProviderCreationExpressionFactory;
+ private final OptionalFactoryInstanceCreationExpression.Factory
+ optionalFactoryInstanceCreationExpressionFactory;
+ private final ProducerCreationExpression.Factory producerCreationExpressionFactory;
+ private final SetFactoryCreationExpression.Factory setFactoryCreationExpressionFactory;
+
+ @Inject
+ UnscopedFrameworkInstanceCreationExpressionFactory(
+ ComponentImplementation componentImplementation,
+ ComponentRequirementExpressions componentRequirementExpressions,
+ AnonymousProviderCreationExpression.Factory anonymousProviderCreationExpressionFactory,
+ DelegatingFrameworkInstanceCreationExpression.Factory
+ delegatingFrameworkInstanceCreationExpressionFactory,
+ DependencyMethodProducerCreationExpression.Factory
+ dependencyMethodProducerCreationExpressionFactory,
+ DependencyMethodProviderCreationExpression.Factory
+ dependencyMethodProviderCreationExpressionFactory,
+ InjectionOrProvisionProviderCreationExpression.Factory
+ injectionOrProvisionProviderCreationExpressionFactory,
+ MapFactoryCreationExpression.Factory mapFactoryCreationExpressionFactory,
+ MembersInjectorProviderCreationExpression.Factory
+ membersInjectorProviderCreationExpressionFactory,
+ OptionalFactoryInstanceCreationExpression.Factory
+ optionalFactoryInstanceCreationExpressionFactory,
+ ProducerCreationExpression.Factory producerCreationExpressionFactory,
+ SetFactoryCreationExpression.Factory setFactoryCreationExpressionFactory) {
+ this.componentImplementation = componentImplementation;
+ this.componentRequirementExpressions = componentRequirementExpressions;
+ this.anonymousProviderCreationExpressionFactory = anonymousProviderCreationExpressionFactory;
+ this.delegatingFrameworkInstanceCreationExpressionFactory =
+ delegatingFrameworkInstanceCreationExpressionFactory;
+ this.dependencyMethodProducerCreationExpressionFactory =
+ dependencyMethodProducerCreationExpressionFactory;
+ this.dependencyMethodProviderCreationExpressionFactory =
+ dependencyMethodProviderCreationExpressionFactory;
+ this.injectionOrProvisionProviderCreationExpressionFactory =
+ injectionOrProvisionProviderCreationExpressionFactory;
+ this.mapFactoryCreationExpressionFactory = mapFactoryCreationExpressionFactory;
+ this.membersInjectorProviderCreationExpressionFactory =
+ membersInjectorProviderCreationExpressionFactory;
+ this.optionalFactoryInstanceCreationExpressionFactory =
+ optionalFactoryInstanceCreationExpressionFactory;
+ this.producerCreationExpressionFactory = producerCreationExpressionFactory;
+ this.setFactoryCreationExpressionFactory = setFactoryCreationExpressionFactory;
+ }
+
+ /**
+ * Returns an unscoped creation expression for a {@link javax.inject.Provider} for provision
+ * bindings or a {@link dagger.producers.Producer} for production bindings.
+ */
+ FrameworkInstanceCreationExpression create(ContributionBinding binding) {
+ switch (binding.kind()) {
+ case COMPONENT:
+ // The cast can be removed when we drop java 7 source support
+ return new InstanceFactoryCreationExpression(
+ () ->
+ CodeBlock.of(
+ "($T) $L",
+ binding.key().type().java(),
+ componentImplementation.componentFieldReference()));
+
+ case BOUND_INSTANCE:
+ return instanceFactoryCreationExpression(
+ binding, ComponentRequirement.forBoundInstance(binding));
+
+ case COMPONENT_DEPENDENCY:
+ return instanceFactoryCreationExpression(
+ binding, ComponentRequirement.forDependency(binding.key().type().xprocessing()));
+
+ case COMPONENT_PROVISION:
+ return dependencyMethodProviderCreationExpressionFactory.create((ProvisionBinding) binding);
+
+ case SUBCOMPONENT_CREATOR:
+ return anonymousProviderCreationExpressionFactory.create(binding);
+
+ case ASSISTED_FACTORY:
+ case ASSISTED_INJECTION:
+ case INJECTION:
+ case PROVISION:
+ return injectionOrProvisionProviderCreationExpressionFactory.create(binding);
+
+ case COMPONENT_PRODUCTION:
+ return dependencyMethodProducerCreationExpressionFactory.create(binding);
+
+ case PRODUCTION:
+ return producerCreationExpressionFactory.create(binding);
+
+ case MULTIBOUND_SET:
+ return setFactoryCreationExpressionFactory.create(binding);
+
+ case MULTIBOUND_MAP:
+ return mapFactoryCreationExpressionFactory.create(binding);
+
+ case DELEGATE:
+ return delegatingFrameworkInstanceCreationExpressionFactory.create(binding);
+
+ case OPTIONAL:
+ return optionalFactoryInstanceCreationExpressionFactory.create(binding);
+
+ case MEMBERS_INJECTOR:
+ return membersInjectorProviderCreationExpressionFactory.create((ProvisionBinding) binding);
+
+ default:
+ throw new AssertionError(binding);
+ }
+ }
+
+ private InstanceFactoryCreationExpression instanceFactoryCreationExpression(
+ ContributionBinding binding, ComponentRequirement componentRequirement) {
+ return new InstanceFactoryCreationExpression(
+ binding.nullableType().isPresent(),
+ () ->
+ componentRequirementExpressions.getExpressionDuringInitialization(
+ componentRequirement, componentImplementation.name()));
+ }
+}
diff --git a/java/dagger/internal/codegen/writing/UnwrappedMapKeyGenerator.java b/java/dagger/internal/codegen/writing/UnwrappedMapKeyGenerator.java
index f07b882b2..094f07a06 100644
--- a/java/dagger/internal/codegen/writing/UnwrappedMapKeyGenerator.java
+++ b/java/dagger/internal/codegen/writing/UnwrappedMapKeyGenerator.java
@@ -16,13 +16,13 @@
package dagger.internal.codegen.writing;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XTypeElement;
import dagger.MapKey;
import dagger.internal.codegen.langmodel.DaggerElements;
import java.util.Set;
-import javax.annotation.processing.Filer;
import javax.inject.Inject;
import javax.lang.model.SourceVersion;
-import javax.lang.model.element.TypeElement;
/**
* Generates classes that create annotation instances for an unwrapped {@link MapKey} annotation
@@ -56,13 +56,13 @@ import javax.lang.model.element.TypeElement;
public final class UnwrappedMapKeyGenerator extends AnnotationCreatorGenerator {
@Inject
- UnwrappedMapKeyGenerator(Filer filer, DaggerElements elements, SourceVersion sourceVersion) {
+ UnwrappedMapKeyGenerator(XFiler filer, DaggerElements elements, SourceVersion sourceVersion) {
super(filer, elements, sourceVersion);
}
@Override
- protected Set<TypeElement> annotationsToCreate(TypeElement annotationElement) {
- Set<TypeElement> nestedAnnotationElements = super.annotationsToCreate(annotationElement);
+ protected Set<XTypeElement> annotationsToCreate(XTypeElement annotationElement) {
+ Set<XTypeElement> nestedAnnotationElements = super.annotationsToCreate(annotationElement);
nestedAnnotationElements.remove(annotationElement);
return nestedAnnotationElements;
}
diff --git a/java/dagger/internal/codegen/xprocessing/BUILD b/java/dagger/internal/codegen/xprocessing/BUILD
new file mode 100644
index 000000000..80a0c027a
--- /dev/null
+++ b/java/dagger/internal/codegen/xprocessing/BUILD
@@ -0,0 +1,51 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Description:
+# Import for including XProcessing in Dagger.
+
+load("@rules_java//java:defs.bzl", "java_import")
+
+package(default_visibility = ["//:src"])
+
+java_library(
+ name = "xprocessing",
+ # TODO(b/181056551): Ideally, all of the methods in these utility classes
+ # will move directly into XProcessing, and we can then remove these classes.
+ srcs = glob(["*.java"]),
+ exports = [
+ ":xprocessing-lib",
+ ],
+ deps = [
+ ":xprocessing-lib",
+ "//java/dagger/internal/codegen/extension",
+ "//third_party/java/auto:common",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
+ "@maven//:org_jetbrains_kotlin_kotlin_stdlib",
+ "@maven//:org_jetbrains_kotlin_kotlin_stdlib_jdk8",
+ ],
+)
+
+alias(
+ name = "xprocessing-lib",
+ actual = ":xprocessing-jar",
+ visibility = ["//visibility:private"],
+)
+
+java_import(
+ name = "xprocessing-jar",
+ jars = ["xprocessing.jar"],
+)
diff --git a/java/dagger/internal/codegen/xprocessing/MethodSpecs.java b/java/dagger/internal/codegen/xprocessing/MethodSpecs.java
new file mode 100644
index 000000000..6c0322cb4
--- /dev/null
+++ b/java/dagger/internal/codegen/xprocessing/MethodSpecs.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.xprocessing;
+
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static javax.lang.model.element.Modifier.PROTECTED;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XMethodType;
+import androidx.room.compiler.processing.XType;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.TypeName;
+
+// TODO(bcorso): Consider moving these methods into XProcessing library.
+/** A utility class for {@link MethodSpec} helper methods. */
+public final class MethodSpecs {
+
+ /** Returns a {@link MethodSpec} that overrides the given method. */
+ public static MethodSpec.Builder overriding(XMethodElement method, XType owner) {
+ XMethodType methodType = method.asMemberOf(owner);
+ MethodSpec.Builder builder =
+ MethodSpec.methodBuilder(getSimpleName(method))
+ .addAnnotation(Override.class)
+ .addTypeVariables(methodType.getTypeVariableNames())
+ .varargs(method.isVarArgs())
+ .returns(methodType.getReturnType().getTypeName());
+ if (method.isPublic()) {
+ builder.addModifiers(PUBLIC);
+ } else if (method.isProtected()) {
+ builder.addModifiers(PROTECTED);
+ }
+ for (int i = 0; i < methodType.getParameterTypes().size(); i++) {
+ String parameterName = getSimpleName(method.getParameters().get(i));
+ TypeName parameterType = methodType.getParameterTypes().get(i).getTypeName();
+ builder.addParameter(ParameterSpec.builder(parameterType, parameterName).build());
+ }
+ method.getThrownTypes().stream().map(XType::getTypeName).forEach(builder::addException);
+ return builder;
+ }
+
+ private MethodSpecs() {}
+}
diff --git a/java/dagger/internal/codegen/xprocessing/XAnnotations.java b/java/dagger/internal/codegen/xprocessing/XAnnotations.java
new file mode 100644
index 000000000..9e77a866f
--- /dev/null
+++ b/java/dagger/internal/codegen/xprocessing/XAnnotations.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.xprocessing;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+
+import androidx.room.compiler.processing.XAnnotation;
+import com.google.auto.common.AnnotationMirrors;
+import com.squareup.javapoet.ClassName;
+
+// TODO(bcorso): Consider moving these methods into XProcessing library.
+/** A utility class for {@link XAnnotation} helper methods. */
+public final class XAnnotations {
+
+ /** Returns the string representation of the given annotation. */
+ public static String toString(XAnnotation annotation) {
+ return AnnotationMirrors.toString(toJavac(annotation));
+ }
+
+ /** Returns the class name of the given annotation */
+ public static ClassName getClassName(XAnnotation annotation) {
+ return annotation.getType().getTypeElement().getClassName();
+ }
+
+ private XAnnotations() {}
+}
diff --git a/java/dagger/internal/codegen/xprocessing/XElements.java b/java/dagger/internal/codegen/xprocessing/XElements.java
new file mode 100644
index 000000000..4c338ef42
--- /dev/null
+++ b/java/dagger/internal/codegen/xprocessing/XElements.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.xprocessing;
+
+import static androidx.room.compiler.processing.XElementKt.isConstructor;
+import static androidx.room.compiler.processing.XElementKt.isField;
+import static androidx.room.compiler.processing.XElementKt.isMethod;
+import static androidx.room.compiler.processing.XElementKt.isMethodParameter;
+import static androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static androidx.room.compiler.processing.XElementKt.isVariableElement;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+
+import androidx.room.compiler.processing.XAnnotated;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XEnumEntry;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XExecutableParameterElement;
+import androidx.room.compiler.processing.XFieldElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.XVariableElement;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import java.util.Collection;
+import java.util.Optional;
+import javax.lang.model.element.ElementKind;
+
+// TODO(bcorso): Consider moving these methods into XProcessing library.
+/** A utility class for {@link XElement} helper methods. */
+public final class XElements {
+
+ // TODO(bcorso): Replace usages with getJvmName() once it exists.
+ /** Returns the simple name of the element. */
+ public static String getSimpleName(XElement element) {
+ return toJavac(element).getSimpleName().toString();
+ }
+
+ /**
+ * Returns the closest enclosing element that is a {@link XTypeElement} or throws an {@link
+ * IllegalStateException} if one doesn't exists.
+ */
+ public static XTypeElement closestEnclosingTypeElement(XElement element) {
+ return optionalClosestEnclosingTypeElement(element)
+ .orElseThrow(() -> new IllegalStateException("No enclosing TypeElement for: " + element));
+ }
+
+ private static Optional<XTypeElement> optionalClosestEnclosingTypeElement(XElement element) {
+ if (isTypeElement(element)) {
+ return Optional.of(asTypeElement(element));
+ } else if (isConstructor(element)) {
+ return Optional.of(asConstructor(element).getEnclosingElement());
+ } else if (isMethod(element)) {
+ return optionalClosestEnclosingTypeElement(asMethod(element).getEnclosingElement());
+ } else if (isField(element)) {
+ return optionalClosestEnclosingTypeElement(asField(element).getEnclosingElement());
+ } else if (isMethodParameter(element)) {
+ return optionalClosestEnclosingTypeElement(
+ asMethodParameter(element).getEnclosingMethodElement());
+ }
+ return Optional.empty();
+ }
+
+ public static boolean isEnumEntry(XElement element) {
+ return element instanceof XEnumEntry;
+ }
+
+ public static boolean isEnum(XElement element) {
+ return toJavac(element).getKind() == ElementKind.ENUM;
+ }
+
+ public static boolean isExecutable(XElement element) {
+ return isConstructor(element) || isMethod(element);
+ }
+
+ public static XExecutableElement asExecutable(XElement element) {
+ checkState(isExecutable(element));
+ return (XExecutableElement) element;
+ }
+
+ public static XTypeElement asTypeElement(XElement element) {
+ checkState(isTypeElement(element));
+ return (XTypeElement) element;
+ }
+
+ // TODO(bcorso): Rename this and the XElementKt.isMethodParameter to isExecutableParameter.
+ public static XExecutableParameterElement asMethodParameter(XElement element) {
+ checkState(isMethodParameter(element));
+ return (XExecutableParameterElement) element;
+ }
+
+ public static XFieldElement asField(XElement element) {
+ checkState(isField(element));
+ return (XFieldElement) element;
+ }
+
+ public static XVariableElement asVariable(XElement element) {
+ checkState(isVariableElement(element));
+ return (XVariableElement) element;
+ }
+
+ public static XConstructorElement asConstructor(XElement element) {
+ checkState(isConstructor(element));
+ return (XConstructorElement) element;
+ }
+
+ public static XMethodElement asMethod(XElement element) {
+ checkState(isMethod(element));
+ return (XMethodElement) element;
+ }
+
+ public static ImmutableSet<XAnnotation> getAnnotatedAnnotations(
+ XAnnotated annotated, ClassName annotationName) {
+ return annotated.getAllAnnotations().stream()
+ .filter(annotation -> annotation.getType().getTypeElement().hasAnnotation(annotationName))
+ .collect(toImmutableSet());
+ }
+
+ /** Returns {@code true} if {@code annotated} is annotated with any of the given annotations. */
+ public static boolean hasAnyAnnotation(XAnnotated annotated, ClassName... annotations) {
+ return hasAnyAnnotation(annotated, ImmutableSet.copyOf(annotations));
+ }
+
+ /** Returns {@code true} if {@code annotated} is annotated with any of the given annotations. */
+ public static boolean hasAnyAnnotation(XAnnotated annotated, Collection<ClassName> annotations) {
+ return annotations.stream().anyMatch(annotated::hasAnnotation);
+ }
+
+ /**
+ * Returns any annotation from {@code annotations} that annotates {@code annotated} or else {@code
+ * Optional.empty()}.
+ */
+ public static Optional<XAnnotation> getAnyAnnotation(
+ XAnnotated annotated, ClassName... annotations) {
+ return getAnyAnnotation(annotated, ImmutableSet.copyOf(annotations));
+ }
+
+ /**
+ * Returns any annotation from {@code annotations} that annotates {@code annotated} or else
+ * {@code Optional.empty()}.
+ */
+ public static Optional<XAnnotation> getAnyAnnotation(
+ XAnnotated annotated, Collection<ClassName> annotations) {
+ return annotations.stream()
+ .filter(annotated::hasAnnotation)
+ .map(annotated::getAnnotation)
+ .findFirst();
+ }
+
+ /** Returns all annotations from {@code annotations} that annotate {@code annotated}. */
+ public static ImmutableSet<XAnnotation> getAllAnnotations(
+ XAnnotated annotated, Collection<ClassName> annotations) {
+ return annotations.stream()
+ .filter(annotated::hasAnnotation)
+ .map(annotated::getAnnotation)
+ .collect(toImmutableSet());
+ }
+
+ private XElements() {}
+}
diff --git a/java/dagger/internal/codegen/xprocessing/XMethodElements.java b/java/dagger/internal/codegen/xprocessing/XMethodElements.java
new file mode 100644
index 000000000..3cd8711ca
--- /dev/null
+++ b/java/dagger/internal/codegen/xprocessing/XMethodElements.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.xprocessing;
+
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XTypeElement;
+
+// TODO(bcorso): Consider moving these methods into XProcessing library.
+/** A utility class for {@link XMethodElement} helper methods. */
+public final class XMethodElements {
+
+ /** Returns the type this method is enclosed in. */
+ public static XTypeElement getEnclosingTypeElement(XMethodElement method) {
+ // TODO(bcorso): In Javac, a method is always enclosed in a type; however, once we start
+ // processing Kotlin we'll want to check this explicitly and add an error to the validation
+ // report if the method is not enclosed in a type.
+ return method.getEnclosingElement().getType().getTypeElement();
+ }
+
+ /** Returns {@code true} if the given method has type parameters. */
+ public static boolean hasTypeParameters(XMethodElement method) {
+ return !method.getExecutableType().getTypeVariableNames().isEmpty();
+ }
+
+ private XMethodElements() {}
+}
diff --git a/java/dagger/internal/codegen/xprocessing/XTypeElements.java b/java/dagger/internal/codegen/xprocessing/XTypeElements.java
new file mode 100644
index 000000000..c0759d11a
--- /dev/null
+++ b/java/dagger/internal/codegen/xprocessing/XTypeElements.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.xprocessing;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static kotlin.streams.jdk8.StreamsKt.asStream;
+
+import androidx.room.compiler.processing.XHasModifiers;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+// TODO(bcorso): Consider moving these methods into XProcessing library.
+/** A utility class for {@link XTypeElement} helper methods. */
+public final class XTypeElements {
+ private enum Visibility {
+ PUBLIC,
+ PRIVATE,
+ OTHER;
+
+ /** Returns the visibility of the given {@link XTypeElement}. */
+ private static Visibility of(XTypeElement element) {
+ checkNotNull(element);
+ if (element.isPrivate()) {
+ return Visibility.PRIVATE;
+ } else if (element.isPublic()) {
+ return Visibility.PUBLIC;
+ } else {
+ return Visibility.OTHER;
+ }
+ }
+ }
+
+ /** Returns {@code true} if the given element is nested. */
+ public static boolean isNested(XTypeElement typeElement) {
+ return typeElement.getEnclosingTypeElement() != null;
+ }
+
+ /** Returns {@code true} if the given {@code type} has type parameters. */
+ public static boolean hasTypeParameters(XTypeElement type) {
+ // TODO(bcorso): Add support for XTypeElement#getTypeParameters() or at least
+ // XTypeElement#hasTypeParameters() in XProcessing. XTypes#getTypeArguments() isn't quite the
+ // same -- it tells you if the declared type has parameters rather than the element itself.
+ return !toJavac(type).getTypeParameters().isEmpty();
+ }
+
+ /** Returns all non-private, non-static, abstract methods in {@code type}. */
+ public static ImmutableList<XMethodElement> getAllUnimplementedMethods(XTypeElement type) {
+ return asStream(type.getAllNonPrivateInstanceMethods())
+ .filter(XHasModifiers::isAbstract)
+ .collect(toImmutableList());
+ }
+
+ public static boolean isEffectivelyPublic(XTypeElement element) {
+ return allVisibilities(element).stream()
+ .allMatch(visibility -> visibility.equals(Visibility.PUBLIC));
+ }
+
+ public static boolean isEffectivelyPrivate(XTypeElement element) {
+ return allVisibilities(element).contains(Visibility.PRIVATE);
+ }
+
+ /**
+ * Returns a list of visibilities containing visibility of the given element and the visibility of
+ * its enclosing elements.
+ */
+ private static ImmutableSet<Visibility> allVisibilities(XTypeElement element) {
+ checkNotNull(element);
+ ImmutableSet.Builder<Visibility> visibilities = ImmutableSet.builder();
+ XTypeElement currentElement = element;
+ while (currentElement != null) {
+ visibilities.add(Visibility.of(currentElement));
+ currentElement = currentElement.getEnclosingTypeElement();
+ }
+ return visibilities.build();
+ }
+
+ private XTypeElements() {}
+}
diff --git a/java/dagger/internal/codegen/xprocessing/XTypes.java b/java/dagger/internal/codegen/xprocessing/XTypes.java
new file mode 100644
index 000000000..8a3c53766
--- /dev/null
+++ b/java/dagger/internal/codegen/xprocessing/XTypes.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.xprocessing;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+
+import androidx.room.compiler.processing.XArrayType;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.compat.XConverters;
+import com.squareup.javapoet.ClassName;
+import javax.lang.model.type.TypeKind;
+
+// TODO(bcorso): Consider moving these methods into XProcessing library.
+/** A utility class for {@link XType} helper methods. */
+public final class XTypes {
+
+ /** Returns {@code true} if the given type is a raw type of a parameterized type. */
+ public static boolean isRawParameterizedType(XType type) {
+ return isDeclared(type)
+ && type.getTypeArguments().isEmpty()
+ && !type.getTypeElement().getType().getTypeArguments().isEmpty();
+ }
+
+ /** Returns the given {@code type} as an {@link XArrayType}. */
+ public static XArrayType asArray(XType type) {
+ return (XArrayType) type;
+ }
+
+ /** Returns {@code true} if the raw type of {@code type} is equal to {@code className}. */
+ public static boolean isTypeOf(XType type, ClassName className) {
+ return isDeclared(type) && type.getTypeElement().getClassName().equals(className);
+ }
+
+ /** Returns {@code true} if the given type is a declared type. */
+ public static boolean isWildcard(XType type) {
+ return toJavac(type).getKind().equals(TypeKind.WILDCARD);
+ }
+
+ /** Returns {@code true} if the given type is a declared type. */
+ public static boolean isDeclared(XType type) {
+ return type.getTypeElement() != null;
+ }
+
+ /** Returns {@code true} if the given type is a type variable. */
+ public static boolean isTypeVariable(XType type) {
+ return XConverters.toJavac(type).getKind() == TypeKind.TYPEVAR;
+ }
+
+ /**
+ * Returns {@code true} if {@code type1} is equivalent to {@code type2}.
+ */
+ public static boolean areEquivalentTypes(XType type1, XType type2) {
+ return type1.getTypeName().equals(type2.getTypeName());
+ }
+
+ /** Returns {@code true} if the given type is a primitive type. */
+ public static boolean isPrimitive(XType type) {
+ return XConverters.toJavac(type).getKind().isPrimitive();
+ }
+
+ /** Returns {@code true} if the given type has type parameters. */
+ public static boolean hasTypeParameters(XType type) {
+ return !type.getTypeArguments().isEmpty();
+ }
+
+ private XTypes() {}
+}
diff --git a/java/dagger/internal/codegen/xprocessing/xprocessing.jar b/java/dagger/internal/codegen/xprocessing/xprocessing.jar
new file mode 100644
index 000000000..2b026687e
--- /dev/null
+++ b/java/dagger/internal/codegen/xprocessing/xprocessing.jar
Binary files differ
diff --git a/java/dagger/internal/guava/BUILD b/java/dagger/internal/guava/BUILD
deleted file mode 100644
index 0bd4dcc60..000000000
--- a/java/dagger/internal/guava/BUILD
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright (C) 2017 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Aliases from guava libraries to //third_party/java/guava.
-
-package(default_visibility = ["//:src"])
-
-alias(
- name = "annotations",
- actual = "@google_bazel_common//third_party/java/guava",
-)
-
-alias(
- name = "base",
- actual = "@google_bazel_common//third_party/java/guava",
-)
-
-alias(
- name = "cache",
- actual = "@google_bazel_common//third_party/java/guava",
-)
-
-alias(
- name = "collect",
- actual = "@google_bazel_common//third_party/java/guava",
-)
-
-alias(
- name = "graph",
- actual = "@google_bazel_common//third_party/java/guava",
-)
-
-alias(
- name = "io",
- actual = "@google_bazel_common//third_party/java/guava",
-)
-
-alias(
- name = "concurrent",
- actual = "@google_bazel_common//third_party/java/guava",
-)
-
-alias(
- name = "base-android",
- actual = "@maven//:com_google_guava_guava",
-)
-
-alias(
- name = "collect-android",
- actual = "@maven//:com_google_guava_guava",
-)
-
-alias(
- name = "concurrent-android",
- actual = "@maven//:com_google_guava_guava",
-)
diff --git a/java/dagger/lint/BUILD b/java/dagger/lint/BUILD
index 3e0ffec2e..173d035c3 100644
--- a/java/dagger/lint/BUILD
+++ b/java/dagger/lint/BUILD
@@ -26,7 +26,7 @@ kt_jvm_library(
srcs = glob(["*.kt"]),
tags = ["maven_coordinates=com.google.dagger:dagger-lint:" + POM_VERSION],
deps = [
- "@google_bazel_common//third_party/java/auto:service",
+ "//third_party/java/auto:service",
"@maven//:com_android_tools_external_com_intellij_intellij_core",
"@maven//:com_android_tools_external_com_intellij_kotlin_compiler",
"@maven//:com_android_tools_external_org_jetbrains_uast",
diff --git a/java/dagger/lint/DaggerIssueRegistry.kt b/java/dagger/lint/DaggerIssueRegistry.kt
index 113e85c01..f82168831 100644
--- a/java/dagger/lint/DaggerIssueRegistry.kt
+++ b/java/dagger/lint/DaggerIssueRegistry.kt
@@ -16,6 +16,7 @@
package dagger.lint
import com.android.tools.lint.client.api.IssueRegistry
+import com.android.tools.lint.client.api.Vendor
import com.android.tools.lint.detector.api.CURRENT_API
import com.android.tools.lint.detector.api.Issue
import com.google.auto.service.AutoService
@@ -35,6 +36,12 @@ class DaggerIssueRegistry : IssueRegistry() {
// The api is meant to be the current api for which this registry was compiled, but we set a
// higher number without depending on a newer Lint to avoid Lint warning users of custom checks
// that might not work. This value eventually has to be updated as newer Api become available.
- override val api: Int = 8
+ override val api: Int = 11
override val issues: List<Issue> = DaggerKotlinIssueDetector.issues
+ override val vendor = Vendor(
+ vendorName = "Google",
+ identifier = "com.google.dagger:dagger-lint",
+ feedbackUrl = "https://github.com/google/dagger/issues",
+ contact = "https://github.com/google/dagger"
+ )
}
diff --git a/java/dagger/lint/DaggerKotlinIssueDetector.kt b/java/dagger/lint/DaggerKotlinIssueDetector.kt
index f3fdbd318..8ca862309 100644
--- a/java/dagger/lint/DaggerKotlinIssueDetector.kt
+++ b/java/dagger/lint/DaggerKotlinIssueDetector.kt
@@ -42,7 +42,6 @@ import org.jetbrains.uast.UElement
import org.jetbrains.uast.UField
import org.jetbrains.uast.UMethod
import org.jetbrains.uast.getUastParentOfType
-import org.jetbrains.uast.kotlin.KotlinUClass
import org.jetbrains.uast.toUElement
/**
@@ -61,7 +60,9 @@ import org.jetbrains.uast.toUElement
* `@Module` when the parent class is _not_ also annotated with `@Module`. While technically legal,
* these should be moved up to top-level objects to avoid confusion.
*/
-@Suppress("UnstableApiUsage") // Lots of Lint APIs are marked with @Beta.
+@Suppress(
+ "UnstableApiUsage" // Lots of Lint APIs are marked with @Beta.
+)
class DaggerKotlinIssueDetector : Detector(), SourceCodeScanner {
companion object {
@@ -164,9 +165,9 @@ class DaggerKotlinIssueDetector : Detector(), SourceCodeScanner {
}
// Can't use hasAnnotation because it doesn't capture all annotations!
val injectAnnotation =
- node.annotations.find { it.qualifiedName == INJECT_ANNOTATION } ?: return
+ node.uAnnotations.find { it.qualifiedName == INJECT_ANNOTATION } ?: return
// Look for qualifier annotations
- node.annotations.forEach { annotation ->
+ node.uAnnotations.forEach { annotation ->
if (annotation === injectAnnotation) {
// Skip the inject annotation
return@forEach
@@ -257,6 +258,6 @@ class DaggerKotlinIssueDetector : Detector(), SourceCodeScanner {
/** @return whether or not the [this] is a Kotlin `object` type. */
private fun UClass.isObject(): Boolean {
- return this is KotlinUClass && ktClass is KtObjectDeclaration
+ return sourcePsi is KtObjectDeclaration
}
}
diff --git a/java/dagger/model/BUILD b/java/dagger/model/BUILD
index 0be8fc5fc..71a6c6b7d 100644
--- a/java/dagger/model/BUILD
+++ b/java/dagger/model/BUILD
@@ -32,13 +32,10 @@ package(
],
)
-INTERNAL_PROXIES = ["BindingGraphProxies.java"]
-
filegroup(
name = "model-srcs",
srcs = glob(
["*.java"],
- exclude = INTERNAL_PROXIES,
),
)
@@ -49,27 +46,14 @@ java_library(
deps = [
"//java/dagger:core",
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:graph",
"//java/dagger/producers",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-java_library(
- name = "internal-proxies",
- srcs = INTERNAL_PROXIES,
- tags = ["maven:merged"],
- visibility = ["//:src"],
- deps = [
- ":model",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:graph",
- "@google_bazel_common//third_party/java/auto:value",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:value",
+ "//third_party/java/error_prone:annotations",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/graph",
+ "//third_party/java/javapoet",
+ "//third_party/java/jsr330_inject",
],
)
diff --git a/java/dagger/model/BindingGraphProxies.java b/java/dagger/model/BindingGraphProxies.java
deleted file mode 100644
index 85d4df8ca..000000000
--- a/java/dagger/model/BindingGraphProxies.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2018 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.model;
-
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.graph.ImmutableNetwork;
-import com.google.common.graph.Network;
-import dagger.model.BindingGraph.Edge;
-import dagger.model.BindingGraph.MissingBinding;
-import dagger.model.BindingGraph.Node;
-
-/**
- * Exposes package-private constructors to the {@code dagger.internal.codegen} package. <em>This
- * class should only be used in the Dagger implementation and is not part of any documented
- * API.</em>
- */
-public final class BindingGraphProxies {
-
- @AutoValue
- abstract static class BindingGraphImpl extends BindingGraph {
- @Override
- @Memoized
- public ImmutableSetMultimap<Class<? extends Node>, ? extends Node> nodesByClass() {
- return super.nodesByClass();
- }
- }
-
- @AutoValue
- abstract static class MissingBindingImpl extends MissingBinding {
- @Memoized
- @Override
- public abstract int hashCode();
-
- @Override
- public abstract boolean equals(Object o);
- }
-
- /** Creates a new {@link BindingGraph}. */
- public static BindingGraph bindingGraph(Network<Node, Edge> network, boolean isFullBindingGraph) {
- return new AutoValue_BindingGraphProxies_BindingGraphImpl(
- ImmutableNetwork.copyOf(network), isFullBindingGraph);
- }
-
- /** Creates a new {@link MissingBinding}. */
- public static MissingBinding missingBindingNode(ComponentPath component, Key key) {
- return new AutoValue_BindingGraphProxies_MissingBindingImpl(component, key);
- }
-
- private BindingGraphProxies() {}
-}
diff --git a/java/dagger/model/Key.java b/java/dagger/model/Key.java
index 03dd41c76..aeeabdff2 100644
--- a/java/dagger/model/Key.java
+++ b/java/dagger/model/Key.java
@@ -111,7 +111,7 @@ public abstract class Key {
* and {@code @A(c = "c", b = "b", attributeWithDefaultValue = "default value")}.
*/
// TODO(ronshapiro): move this to auto-common
- private static String stableAnnotationMirrorToString(AnnotationMirror qualifier) {
+ static String stableAnnotationMirrorToString(AnnotationMirror qualifier) {
StringBuilder builder = new StringBuilder("@").append(qualifier.getAnnotationType());
ImmutableMap<ExecutableElement, AnnotationValue> elementValues =
AnnotationMirrors.getAnnotationValuesWithDefaults(qualifier);
diff --git a/java/dagger/model/Scope.java b/java/dagger/model/Scope.java
index f48fa16df..c7ebfa811 100644
--- a/java/dagger/model/Scope.java
+++ b/java/dagger/model/Scope.java
@@ -24,9 +24,9 @@ import com.google.auto.common.MoreElements;
import com.google.auto.common.MoreTypes;
import com.google.auto.value.AutoValue;
import com.google.common.base.Equivalence;
+import com.squareup.javapoet.ClassName;
import dagger.Reusable;
import dagger.producers.ProductionScope;
-import java.lang.annotation.Annotation;
import javax.inject.Singleton;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.TypeElement;
@@ -66,26 +66,35 @@ public abstract class Scope {
* Returns {@code true} if {@code scopeAnnotationType} is a {@link javax.inject.Scope} annotation.
*/
public static boolean isScope(TypeElement scopeAnnotationType) {
- return isAnnotationPresent(scopeAnnotationType, javax.inject.Scope.class);
+ return isAnnotationPresent(scopeAnnotationType, SCOPE.canonicalName())
+ || isAnnotationPresent(scopeAnnotationType, SCOPE_JAVAX.canonicalName());
}
+ private static final ClassName PRODUCTION_SCOPE =
+ ClassName.get("dagger.producers", "ProductionScope");
+ private static final ClassName SINGLETON = ClassName.get("jakarta.inject", "Singleton");
+ private static final ClassName SINGLETON_JAVAX = ClassName.get("javax.inject", "Singleton");
+ private static final ClassName REUSABLE = ClassName.get("dagger", "Reusable");
+ private static final ClassName SCOPE = ClassName.get("jakarta.inject", "Scope");
+ private static final ClassName SCOPE_JAVAX = ClassName.get("javax.inject", "Scope");
+
/** Returns {@code true} if this scope is the {@link Singleton @Singleton} scope. */
public final boolean isSingleton() {
- return isScope(Singleton.class);
+ return isScope(SINGLETON) || isScope(SINGLETON_JAVAX);
}
/** Returns {@code true} if this scope is the {@link Reusable @Reusable} scope. */
public final boolean isReusable() {
- return isScope(Reusable.class);
+ return isScope(REUSABLE);
}
/** Returns {@code true} if this scope is the {@link ProductionScope @ProductionScope} scope. */
public final boolean isProductionScope() {
- return isScope(ProductionScope.class);
+ return isScope(PRODUCTION_SCOPE);
}
- private boolean isScope(Class<? extends Annotation> annotation) {
- return scopeAnnotationElement().getQualifiedName().contentEquals(annotation.getCanonicalName());
+ private boolean isScope(ClassName className) {
+ return scopeAnnotationElement().getQualifiedName().contentEquals(className.canonicalName());
}
/** Returns a debug representation of the scope. */
diff --git a/java/dagger/model/testing/BUILD b/java/dagger/model/testing/BUILD
index 9c9f44aea..722990aa0 100644
--- a/java/dagger/model/testing/BUILD
+++ b/java/dagger/model/testing/BUILD
@@ -31,11 +31,11 @@ java_library(
javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
deps = [
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
"//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/checker_framework_annotations",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/auto:value",
+ "//third_party/java/checker_framework_annotations",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/truth",
],
)
diff --git a/java/dagger/multibindings/ClassKey.java b/java/dagger/multibindings/ClassKey.java
index ac255457c..edc9ea356 100644
--- a/java/dagger/multibindings/ClassKey.java
+++ b/java/dagger/multibindings/ClassKey.java
@@ -16,11 +16,11 @@
package dagger.multibindings;
-import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import dagger.MapKey;
import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@@ -31,7 +31,11 @@ import java.lang.annotation.Target;
* member whose type is {@code Class<? extends Something>}.
*/
@Documented
-@Target(METHOD)
+// While METHOD is the only valid target for Dagger, FIELD was added to support Hilt's
+// @BindValueIntoMap and TYPE was added to support external extension types since it likely won't
+// cause confusion/maintenance issues as this isn't part of Dagger's core API.
+// See discussion on https://github.com/google/dagger/pull/2831#issuecomment-919417457 for details.
+@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RUNTIME)
@MapKey
public @interface ClassKey {
diff --git a/java/dagger/multibindings/IntKey.java b/java/dagger/multibindings/IntKey.java
index 55e79a1bf..1e7960f53 100644
--- a/java/dagger/multibindings/IntKey.java
+++ b/java/dagger/multibindings/IntKey.java
@@ -16,17 +16,21 @@
package dagger.multibindings;
-import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import dagger.MapKey;
import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/** A {@link MapKey} annotation for maps with {@code int} keys. */
@Documented
-@Target(METHOD)
+// While METHOD is the only valid target for Dagger, FIELD was added to support Hilt's
+// @BindValueIntoMap and TYPE was added to support external extension types since it likely won't
+// cause confusion/maintenance issues as this isn't part of Dagger's core API.
+// See discussion on https://github.com/google/dagger/pull/2831#issuecomment-919417457 for details.
+@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RUNTIME)
@MapKey
public @interface IntKey {
diff --git a/java/dagger/multibindings/LongKey.java b/java/dagger/multibindings/LongKey.java
index 71d0fe116..802478f16 100644
--- a/java/dagger/multibindings/LongKey.java
+++ b/java/dagger/multibindings/LongKey.java
@@ -16,17 +16,21 @@
package dagger.multibindings;
-import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import dagger.MapKey;
import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/** A {@link MapKey} annotation for maps with {@code long} keys. */
@Documented
-@Target(METHOD)
+// While METHOD is the only valid target for Dagger, FIELD was added to support Hilt's
+// @BindValueIntoMap and TYPE was added to support external extension types since it likely won't
+// cause confusion/maintenance issues as this isn't part of Dagger's core API.
+// See discussion on https://github.com/google/dagger/pull/2831#issuecomment-919417457 for details.
+@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RUNTIME)
@MapKey
public @interface LongKey {
diff --git a/java/dagger/multibindings/StringKey.java b/java/dagger/multibindings/StringKey.java
index 5dad8e3e9..c773ceab6 100644
--- a/java/dagger/multibindings/StringKey.java
+++ b/java/dagger/multibindings/StringKey.java
@@ -16,17 +16,21 @@
package dagger.multibindings;
-import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import dagger.MapKey;
import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/** A {@link MapKey} annotation for maps with {@link String} keys. */
@Documented
-@Target(METHOD)
+// While METHOD is the only valid target for Dagger, FIELD was added to support Hilt's
+// @BindValueIntoMap and TYPE was added to support external extension types since it likely won't
+// cause confusion/maintenance issues as this isn't part of Dagger's core API.
+// See discussion on https://github.com/google/dagger/pull/2831#issuecomment-919417457 for details.
+@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RUNTIME)
@MapKey
public @interface StringKey {
diff --git a/java/dagger/producers/BUILD b/java/dagger/producers/BUILD
index 41762e6e1..b966ad588 100644
--- a/java/dagger/producers/BUILD
+++ b/java/dagger/producers/BUILD
@@ -42,18 +42,18 @@ java_library(
javacopts = SOURCE_7_TARGET_7 + DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
tags = ["maven_coordinates=com.google.dagger:dagger-producers:" + POM_VERSION],
exports = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:concurrent",
- "@google_bazel_common//third_party/java/jsr330_inject",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/util/concurrent",
+ "//third_party/java/jsr330_inject",
],
deps = [
"//java/dagger:core",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "@google_bazel_common//third_party/java/checker_framework_annotations",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@google_bazel_common//third_party/java/jsr330_inject",
+ "//third_party/java/checker_framework_annotations",
+ "//third_party/java/error_prone:annotations",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/util/concurrent",
+ "//third_party/java/jsr330_inject",
],
)
diff --git a/java/dagger/producers/internal/AnnotationUsages.java b/java/dagger/producers/internal/AnnotationUsages.java
new file mode 100644
index 000000000..9e7760837
--- /dev/null
+++ b/java/dagger/producers/internal/AnnotationUsages.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.producers.internal;
+
+import dagger.producers.Production;
+import dagger.producers.ProductionScope;
+
+/**
+ * This class should never be referenced directly!
+ *
+ * This class should only be used by Dagger's annotation processor to get access to the annotations
+ * types.
+ */
+final class AnnotationUsages {
+ @Production
+ static final class ProductionUsage {}
+
+ @ProductionImplementation
+ static final class ProductionImplementationUsage {}
+
+ @ProductionScope
+ static final class ProductionScopeUsage {}
+
+ private AnnotationUsages() {}
+}
diff --git a/java/dagger/spi/BUILD b/java/dagger/spi/BUILD
index cbec4658d..529842ad3 100644
--- a/java/dagger/spi/BUILD
+++ b/java/dagger/spi/BUILD
@@ -30,6 +30,7 @@ filegroup(
name = "spi-srcs",
srcs = glob(["*.java"]) + [
"//java/dagger/model:model-srcs",
+ "//java/dagger/spi/model:model-srcs",
],
)
@@ -40,15 +41,13 @@ java_library(
tags = ["maven_coordinates=com.google.dagger:dagger-spi:" + POM_VERSION],
exports = [
"//java/dagger/model",
+ "//java/dagger/spi/model",
],
deps = [
"//java/dagger:core",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
"//java/dagger/model",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@google_bazel_common//third_party/java/jsr330_inject",
+ "//third_party/java/auto:value",
+ "//third_party/java/error_prone:annotations",
],
)
@@ -59,23 +58,33 @@ gen_maven_artifact(
artifact_target = ":spi",
artifact_target_libs = [
"//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
"//java/dagger/model",
+ "//java/dagger/spi/model",
],
artifact_target_maven_deps = [
"com.google.auto:auto-common",
"com.google.code.findbugs:jsr305",
"com.google.dagger:dagger-producers",
"com.google.dagger:dagger",
+ "com.google.devtools.ksp:symbol-processing-api",
"com.google.guava:failureaccess",
"com.google.guava:guava",
"com.squareup:javapoet",
"javax.inject:javax.inject",
+ "org.jetbrains.kotlin:kotlin-stdlib",
+ "org.jetbrains.kotlin:kotlin-stdlib-jdk8",
],
javadoc_root_packages = [
"dagger.model",
"dagger.spi",
],
javadoc_srcs = [":spi-srcs"],
- shaded_deps = ["@maven//:com_google_auto_auto_common"],
- shaded_rules = ["rule com.google.auto.common.** dagger.spi.shaded.auto.common.@1"],
+ # The shaded deps are added using jarjar, but they won't be shaded until later
+ # due to: https://github.com/google/dagger/issues/2765. For the shaded rules see
+ # util/deploy-dagger.sh
+ shaded_deps = [
+ "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing:xprocessing-jar",
+ ],
)
diff --git a/java/dagger/spi/model/BUILD b/java/dagger/spi/model/BUILD
new file mode 100644
index 000000000..9c825b4cb
--- /dev/null
+++ b/java/dagger/spi/model/BUILD
@@ -0,0 +1,60 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Description:
+# Dagger's core APIs exposed for plugins
+
+load("@rules_java//java:defs.bzl", "java_library")
+load(
+ "//:build_defs.bzl",
+ "DOCLINT_HTML_AND_SYNTAX",
+ "DOCLINT_REFERENCES",
+)
+
+package(
+ default_visibility = [
+ # The dagger/spi should be the only direct dependent on this target.
+ # If you need to depend on :model, depend on dagger/spi instead so
+ # that pom files correctly pick up the spi maven dependency.
+ # TODO(bcorso): Consider if :model should have its own maven coordinates.
+ "//java/dagger/spi:__pkg__",
+ ],
+)
+
+filegroup(
+ name = "model-srcs",
+ srcs = glob(["*.java"]),
+)
+
+java_library(
+ name = "model",
+ srcs = [":model-srcs"],
+ javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+ deps = [
+ "//java/dagger:core",
+ "//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
+ "//java/dagger/producers",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:value",
+ "//third_party/java/error_prone:annotations",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/graph",
+ "//third_party/java/javapoet",
+ "//third_party/java/jsr305_annotations",
+ "//third_party/java/jsr330_inject",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
+ ],
+)
diff --git a/java/dagger/spi/model/Binding.java b/java/dagger/spi/model/Binding.java
new file mode 100644
index 000000000..3c6c6a165
--- /dev/null
+++ b/java/dagger/spi/model/Binding.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+import com.google.common.collect.ImmutableSet;
+import dagger.spi.model.BindingGraph.MaybeBinding;
+import java.util.Optional;
+
+/**
+ * The association between a {@link Key} and the way in which instances of the key are provided.
+ * Includes any {@linkplain DependencyRequest dependencies} that are needed in order to provide the
+ * instances.
+ *
+ * <p>If a binding is owned by more than one component, there is one {@code Binding} for every
+ * owning component.
+ */
+public interface Binding extends MaybeBinding {
+ @Override
+ ComponentPath componentPath();
+
+ /** @deprecated This always returns {@code Optional.of(this)}. */
+ @Override
+ @Deprecated
+ default Optional<Binding> binding() {
+ return Optional.of(this);
+ }
+ /**
+ * The dependencies of this binding. The order of the dependencies corresponds to the order in
+ * which they will be injected when the binding is requested.
+ */
+ ImmutableSet<DependencyRequest> dependencies();
+
+ /**
+ * The {@link DaggerElement} that declares this binding. Absent for
+ * {@linkplain BindingKind binding kinds} that are not always declared by exactly one element.
+ *
+ * <p>For example, consider {@link BindingKind#MULTIBOUND_SET}. A component with many
+ * {@code @IntoSet} bindings for the same key will have a synthetic binding that depends on all
+ * contributions, but with no identifiying binding element. A {@code @Multibinds} method will also
+ * contribute a synthetic binding, but since multiple {@code @Multibinds} methods can coexist in
+ * the same component (and contribute to one single binding), it has no binding element.
+ */
+ Optional<DaggerElement> bindingElement();
+
+ /**
+ * The {@link DaggerTypeElement} of the module which contributes this binding. Absent for bindings
+ * that have no {@link #bindingElement() binding element}.
+ */
+ Optional<DaggerTypeElement> contributingModule();
+
+ /**
+ * Returns {@code true} if using this binding requires an instance of the {@link
+ * #contributingModule()}.
+ */
+ boolean requiresModuleInstance();
+
+ /** The scope of this binding if it has one. */
+ Optional<Scope> scope();
+
+ /**
+ * Returns {@code true} if this binding may provide {@code null} instead of an instance of {@link
+ * #key()}. Nullable bindings cannot be requested from {@linkplain DependencyRequest#isNullable()
+ * non-nullable dependency requests}.
+ */
+ boolean isNullable();
+
+ /** Returns {@code true} if this is a production binding, e.g. an {@code @Produces} method. */
+ boolean isProduction();
+
+ /** The kind of binding this instance represents. */
+ BindingKind kind();
+
+}
diff --git a/java/dagger/spi/model/BindingGraph.java b/java/dagger/spi/model/BindingGraph.java
new file mode 100644
index 000000000..f10ffe2f6
--- /dev/null
+++ b/java/dagger/spi/model/BindingGraph.java
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+import static com.google.common.collect.Sets.intersection;
+import static com.google.common.graph.Graphs.inducedSubgraph;
+import static com.google.common.graph.Graphs.reachableNodes;
+import static com.google.common.graph.Graphs.transpose;
+import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSetMultimap;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.graph.EndpointPair;
+import com.google.common.graph.ImmutableNetwork;
+import com.google.common.graph.MutableNetwork;
+import com.google.common.graph.Network;
+import com.google.common.graph.NetworkBuilder;
+import dagger.Module;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+/**
+ * A graph of bindings, dependency requests, and components.
+ *
+ * <p>A {@link BindingGraph} represents one of the following:
+ *
+ * <ul>
+ * <li>an entire component hierarchy rooted at a {@link dagger.Component} or {@link
+ * dagger.producers.ProductionComponent}
+ * <li>a partial component hierarchy rooted at a {@link dagger.Subcomponent} or {@link
+ * dagger.producers.ProductionSubcomponent} (only when the value of {@code
+ * -Adagger.fullBindingGraphValidation} is not {@code NONE})
+ * <li>the bindings installed by a {@link Module} or {@link dagger.producers.ProducerModule},
+ * including all subcomponents generated by {@link Module#subcomponents()} ()} and {@link
+ * dagger.producers.ProducerModule#subcomponents()} ()}
+ * </ul>
+ *
+ * In the case of a {@link BindingGraph} representing a module, the root {@link ComponentNode} will
+ * actually represent the module type. The graph will also be a {@linkplain #isFullBindingGraph()
+ * full binding graph}, which means it will contain all bindings in all modules, as well as nodes
+ * for their dependencies. Otherwise it will contain only bindings that are reachable from at least
+ * one {@linkplain #entryPointEdges() entry point}.
+ *
+ * <h3>Nodes</h3>
+ *
+ * <p>There is a <b>{@link Binding}</b> for each owned binding in the graph. If a binding is owned
+ * by more than one component, there is one binding object for that binding for every owning
+ * component.
+ *
+ * <p>There is a <b>{@linkplain ComponentNode component node}</b> (without a binding) for each
+ * component in the graph.
+ *
+ * <h3>Edges</h3>
+ *
+ * <p>There is a <b>{@linkplain DependencyEdge dependency edge}</b> for each dependency request in
+ * the graph. Its target node is the binding for the binding that satisfies the request. For entry
+ * point dependency requests, the source node is the component node for the component for which it
+ * is an entry point. For other dependency requests, the source node is the binding for the binding
+ * that contains the request.
+ *
+ * <p>There is a <b>subcomponent edge</b> for each parent-child component relationship in the graph.
+ * The target node is the component node for the child component. For subcomponents defined by a
+ * {@linkplain SubcomponentCreatorBindingEdge subcomponent creator binding} (either a method on the
+ * component or a set of {@code @Module.subcomponents} annotation values), the source node is the
+ * binding for the {@code @Subcomponent.Builder} type. For subcomponents defined by {@linkplain
+ * ChildFactoryMethodEdge subcomponent factory methods}, the source node is the component node for
+ * the parent.
+ *
+ * <p><b>Note that this API is experimental and will change.</b>
+ */
+public abstract class BindingGraph {
+ /** Returns the graph in its {@link Network} representation. */
+ public abstract ImmutableNetwork<Node, Edge> network();
+
+ @Override
+ public String toString() {
+ return network().toString();
+ }
+
+ /**
+ * Returns {@code true} if this graph was constructed from a module for full binding graph
+ * validation.
+ *
+ * @deprecated use {@link #isFullBindingGraph()} to tell if this is a full binding graph, or
+ * {@link ComponentNode#isRealComponent() rootComponentNode().isRealComponent()} to tell if
+ * the root component node is really a component or derived from a module. Dagger can generate
+ * full binding graphs for components and subcomponents as well as modules.
+ */
+ @Deprecated
+ public boolean isModuleBindingGraph() {
+ return !rootComponentNode().isRealComponent();
+ }
+
+ /**
+ * Returns {@code true} if this is a full binding graph, which contains all bindings installed in
+ * the component, or {@code false} if it is a reachable binding graph, which contains only
+ * bindings that are reachable from at least one {@linkplain #entryPointEdges() entry point}.
+ *
+ * @see <a href="https://dagger.dev/compiler-options#full-binding-graph-validation">Full binding
+ * graph validation</a>
+ */
+ public abstract boolean isFullBindingGraph();
+
+ /**
+ * Returns {@code true} if the {@link #rootComponentNode()} is a subcomponent. This occurs in
+ * when {@code -Adagger.fullBindingGraphValidation} is used in a compilation with a subcomponent.
+ *
+ * @deprecated use {@link ComponentNode#isSubcomponent() rootComponentNode().isSubcomponent()}
+ * instead
+ */
+ @Deprecated
+ public boolean isPartialBindingGraph() {
+ return rootComponentNode().isSubcomponent();
+ }
+
+ /** Returns the bindings. */
+ public ImmutableSet<Binding> bindings() {
+ return nodes(Binding.class);
+ }
+
+ /** Returns the bindings for a key. */
+ public ImmutableSet<Binding> bindings(Key key) {
+ return nodes(Binding.class).stream()
+ .filter(binding -> binding.key().equals(key))
+ .collect(toImmutableSet());
+ }
+
+ /** Returns the nodes that represent missing bindings. */
+ public ImmutableSet<MissingBinding> missingBindings() {
+ return nodes(MissingBinding.class);
+ }
+
+ /** Returns the component nodes. */
+ public ImmutableSet<ComponentNode> componentNodes() {
+ return nodes(ComponentNode.class);
+ }
+
+ /** Returns the component node for a component. */
+ public Optional<ComponentNode> componentNode(ComponentPath component) {
+ return componentNodes().stream()
+ .filter(node -> node.componentPath().equals(component))
+ .findFirst();
+ }
+
+ /** Returns the component nodes for a component. */
+ public ImmutableSet<ComponentNode> componentNodes(DaggerTypeElement component) {
+ return componentNodes().stream()
+ .filter(node -> node.componentPath().currentComponent().equals(component))
+ .collect(toImmutableSet());
+ }
+
+ /** Returns the component node for the root component. */
+ public ComponentNode rootComponentNode() {
+ return componentNodes().stream()
+ .filter(node -> node.componentPath().atRoot())
+ .findFirst()
+ .get();
+ }
+
+ /** Returns the dependency edges. */
+ public ImmutableSet<DependencyEdge> dependencyEdges() {
+ return dependencyEdgeStream().collect(toImmutableSet());
+ }
+
+ /**
+ * Returns the dependency edges for the dependencies of a binding. For valid graphs, each {@link
+ * DependencyRequest} will map to a single {@link DependencyEdge}. When conflicting bindings exist
+ * for a key, the multimap will have several edges for that {@link DependencyRequest}. Graphs that
+ * have no binding for a key will have an edge whose {@linkplain EndpointPair#target() target
+ * node} is a {@link MissingBinding}.
+ */
+ public ImmutableSetMultimap<DependencyRequest, DependencyEdge> dependencyEdges(
+ Binding binding) {
+ return dependencyEdgeStream(binding)
+ .collect(toImmutableSetMultimap(DependencyEdge::dependencyRequest, edge -> edge));
+ }
+
+ /** Returns the dependency edges for a dependency request. */
+ public ImmutableSet<DependencyEdge> dependencyEdges(DependencyRequest dependencyRequest) {
+ return dependencyEdgeStream()
+ .filter(edge -> edge.dependencyRequest().equals(dependencyRequest))
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Returns the dependency edges for the entry points of a given {@code component}. Each edge's
+ * source node is that component's component node.
+ */
+ public ImmutableSet<DependencyEdge> entryPointEdges(ComponentPath component) {
+ return dependencyEdgeStream(componentNode(component).get()).collect(toImmutableSet());
+ }
+
+ private Stream<DependencyEdge> dependencyEdgeStream(Node node) {
+ return network().outEdges(node).stream().flatMap(instancesOf(DependencyEdge.class));
+ }
+
+ /**
+ * Returns the dependency edges for all entry points for all components and subcomponents. Each
+ * edge's source node is a component node.
+ */
+ public ImmutableSet<DependencyEdge> entryPointEdges() {
+ return entryPointEdgeStream().collect(toImmutableSet());
+ }
+
+ /** Returns the binding or missing binding nodes that directly satisfy entry points. */
+ public ImmutableSet<MaybeBinding> entryPointBindings() {
+ return entryPointEdgeStream()
+ .map(edge -> (MaybeBinding) network().incidentNodes(edge).target())
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Returns the edges for entry points that transitively depend on a binding or missing binding for
+ * a key.
+ */
+ public ImmutableSet<DependencyEdge> entryPointEdgesDependingOnBinding(
+ MaybeBinding binding) {
+ ImmutableNetwork<Node, DependencyEdge> dependencyGraph = dependencyGraph();
+ Network<Node, DependencyEdge> subgraphDependingOnBinding =
+ inducedSubgraph(
+ dependencyGraph, reachableNodes(transpose(dependencyGraph).asGraph(), binding));
+ return intersection(entryPointEdges(), subgraphDependingOnBinding.edges()).immutableCopy();
+ }
+
+ /** Returns the bindings that directly request a given binding as a dependency. */
+ public ImmutableSet<Binding> requestingBindings(MaybeBinding binding) {
+ return network().predecessors(binding).stream()
+ .flatMap(instancesOf(Binding.class))
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Returns the bindings that a given binding directly requests as a dependency. Does not include
+ * any {@link MissingBinding}s.
+ *
+ * @see #requestedMaybeMissingBindings(Binding)
+ */
+ public ImmutableSet<Binding> requestedBindings(Binding binding) {
+ return network().successors(binding).stream()
+ .flatMap(instancesOf(Binding.class))
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Returns the bindings or missing bindings that a given binding directly requests as a
+ * dependency.
+ *
+ * @see #requestedBindings(Binding)
+ */
+ public ImmutableSet<MaybeBinding> requestedMaybeMissingBindings(Binding binding) {
+ return network().successors(binding).stream()
+ .flatMap(instancesOf(MaybeBinding.class))
+ .collect(toImmutableSet());
+ }
+
+ /** Returns a subnetwork that contains all nodes but only {@link DependencyEdge}s. */
+ // TODO(dpb): Make public. Cache.
+ private ImmutableNetwork<Node, DependencyEdge> dependencyGraph() {
+ MutableNetwork<Node, DependencyEdge> dependencyGraph =
+ NetworkBuilder.from(network())
+ .expectedNodeCount(network().nodes().size())
+ .expectedEdgeCount((int) dependencyEdgeStream().count())
+ .build();
+ network().nodes().forEach(dependencyGraph::addNode); // include disconnected nodes
+ dependencyEdgeStream()
+ .forEach(
+ edge -> {
+ EndpointPair<Node> endpoints = network().incidentNodes(edge);
+ dependencyGraph.addEdge(endpoints.source(), endpoints.target(), edge);
+ });
+ return ImmutableNetwork.copyOf(dependencyGraph);
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ private <N extends Node> ImmutableSet<N> nodes(Class<N> clazz) {
+ return (ImmutableSet) nodesByClass().get(clazz);
+ }
+
+ private static final ImmutableSet<Class<? extends Node>> NODE_TYPES =
+ ImmutableSet.of(Binding.class, MissingBinding.class, ComponentNode.class);
+
+ protected ImmutableSetMultimap<Class<? extends Node>, ? extends Node> nodesByClass() {
+ return network().nodes().stream()
+ .collect(
+ toImmutableSetMultimap(
+ node ->
+ NODE_TYPES.stream().filter(clazz -> clazz.isInstance(node)).findFirst().get(),
+ node -> node));
+ }
+
+ private Stream<DependencyEdge> dependencyEdgeStream() {
+ return network().edges().stream().flatMap(instancesOf(DependencyEdge.class));
+ }
+
+ private Stream<DependencyEdge> entryPointEdgeStream() {
+ return dependencyEdgeStream().filter(DependencyEdge::isEntryPoint);
+ }
+
+ /**
+ * An edge in the binding graph. Either a {@link DependencyEdge}, a {@link
+ * ChildFactoryMethodEdge}, or a {@link SubcomponentCreatorBindingEdge}.
+ */
+ public interface Edge {}
+
+ /**
+ * An edge that represents a dependency on a binding.
+ *
+ * <p>Because one {@link DependencyRequest} may represent a dependency from two bindings (e.g., a
+ * dependency of {@code Foo<String>} and {@code Foo<Number>} may have the same key and request
+ * element), this class does not override {@link #equals(Object)} to use value semantics.
+ *
+ * <p>For entry points, the source node is the {@link ComponentNode} that contains the entry
+ * point. Otherwise the source node is a {@link Binding}.
+ *
+ * <p>For dependencies on missing bindings, the target node is a {@link MissingBinding}. Otherwise
+ * the target node is a {@link Binding}.
+ */
+ public interface DependencyEdge extends Edge {
+ /** The dependency request. */
+ DependencyRequest dependencyRequest();
+
+ /** Returns {@code true} if this edge represents an entry point. */
+ boolean isEntryPoint();
+ }
+
+ /**
+ * An edge that represents a subcomponent factory method linking a parent component to a child
+ * subcomponent.
+ */
+ public interface ChildFactoryMethodEdge extends Edge {
+ /** The subcomponent factory method element. */
+ DaggerExecutableElement factoryMethod();
+ }
+
+ /**
+ * An edge that represents the link between a parent component and a child subcomponent implied by
+ * a subcomponent creator ({@linkplain dagger.Subcomponent.Builder builder} or {@linkplain
+ * dagger.Subcomponent.Factory factory}) binding.
+ *
+ * <p>The {@linkplain com.google.common.graph.EndpointPair#source() source node} of this edge is a
+ * {@link Binding} for the subcomponent creator {@link Key} and the {@linkplain
+ * com.google.common.graph.EndpointPair#target() target node} is a {@link ComponentNode} for the
+ * child subcomponent.
+ */
+ public interface SubcomponentCreatorBindingEdge extends Edge {
+ /**
+ * The modules that {@linkplain Module#subcomponents() declare the subcomponent} that generated
+ * this edge. Empty if the parent component has a subcomponent creator method and there are no
+ * declaring modules.
+ */
+ ImmutableSet<DaggerTypeElement> declaringModules();
+ }
+
+ /** A node in the binding graph. Either a {@link Binding} or a {@link ComponentNode}. */
+ // TODO(dpb): Make all the node/edge types top-level.
+ public interface Node {
+ /** The component this node belongs to. */
+ ComponentPath componentPath();
+ }
+
+ /** A node in the binding graph that is either a {@link Binding} or a {@link MissingBinding}. */
+ public interface MaybeBinding extends Node {
+
+ /** The component that owns the binding, or in which the binding is missing. */
+ @Override
+ ComponentPath componentPath();
+
+ /** The key of the binding, or for which there is no binding. */
+ Key key();
+
+ /** The binding, or empty if missing. */
+ Optional<Binding> binding();
+ }
+
+ /** A node in the binding graph that represents a missing binding for a key in a component. */
+ public abstract static class MissingBinding implements MaybeBinding {
+ /** The component in which the binding is missing. */
+ @Override
+ public abstract ComponentPath componentPath();
+
+ /** The key for which there is no binding. */
+ @Override
+ public abstract Key key();
+
+ /** @deprecated This always returns {@code Optional.empty()}. */
+ @Override
+ @Deprecated
+ public Optional<Binding> binding() {
+ return Optional.empty();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("missing binding for %s in %s", key(), componentPath());
+ }
+ }
+
+ /**
+ * A <b>component node</b> in the graph. Every entry point {@linkplain DependencyEdge dependency
+ * edge}'s source node is a component node for the component containing the entry point.
+ */
+ public interface ComponentNode extends Node {
+
+ /** The component represented by this node. */
+ @Override
+ ComponentPath componentPath();
+
+ /**
+ * Returns {@code true} if the component is a {@code @Subcomponent} or
+ * {@code @ProductionSubcomponent}.
+ */
+ boolean isSubcomponent();
+
+ /**
+ * Returns {@code true} if the component is a real component, or {@code false} if it is a
+ * fictional component based on a module.
+ */
+ boolean isRealComponent();
+
+ /** The entry points on this component. */
+ ImmutableSet<DependencyRequest> entryPoints();
+
+ /** The scopes declared on this component. */
+ ImmutableSet<Scope> scopes();
+ }
+}
diff --git a/java/dagger/spi/model/BindingGraphPlugin.java b/java/dagger/spi/model/BindingGraphPlugin.java
new file mode 100644
index 000000000..41e421975
--- /dev/null
+++ b/java/dagger/spi/model/BindingGraphPlugin.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.Messager;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+// TODO(bcorso): Move this into dagger/spi?
+/**
+ * A pluggable visitor for {@link BindingGraph}.
+ *
+ * <p>Note: This is still experimental and will change.
+ */
+public interface BindingGraphPlugin {
+ /**
+ * Called once for each valid root binding graph encountered by the Dagger processor. May report
+ * diagnostics using {@code diagnosticReporter}.
+ */
+ void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter);
+
+ /**
+ * Initializes this plugin with a {@link Filer} that it can use to write Java or other files based
+ * on the binding graph. This will be called once per instance of this plugin, before any graph is
+ * {@linkplain #visitGraph(BindingGraph, DiagnosticReporter) visited}.
+ *
+ * @see javax.annotation.processing.ProcessingEnvironment#getFiler()
+ */
+ default void initFiler(Filer filer) {}
+
+ /**
+ * Initializes this plugin with a {@link Types} instance. This will be called once per instance of
+ * this plugin, before any graph is {@linkplain #visitGraph(BindingGraph, DiagnosticReporter)
+ * visited}.
+ *
+ * @see javax.annotation.processing.ProcessingEnvironment#getTypeUtils()
+ */
+ default void initTypes(Types types) {}
+
+ /**
+ * Initializes this plugin with a {@link Elements} instance. This will be called once per instance
+ * of this plugin, before any graph is {@linkplain #visitGraph(BindingGraph, DiagnosticReporter)
+ * visited}.
+ *
+ * @see javax.annotation.processing.ProcessingEnvironment#getElementUtils()
+ */
+ default void initElements(Elements elements) {}
+
+ /**
+ * Initializes this plugin with a filtered view of the options passed on the {@code javac}
+ * command-line for all keys from {@link #supportedOptions()}. This will be called once per
+ * instance of this plugin, before any graph is {@linkplain #visitGraph(BindingGraph,
+ * DiagnosticReporter) visited}.
+ *
+ * @see javax.annotation.processing.ProcessingEnvironment#getOptions()
+ */
+ default void initOptions(Map<String, String> options) {}
+
+ /**
+ * Returns the annotation-processing options that this plugin uses to configure behavior.
+ *
+ * @see javax.annotation.processing.Processor#getSupportedOptions()
+ */
+ default Set<String> supportedOptions() {
+ return Collections.emptySet();
+ }
+
+ /**
+ * A distinguishing name of the plugin that will be used in diagnostics printed to the {@link
+ * Messager}. By default, the {@linkplain Class#getCanonicalName() fully qualified name} of the
+ * plugin is used.
+ */
+ default String pluginName() {
+ return getClass().getCanonicalName();
+ }
+}
diff --git a/java/dagger/spi/model/BindingKind.java b/java/dagger/spi/model/BindingKind.java
new file mode 100644
index 000000000..b854b5300
--- /dev/null
+++ b/java/dagger/spi/model/BindingKind.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+/** Represents the different kinds of {@link Binding}s that can exist in a binding graph. */
+public enum BindingKind {
+ /** A binding for an {@link javax.inject.Inject}-annotated constructor. */
+ INJECTION,
+
+ /** A binding for a {@link dagger.Provides}-annotated method. */
+ PROVISION,
+
+ /**
+ * A binding for an {@link javax.inject.Inject}-annotated constructor that contains at least one
+ * {@link dagger.assisted.Assisted}-annotated parameter.
+ */
+ ASSISTED_INJECTION,
+
+ /** A binding for an {@link dagger.assisted.AssistedFactory}-annotated type. */
+ ASSISTED_FACTORY,
+
+ /**
+ * An implicit binding for a {@link dagger.Component}- or {@link
+ * dagger.producers.ProductionComponent}-annotated type.
+ */
+ COMPONENT,
+
+ /**
+ * A binding for a provision method on a component's {@linkplain dagger.Component#dependencies()
+ * dependency}.
+ */
+ COMPONENT_PROVISION,
+
+ /**
+ * A binding for an instance of a component's {@linkplain dagger.Component#dependencies()
+ * dependency}.
+ */
+ COMPONENT_DEPENDENCY,
+
+ /** A binding for a {@link dagger.MembersInjector} of a type. */
+ MEMBERS_INJECTOR,
+
+ /**
+ * A binding for a subcomponent creator (a {@linkplain dagger.Subcomponent.Builder builder} or
+ * {@linkplain dagger.Subcomponent.Factory factory}).
+ *
+ * @since 2.22 (previously named {@code SUBCOMPONENT_BUILDER})
+ */
+ SUBCOMPONENT_CREATOR,
+
+ /** A binding for a {@link dagger.BindsInstance}-annotated builder method. */
+ BOUND_INSTANCE,
+
+ /** A binding for a {@link dagger.producers.Produces}-annotated method. */
+ PRODUCTION,
+
+ /**
+ * A binding for a production method on a production component's {@linkplain
+ * dagger.producers.ProductionComponent#dependencies()} dependency} that returns a {@link
+ * com.google.common.util.concurrent.ListenableFuture} or {@link
+ * com.google.common.util.concurrent.FluentFuture}. Methods on production component dependencies
+ * that don't return a future are considered {@linkplain #COMPONENT_PROVISION component provision
+ * bindings}.
+ */
+ COMPONENT_PRODUCTION,
+
+ /**
+ * A synthetic binding for a multibound set that depends on individual multibinding {@link
+ * #PROVISION} or {@link #PRODUCTION} contributions.
+ */
+ MULTIBOUND_SET,
+
+ /**
+ * A synthetic binding for a multibound map that depends on the individual multibinding {@link
+ * #PROVISION} or {@link #PRODUCTION} contributions.
+ */
+ MULTIBOUND_MAP,
+
+ /**
+ * A synthetic binding for {@code Optional} of a type or a {@link javax.inject.Provider}, {@link
+ * dagger.Lazy}, or {@code Provider} of {@code Lazy} of a type. Generated by a {@link
+ * dagger.BindsOptionalOf} declaration.
+ */
+ OPTIONAL,
+
+ /**
+ * A binding for {@link dagger.Binds}-annotated method that that delegates from requests for one
+ * key to another.
+ */
+ // TODO(dpb,ronshapiro): This name is confusing and could use work. Not all usages of @Binds
+ // bindings are simple delegations and we should have a name that better reflects that
+ DELEGATE,
+
+ /** A binding for a members injection method on a component. */
+ MEMBERS_INJECTION,
+ ;
+
+ /**
+ * Returns {@code true} if this is a kind of multibinding (not a contribution to a multibinding,
+ * but the multibinding itself).
+ */
+ public boolean isMultibinding() {
+ switch (this) {
+ case MULTIBOUND_MAP:
+ case MULTIBOUND_SET:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+}
diff --git a/java/dagger/spi/model/CompilerEnvironment.java b/java/dagger/spi/model/CompilerEnvironment.java
new file mode 100644
index 000000000..28553e4c3
--- /dev/null
+++ b/java/dagger/spi/model/CompilerEnvironment.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+/** Types for the compiler in use for annotation processing. */
+public enum CompilerEnvironment {
+ JAVA,
+ KSP
+}
diff --git a/java/dagger/spi/model/ComponentPath.java b/java/dagger/spi/model/ComponentPath.java
new file mode 100644
index 000000000..74195e430
--- /dev/null
+++ b/java/dagger/spi/model/ComponentPath.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Iterables.getLast;
+import static java.util.stream.Collectors.joining;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableList;
+import com.squareup.javapoet.ClassName;
+
+/** A path containing a component and all of its ancestor components. */
+@AutoValue
+public abstract class ComponentPath {
+ /** Returns a new {@link ComponentPath} from {@code components}. */
+ public static ComponentPath create(Iterable<DaggerTypeElement> components) {
+ return new AutoValue_ComponentPath(ImmutableList.copyOf(components));
+ }
+
+ /**
+ * Returns the component types, starting from the {@linkplain #rootComponent() root
+ * component} and ending with the {@linkplain #currentComponent() current component}.
+ */
+ public abstract ImmutableList<DaggerTypeElement> components();
+
+ /**
+ * Returns the root {@link dagger.Component}- or {@link
+ * dagger.producers.ProductionComponent}-annotated type
+ */
+ public final DaggerTypeElement rootComponent() {
+ return components().get(0);
+ }
+
+ /** Returns the component at the end of the path. */
+ @Memoized
+ public DaggerTypeElement currentComponent() {
+ return getLast(components());
+ }
+
+ /**
+ * Returns the parent of the {@linkplain #currentComponent()} current component}.
+ *
+ * @throws IllegalStateException if the current graph is the {@linkplain #atRoot() root component}
+ */
+ public final DaggerTypeElement parentComponent() {
+ checkState(!atRoot());
+ return components().reverse().get(1);
+ }
+
+ /**
+ * Returns this path's parent path.
+ *
+ * @throws IllegalStateException if the current graph is the {@linkplain #atRoot() root component}
+ */
+ // TODO(ronshapiro): consider memoizing this
+ public final ComponentPath parent() {
+ checkState(!atRoot());
+ return create(components().subList(0, components().size() - 1));
+ }
+
+ /** Returns the path from the root component to the {@code child} of the current component. */
+ public final ComponentPath childPath(DaggerTypeElement child) {
+ return create(
+ ImmutableList.<DaggerTypeElement>builder().addAll(components()).add(child).build());
+ }
+
+ /**
+ * Returns {@code true} if the {@linkplain #currentComponent()} current component} is the
+ * {@linkplain #rootComponent()} root component}.
+ */
+ public final boolean atRoot() {
+ return components().size() == 1;
+ }
+
+ @Override
+ public final String toString() {
+ return components().stream()
+ .map(DaggerTypeElement::className)
+ .map(ClassName::canonicalName)
+ .collect(joining(" → "));
+ }
+
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ @Override
+ public abstract boolean equals(Object obj);
+}
diff --git a/java/dagger/spi/model/DaggerAnnotation.java b/java/dagger/spi/model/DaggerAnnotation.java
new file mode 100644
index 000000000..42b12d525
--- /dev/null
+++ b/java/dagger/spi/model/DaggerAnnotation.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+
+import androidx.room.compiler.processing.XAnnotation;
+import com.google.auto.common.AnnotationMirrors;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Preconditions;
+import com.squareup.javapoet.ClassName;
+import javax.lang.model.element.AnnotationMirror;
+
+/** Wrapper type for an annotation. */
+@AutoValue
+public abstract class DaggerAnnotation {
+ private XAnnotation annotation;
+
+ public static DaggerAnnotation from(XAnnotation annotation) {
+ Preconditions.checkNotNull(annotation);
+ DaggerAnnotation daggerAnnotation =
+ new AutoValue_DaggerAnnotation(AnnotationMirrors.equivalence().wrap(toJavac(annotation)));
+ daggerAnnotation.annotation = annotation;
+ return daggerAnnotation;
+ }
+
+ abstract Equivalence.Wrapper<AnnotationMirror> annotationMirror();
+
+ public DaggerTypeElement annotationTypeElement() {
+ return DaggerTypeElement.from(annotation.getType().getTypeElement());
+ }
+
+ public ClassName className() {
+ return annotationTypeElement().className();
+ }
+
+ public XAnnotation xprocessing() {
+ return annotation;
+ }
+
+ public AnnotationMirror java() {
+ return toJavac(annotation);
+ }
+
+ // TODO(b/204390647): We'll need to update to auto-common to 1.2 before using AnnotationMirrors.
+ @SuppressWarnings("AnnotationMirrorToString")
+ @Override
+ public final String toString() {
+ return java().toString();
+ }
+}
diff --git a/java/dagger/spi/model/DaggerElement.java b/java/dagger/spi/model/DaggerElement.java
new file mode 100644
index 000000000..aa1b4a5eb
--- /dev/null
+++ b/java/dagger/spi/model/DaggerElement.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+
+import androidx.room.compiler.processing.XElement;
+import com.google.auto.value.AutoValue;
+import javax.lang.model.element.Element;
+
+/** Wrapper type for an element. */
+@AutoValue
+public abstract class DaggerElement {
+ public static DaggerElement from(XElement element) {
+ return new AutoValue_DaggerElement(element);
+ }
+
+ public abstract XElement xprocessing();
+
+ public Element java() {
+ return toJavac(xprocessing());
+ }
+
+ @Override
+ public final String toString() {
+ return xprocessing().toString();
+ }
+}
diff --git a/java/dagger/spi/model/DaggerExecutableElement.java b/java/dagger/spi/model/DaggerExecutableElement.java
new file mode 100644
index 000000000..e15ca375b
--- /dev/null
+++ b/java/dagger/spi/model/DaggerExecutableElement.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import androidx.room.compiler.processing.XExecutableElement;
+import com.google.auto.value.AutoValue;
+import javax.lang.model.element.ExecutableElement;
+
+/** Wrapper type for an executable element. */
+@AutoValue
+public abstract class DaggerExecutableElement {
+ public static DaggerExecutableElement from(XExecutableElement executableElement) {
+ return new AutoValue_DaggerExecutableElement(checkNotNull(executableElement));
+ }
+
+ public abstract XExecutableElement xprocessing();
+
+ public ExecutableElement java() {
+ return toJavac(xprocessing());
+ }
+
+ @Override
+ public final String toString() {
+ return xprocessing().toString();
+ }
+}
diff --git a/java/dagger/spi/model/DaggerType.java b/java/dagger/spi/model/DaggerType.java
new file mode 100644
index 000000000..34cc6dc8a
--- /dev/null
+++ b/java/dagger/spi/model/DaggerType.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+
+import androidx.room.compiler.processing.XType;
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Preconditions;
+import javax.lang.model.type.TypeMirror;
+
+/** Wrapper type for a type. */
+@AutoValue
+public abstract class DaggerType {
+ private XType type;
+
+ public static DaggerType from(XType type) {
+ Preconditions.checkNotNull(type);
+ DaggerType daggerType = new AutoValue_DaggerType(MoreTypes.equivalence().wrap(toJavac(type)));
+ daggerType.type = type;
+ return daggerType;
+ }
+
+ abstract Equivalence.Wrapper<TypeMirror> typeMirror();
+
+ public XType xprocessing() {
+ return type;
+ }
+
+ public TypeMirror java() {
+ return toJavac(type);
+ }
+
+ @Override
+ public final String toString() {
+ return type.toString();
+ }
+}
diff --git a/java/dagger/spi/model/DaggerTypeElement.java b/java/dagger/spi/model/DaggerTypeElement.java
new file mode 100644
index 000000000..aa4750794
--- /dev/null
+++ b/java/dagger/spi/model/DaggerTypeElement.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.auto.value.AutoValue;
+import com.squareup.javapoet.ClassName;
+import javax.lang.model.element.TypeElement;
+
+/** Wrapper type for a type element. */
+@AutoValue
+public abstract class DaggerTypeElement {
+ public static DaggerTypeElement from(XTypeElement typeElement) {
+ return new AutoValue_DaggerTypeElement(typeElement);
+ }
+
+ public abstract XTypeElement xprocessing();
+
+ public TypeElement java() {
+ return toJavac(xprocessing());
+ }
+
+ public ClassName className() {
+ return xprocessing().getClassName();
+ }
+
+ @Override
+ public final String toString() {
+ return xprocessing().toString();
+ }
+}
diff --git a/java/dagger/spi/model/DependencyRequest.java b/java/dagger/spi/model/DependencyRequest.java
new file mode 100644
index 000000000..64c0f2834
--- /dev/null
+++ b/java/dagger/spi/model/DependencyRequest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+import com.google.auto.value.AutoValue;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.Provides;
+import java.util.Optional;
+import javax.inject.Inject;
+
+/**
+ * Represents a request for a {@link Key} at an injection point. For example, parameters to {@link
+ * Inject} constructors, {@link Provides} methods, and component methods are all dependency
+ * requests.
+ *
+ * <p id="synthetic">A dependency request is considered to be <em>synthetic</em> if it does not have
+ * an {@link DaggerElement} in code that requests the key directly. For example, an {@link
+ * java.util.concurrent.Executor} is required for all {@code @Produces} methods to run
+ * asynchronously even though it is not directly specified as a parameter to the binding method.
+ */
+@AutoValue
+public abstract class DependencyRequest {
+ /** The kind of this request. */
+ public abstract RequestKind kind();
+
+ /** The key of this request. */
+ public abstract Key key();
+
+ /**
+ * The element that declares this dependency request. Absent for <a href="#synthetic">synthetic
+ * </a> requests.
+ */
+ public abstract Optional<DaggerElement> requestElement();
+
+ /**
+ * Returns {@code true} if this request allows null objects. A request is nullable if it is
+ * has an annotation with "Nullable" as its simple name.
+ */
+ public abstract boolean isNullable();
+
+ /** Returns a new builder of dependency requests. */
+ public static DependencyRequest.Builder builder() {
+ return new AutoValue_DependencyRequest.Builder().isNullable(false);
+ }
+
+ /** A builder of {@link DependencyRequest}s. */
+ @CanIgnoreReturnValue
+ @AutoValue.Builder
+ public abstract static class Builder {
+ public abstract Builder kind(RequestKind kind);
+
+ public abstract Builder key(Key key);
+
+ public abstract Builder requestElement(DaggerElement element);
+
+ public abstract Builder isNullable(boolean isNullable);
+
+ @CheckReturnValue
+ public abstract DependencyRequest build();
+ }
+}
diff --git a/java/dagger/spi/model/DiagnosticReporter.java b/java/dagger/spi/model/DiagnosticReporter.java
new file mode 100644
index 000000000..a3d222965
--- /dev/null
+++ b/java/dagger/spi/model/DiagnosticReporter.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+import com.google.errorprone.annotations.FormatMethod;
+import dagger.spi.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.spi.model.BindingGraph.ComponentNode;
+import dagger.spi.model.BindingGraph.DependencyEdge;
+import dagger.spi.model.BindingGraph.MaybeBinding;
+import javax.tools.Diagnostic;
+
+// TODO(bcorso): Move this into dagger/spi?
+/**
+ * An object that {@link BindingGraphPlugin}s can use to report diagnostics while visiting a {@link
+ * BindingGraph}.
+ *
+ * <p>Note: This API is still experimental and will change.
+ */
+public interface DiagnosticReporter {
+ /**
+ * Reports a diagnostic for a component. For non-root components, includes information about the
+ * path from the root component.
+ */
+ void reportComponent(Diagnostic.Kind diagnosticKind, ComponentNode componentNode, String message);
+
+ /**
+ * Reports a diagnostic for a component. For non-root components, includes information about the
+ * path from the root component.
+ */
+ @FormatMethod
+ void reportComponent(
+ Diagnostic.Kind diagnosticKind,
+ ComponentNode componentNode,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs);
+
+ /**
+ * Reports a diagnostic for a binding or missing binding. Includes information about how the
+ * binding is reachable from entry points.
+ */
+ void reportBinding(Diagnostic.Kind diagnosticKind, MaybeBinding binding, String message);
+
+ /**
+ * Reports a diagnostic for a binding or missing binding. Includes information about how the
+ * binding is reachable from entry points.
+ */
+ @FormatMethod
+ void reportBinding(
+ Diagnostic.Kind diagnosticKind,
+ MaybeBinding binding,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs);
+
+ /**
+ * Reports a diagnostic for a dependency. Includes information about how the dependency is
+ * reachable from entry points.
+ */
+ void reportDependency(
+ Diagnostic.Kind diagnosticKind, DependencyEdge dependencyEdge, String message);
+
+ /**
+ * Reports a diagnostic for a dependency. Includes information about how the dependency is
+ * reachable from entry points.
+ */
+ @FormatMethod
+ void reportDependency(
+ Diagnostic.Kind diagnosticKind,
+ DependencyEdge dependencyEdge,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs);
+
+ /** Reports a diagnostic for a subcomponent factory method. */
+ void reportSubcomponentFactoryMethod(
+ Diagnostic.Kind diagnosticKind,
+ ChildFactoryMethodEdge childFactoryMethodEdge,
+ String message);
+
+ /** Reports a diagnostic for a subcomponent factory method. */
+ @FormatMethod
+ void reportSubcomponentFactoryMethod(
+ Diagnostic.Kind diagnosticKind,
+ ChildFactoryMethodEdge childFactoryMethodEdge,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs);
+}
diff --git a/java/dagger/spi/model/Key.java b/java/dagger/spi/model/Key.java
new file mode 100644
index 000000000..ad9b6c7de
--- /dev/null
+++ b/java/dagger/spi/model/Key.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.base.Joiner;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import com.google.errorprone.annotations.CheckReturnValue;
+import java.util.Objects;
+import java.util.Optional;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * A {@linkplain DaggerType type} and an optional {@linkplain javax.inject.Qualifier qualifier} that
+ * is the lookup key for a binding.
+ */
+@AutoValue
+public abstract class Key {
+ /**
+ * A {@link javax.inject.Qualifier} annotation that provides a unique namespace prefix for the
+ * type of this key.
+ */
+ public abstract Optional<DaggerAnnotation> qualifier();
+
+ /** The type represented by this key. */
+ public abstract DaggerType type();
+
+ /**
+ * Distinguishes keys for multibinding contributions that share a {@link #type()} and {@link
+ * #qualifier()}.
+ *
+ * <p>Each multibound map and set has a synthetic multibinding that depends on the specific
+ * contributions to that map or set using keys that identify those multibinding contributions.
+ *
+ * <p>Absent except for multibinding contributions.
+ */
+ public abstract Optional<MultibindingContributionIdentifier> multibindingContributionIdentifier();
+
+ /** Returns a {@link Builder} that inherits the properties of this key. */
+ public abstract Builder toBuilder();
+
+ // The main hashCode/equality bottleneck is in MoreTypes.equivalence(). It's possible that we can
+ // avoid this by tuning that method. Perhaps we can also avoid the issue entirely by interning all
+ // Keys
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ @Override
+ public abstract boolean equals(Object o);
+
+ @Override
+ public final String toString() {
+ return Joiner.on(' ')
+ .skipNulls()
+ .join(
+ qualifier().map(MoreAnnotationMirrors::toStableString).orElse(null),
+ type(),
+ multibindingContributionIdentifier().orElse(null));
+ }
+
+ /** Returns a builder for {@link Key}s. */
+ public static Builder builder(DaggerType type) {
+ return new AutoValue_Key.Builder().type(type);
+ }
+
+ /** A builder for {@link Key}s. */
+ @CanIgnoreReturnValue
+ @AutoValue.Builder
+ public abstract static class Builder {
+ public abstract Builder type(DaggerType type);
+
+ public abstract Builder qualifier(Optional<DaggerAnnotation> qualifier);
+
+ public abstract Builder qualifier(DaggerAnnotation qualifier);
+
+ public abstract Builder multibindingContributionIdentifier(
+ Optional<MultibindingContributionIdentifier> identifier);
+
+ public abstract Builder multibindingContributionIdentifier(
+ MultibindingContributionIdentifier identifier);
+
+ @CheckReturnValue
+ public abstract Key build();
+ }
+
+ /**
+ * An object that identifies a multibinding contribution method and the module class that
+ * contributes it to the graph.
+ *
+ * @see #multibindingContributionIdentifier()
+ */
+ public static final class MultibindingContributionIdentifier {
+ private final String module;
+ private final String bindingElement;
+
+ /**
+ * @deprecated This is only meant to be called from code in {@code dagger.internal.codegen}.
+ * It is not part of a specified API and may change at any point.
+ */
+ @Deprecated
+ public MultibindingContributionIdentifier(
+ // TODO(ronshapiro): reverse the order of these parameters
+ ExecutableElement bindingMethod, TypeElement contributingModule) {
+ this(
+ bindingMethod.getSimpleName().toString(),
+ contributingModule.getQualifiedName().toString());
+ }
+
+ // TODO(ronshapiro,dpb): create KeyProxies so that these constructors don't need to be public.
+ @Deprecated
+ public MultibindingContributionIdentifier(String bindingElement, String module) {
+ this.module = module;
+ this.bindingElement = bindingElement;
+ }
+
+ /**
+ * @deprecated This is only meant to be called from code in {@code dagger.internal.codegen}.
+ * It is not part of a specified API and may change at any point.
+ */
+ @Deprecated
+ public String module() {
+ return module;
+ }
+
+ /**
+ * @deprecated This is only meant to be called from code in {@code dagger.internal.codegen}.
+ * It is not part of a specified API and may change at any point.
+ */
+ @Deprecated
+ public String bindingElement() {
+ return bindingElement;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The returned string is human-readable and distinguishes the keys in the same way as the
+ * whole object.
+ */
+ @Override
+ public String toString() {
+ return String.format("%s#%s", module, bindingElement);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof MultibindingContributionIdentifier) {
+ MultibindingContributionIdentifier other = (MultibindingContributionIdentifier) obj;
+ return module.equals(other.module) && bindingElement.equals(other.bindingElement);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(module, bindingElement);
+ }
+ }
+}
diff --git a/java/dagger/spi/model/MoreAnnotationMirrors.java b/java/dagger/spi/model/MoreAnnotationMirrors.java
new file mode 100644
index 000000000..44c0363c9
--- /dev/null
+++ b/java/dagger/spi/model/MoreAnnotationMirrors.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+import static com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults;
+import static java.util.stream.Collectors.joining;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import com.squareup.javapoet.CodeBlock;
+import java.util.List;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.util.SimpleAnnotationValueVisitor8;
+
+/** Utility class for qualifier transformations */
+final class MoreAnnotationMirrors {
+ /**
+ * Returns a String rendering of an {@link AnnotationMirror} that includes attributes in the order
+ * defined in the annotation type.
+ */
+ public static String toStableString(DaggerAnnotation qualifier) {
+ return stableAnnotationMirrorToString(qualifier.java());
+ }
+
+ /**
+ * Returns a String rendering of an {@link AnnotationMirror} that includes attributes in the order
+ * defined in the annotation type. This will produce the same output for {@linkplain
+ * com.google.auto.common.AnnotationMirrors#equivalence() equal} {@link AnnotationMirror}s even if
+ * default values are omitted or their attributes were written in different orders, e.g.
+ * {@code @A(b = "b", c = "c")} and {@code @A(c = "c", b = "b", attributeWithDefaultValue =
+ * "default value")}.
+ */
+ // TODO(ronshapiro): move this to auto-common
+ private static String stableAnnotationMirrorToString(AnnotationMirror qualifier) {
+ StringBuilder builder = new StringBuilder("@").append(qualifier.getAnnotationType());
+ ImmutableMap<ExecutableElement, AnnotationValue> elementValues =
+ getAnnotationValuesWithDefaults(qualifier);
+ if (!elementValues.isEmpty()) {
+ ImmutableMap.Builder<String, String> namedValuesBuilder = ImmutableMap.builder();
+ elementValues.forEach(
+ (key, value) ->
+ namedValuesBuilder.put(
+ key.getSimpleName().toString(), stableAnnotationValueToString(value)));
+ ImmutableMap<String, String> namedValues = namedValuesBuilder.build();
+ builder.append('(');
+ if (namedValues.size() == 1 && namedValues.containsKey("value")) {
+ // Omit "value ="
+ builder.append(namedValues.get("value"));
+ } else {
+ builder.append(Joiner.on(", ").withKeyValueSeparator("=").join(namedValues));
+ }
+ builder.append(')');
+ }
+ return builder.toString();
+ }
+
+ private static String stableAnnotationValueToString(AnnotationValue annotationValue) {
+ return annotationValue.accept(
+ new SimpleAnnotationValueVisitor8<String, Void>() {
+ @Override
+ protected String defaultAction(Object value, Void ignore) {
+ return value.toString();
+ }
+
+ @Override
+ public String visitString(String value, Void ignore) {
+ return CodeBlock.of("$S", value).toString();
+ }
+
+ @Override
+ public String visitAnnotation(AnnotationMirror value, Void ignore) {
+ return stableAnnotationMirrorToString(value);
+ }
+
+ @Override
+ public String visitArray(List<? extends AnnotationValue> value, Void ignore) {
+ return value.stream()
+ .map(MoreAnnotationMirrors::stableAnnotationValueToString)
+ .collect(joining(", ", "{", "}"));
+ }
+ },
+ null);
+ }
+
+ private MoreAnnotationMirrors() {}
+}
diff --git a/java/dagger/spi/model/RequestKind.java b/java/dagger/spi/model/RequestKind.java
new file mode 100644
index 000000000..62f46cd65
--- /dev/null
+++ b/java/dagger/spi/model/RequestKind.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
+
+import dagger.Lazy;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import javax.inject.Provider;
+
+/**
+ * Represents the different kinds of {@link javax.lang.model.type.TypeMirror types} that may be
+ * requested as dependencies for the same key. For example, {@code String}, {@code
+ * Provider<String>}, and {@code Lazy<String>} can all be requested if a key exists for {@code
+ * String}; they have the {@link #INSTANCE}, {@link #PROVIDER}, and {@link #LAZY} request kinds,
+ * respectively.
+ */
+public enum RequestKind {
+ /** A default request for an instance. E.g.: {@code FooType} */
+ INSTANCE,
+
+ /** A request for a {@link Provider}. E.g.: {@code Provider<FooType>} */
+ PROVIDER,
+
+ /** A request for a {@link Lazy}. E.g.: {@code Lazy<FooType>} */
+ LAZY,
+
+ /** A request for a {@link Provider} of a {@link Lazy}. E.g.: {@code Provider<Lazy<FooType>>} */
+ PROVIDER_OF_LAZY,
+
+ /**
+ * A request for a members injection. E.g. {@code void injectMembers(FooType);}. Can only be
+ * requested by component interfaces.
+ */
+ MEMBERS_INJECTION,
+
+ /** A request for a {@link Producer}. E.g.: {@code Producer<FooType>} */
+ PRODUCER,
+
+ /** A request for a {@link Produced}. E.g.: {@code Produced<FooType>} */
+ PRODUCED,
+
+ /**
+ * A request for a {@link com.google.common.util.concurrent.ListenableFuture}. E.g.: {@code
+ * ListenableFuture<FooType>}. These can only be requested by component interfaces.
+ */
+ FUTURE,
+ ;
+
+ /** Returns a string that represents requests of this kind for a key. */
+ public String format(Key key) {
+ switch (this) {
+ case INSTANCE:
+ return key.toString();
+
+ case PROVIDER_OF_LAZY:
+ return String.format("Provider<Lazy<%s>>", key);
+
+ case MEMBERS_INJECTION:
+ return String.format("injectMembers(%s)", key);
+
+ case FUTURE:
+ return String.format("ListenableFuture<%s>", key);
+
+ default:
+ return String.format("%s<%s>", UPPER_UNDERSCORE.to(UPPER_CAMEL, name()), key);
+ }
+ }
+}
diff --git a/java/dagger/spi/model/Scope.java b/java/dagger/spi/model/Scope.java
new file mode 100644
index 000000000..c3a980365
--- /dev/null
+++ b/java/dagger/spi/model/Scope.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.auto.value.AutoValue;
+import com.squareup.javapoet.ClassName;
+
+/** A representation of a {@link javax.inject.Scope}. */
+@AutoValue
+public abstract class Scope {
+ /**
+ * Creates a {@link Scope} object from the {@link javax.inject.Scope}-annotated annotation type.
+ */
+ public static Scope scope(DaggerAnnotation scopeAnnotation) {
+ checkArgument(isScope(scopeAnnotation));
+ return new AutoValue_Scope(scopeAnnotation);
+ }
+
+ /**
+ * Returns {@code true} if {@link #scopeAnnotation()} is a {@link javax.inject.Scope} annotation.
+ */
+ public static boolean isScope(DaggerAnnotation scopeAnnotation) {
+ return isScope(scopeAnnotation.annotationTypeElement());
+ }
+
+ /**
+ * Returns {@code true} if {@code scopeAnnotationType} is a {@link javax.inject.Scope} annotation.
+ */
+ public static boolean isScope(DaggerTypeElement scopeAnnotationType) {
+ return isAnnotationPresent(scopeAnnotationType.java(), SCOPE.canonicalName())
+ || isAnnotationPresent(scopeAnnotationType.java(), SCOPE_JAVAX.canonicalName());
+ }
+
+ private static final ClassName PRODUCTION_SCOPE =
+ ClassName.get("dagger.producers", "ProductionScope");
+ private static final ClassName SINGLETON = ClassName.get("jakarta.inject", "Singleton");
+ private static final ClassName SINGLETON_JAVAX = ClassName.get("javax.inject", "Singleton");
+ private static final ClassName REUSABLE = ClassName.get("dagger", "Reusable");
+ private static final ClassName SCOPE = ClassName.get("jakarta.inject", "Scope");
+ private static final ClassName SCOPE_JAVAX = ClassName.get("javax.inject", "Scope");
+
+
+ /** The {@link DaggerAnnotation} that represents the scope annotation. */
+ public abstract DaggerAnnotation scopeAnnotation();
+
+ public final ClassName className() {
+ return scopeAnnotation().className();
+ }
+
+ /** Returns {@code true} if this scope is the {@link javax.inject.Singleton @Singleton} scope. */
+ public final boolean isSingleton() {
+ return isScope(SINGLETON) || isScope(SINGLETON_JAVAX);
+ }
+
+ /** Returns {@code true} if this scope is the {@link dagger.Reusable @Reusable} scope. */
+ public final boolean isReusable() {
+ return isScope(REUSABLE);
+ }
+
+ /**
+ * Returns {@code true} if this scope is the {@link
+ * dagger.producers.ProductionScope @ProductionScope} scope.
+ */
+ public final boolean isProductionScope() {
+ return isScope(PRODUCTION_SCOPE);
+ }
+
+ private boolean isScope(ClassName annotation) {
+ return scopeAnnotation().className().equals(annotation);
+ }
+
+ /** Returns a debug representation of the scope. */
+ @Override
+ public final String toString() {
+ return scopeAnnotation().toString();
+ }
+}
diff --git a/java/dagger/spi/model/package-info.java b/java/dagger/spi/model/package-info.java
new file mode 100644
index 000000000..133a54219
--- /dev/null
+++ b/java/dagger/spi/model/package-info.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This package contains the APIs that are core to Dagger's internal model of bindings and the
+ * binding graph. The types are shared with the Dagger processor and are exposed to clients of the
+ * Dagger SPI.
+ *
+ * <p>Unless otherwise specified, the types/interfaces are only intended to be implemented in this
+ * package (i.e. via {@code @AutoValue}) or by Dagger's processor. This applies to test code as
+ * well, so if you need a fake, please file a feature request instead of implementing it yourself.
+ */
+@CheckReturnValue
+@Beta
+package dagger.spi.model;
+
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.Beta;
diff --git a/java/dagger/spi/model/testing/BUILD b/java/dagger/spi/model/testing/BUILD
new file mode 100644
index 000000000..939e41171
--- /dev/null
+++ b/java/dagger/spi/model/testing/BUILD
@@ -0,0 +1,39 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Description:
+# Test utilities for the Dagger model
+
+load("@rules_java//java:defs.bzl", "java_library")
+load(
+ "//:build_defs.bzl",
+ "DOCLINT_HTML_AND_SYNTAX",
+ "DOCLINT_REFERENCES",
+)
+
+package(default_visibility = ["//:src"])
+
+java_library(
+ name = "testing",
+ testonly = 1,
+ srcs = glob(["*.java"]),
+ javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+ deps = [
+ "//java/dagger/internal/codegen/extension",
+ "//java/dagger/spi",
+ "//third_party/java/checker_framework_annotations",
+ "//third_party/java/guava/collect",
+ "//third_party/java/truth",
+ ],
+)
diff --git a/java/dagger/spi/model/testing/BindingGraphSubject.java b/java/dagger/spi/model/testing/BindingGraphSubject.java
new file mode 100644
index 000000000..32bf15237
--- /dev/null
+++ b/java/dagger/spi/model/testing/BindingGraphSubject.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model.testing;
+
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.google.common.truth.Truth.assertAbout;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.Subject;
+import dagger.spi.model.Binding;
+import dagger.spi.model.BindingGraph;
+import javax.lang.model.type.TypeMirror;
+import org.checkerframework.checker.nullness.compatqual.NullableDecl;
+
+/** A Truth subject for making assertions on a {@link BindingGraph}. */
+public final class BindingGraphSubject extends Subject {
+
+ /** Starts a fluent assertion about a {@link BindingGraph}. */
+ public static BindingGraphSubject assertThat(BindingGraph bindingGraph) {
+ return assertAbout(BindingGraphSubject::new).that(bindingGraph);
+ }
+
+ private final BindingGraph actual;
+
+ private BindingGraphSubject(FailureMetadata metadata, @NullableDecl BindingGraph actual) {
+ super(metadata, actual);
+ this.actual = actual;
+ }
+
+ /**
+ * Asserts that the graph has at least one binding with an unqualified key.
+ *
+ * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()}
+ */
+ public void hasBindingWithKey(String type) {
+ bindingWithKey(type);
+ }
+
+ /**
+ * Asserts that the graph has at least one binding with a qualified key.
+ *
+ * @param qualifier the canonical string form of the qualifier, as returned by {@link
+ * javax.lang.model.element.AnnotationMirror AnnotationMirror.toString()}
+ * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()}
+ */
+ public void hasBindingWithKey(String qualifier, String type) {
+ bindingWithKey(qualifier, type);
+ }
+
+ /**
+ * Returns a subject for testing the binding for an unqualified key.
+ *
+ * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()}
+ */
+ public BindingSubject bindingWithKey(String type) {
+ return bindingWithKeyString(keyString(type));
+ }
+
+ /**
+ * Returns a subject for testing the binding for a qualified key.
+ *
+ * @param qualifier the canonical string form of the qualifier, as returned by {@link
+ * javax.lang.model.element.AnnotationMirror AnnotationMirror.toString()}
+ * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()}
+ */
+ public BindingSubject bindingWithKey(String qualifier, String type) {
+ return bindingWithKeyString(keyString(qualifier, type));
+ }
+
+ private BindingSubject bindingWithKeyString(String keyString) {
+ ImmutableSet<Binding> bindings = getBindingNodes(keyString);
+ // TODO(dpb): Handle multiple bindings for the same key.
+ check("bindingsWithKey(%s)", keyString).that(bindings).hasSize(1);
+ return check("bindingWithKey(%s)", keyString)
+ .about(BindingSubject::new)
+ .that(getOnlyElement(bindings));
+ }
+
+ private ImmutableSet<Binding> getBindingNodes(String keyString) {
+ return actual.bindings().stream()
+ .filter(binding -> binding.key().toString().equals(keyString))
+ .collect(toImmutableSet());
+ }
+
+ private static String keyString(String type) {
+ return type;
+ }
+
+ private static String keyString(String qualifier, String type) {
+ return String.format("%s %s", qualifier, type);
+ }
+
+ /** A Truth subject for a {@link Binding}. */
+ public final class BindingSubject extends Subject {
+
+ private final Binding actual;
+
+ BindingSubject(FailureMetadata metadata, @NullableDecl Binding actual) {
+ super(metadata, actual);
+ this.actual = actual;
+ }
+
+ /**
+ * Asserts that the binding depends on a binding with an unqualified key.
+ *
+ * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()}
+ */
+ public void dependsOnBindingWithKey(String type) {
+ dependsOnBindingWithKeyString(keyString(type));
+ }
+
+ /**
+ * Asserts that the binding depends on a binding with a qualified key.
+ *
+ * @param qualifier the canonical string form of the qualifier, as returned by {@link
+ * javax.lang.model.element.AnnotationMirror AnnotationMirror.toString()}
+ * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()}
+ */
+ public void dependsOnBindingWithKey(String qualifier, String type) {
+ dependsOnBindingWithKeyString(keyString(qualifier, type));
+ }
+
+ private void dependsOnBindingWithKeyString(String keyString) {
+ if (actualBindingGraph().requestedBindings(actual).stream()
+ .noneMatch(binding -> binding.key().toString().equals(keyString))) {
+ failWithActual("expected to depend on binding with key", keyString);
+ }
+ }
+
+ private BindingGraph actualBindingGraph() {
+ return BindingGraphSubject.this.actual;
+ }
+ }
+}
diff --git a/java/dagger/testing/compile/BUILD b/java/dagger/testing/compile/BUILD
index 20e6a3d20..dbad09f02 100644
--- a/java/dagger/testing/compile/BUILD
+++ b/java/dagger/testing/compile/BUILD
@@ -24,9 +24,11 @@ java_library(
testonly = 1,
srcs = ["CompilerTests.java"],
deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:io",
- "@google_bazel_common//third_party/java/compile_testing",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/io",
+ "//third_party/java/compile_testing",
+ "//java/dagger/internal/codegen:processor",
+ "@maven//:com_github_tschuchortdev_kotlin_compile_testing",
],
)
diff --git a/java/dagger/testing/compile/CompilerTests.java b/java/dagger/testing/compile/CompilerTests.java
index 6750d0c65..a7fbef71b 100644
--- a/java/dagger/testing/compile/CompilerTests.java
+++ b/java/dagger/testing/compile/CompilerTests.java
@@ -29,10 +29,10 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.NoSuchElementException;
+import com.tschuchort.compiletesting.KotlinCompilation;
+import dagger.internal.codegen.ComponentProcessor;
-/**
- * A helper class for working with java compiler tests.
- */
+/** A helper class for working with java compiler tests. */
public final class CompilerTests {
private CompilerTests() {}
@@ -53,6 +53,18 @@ public final class CompilerTests {
return javac().withClasspath(ImmutableList.of(compilerDepsJar()));
}
+ public static KotlinCompilation kotlinCompiler() {
+ KotlinCompilation compilation = new KotlinCompilation();
+ compilation.setAnnotationProcessors(ImmutableList.of(new ComponentProcessor()));
+ compilation.setClasspaths(
+ ImmutableList.<java.io.File>builder()
+ .addAll(compilation.getClasspaths())
+ .add(compilerDepsJar())
+ .build()
+ );
+ return compilation;
+ }
+
private static File getRunfilesDir() {
return getRunfilesPath().toFile();
}
diff --git a/javatests/artifacts/dagger-android/simple/build.gradle b/javatests/artifacts/dagger-android/simple/build.gradle
index d29aa0c7a..3fedf3b5a 100644
--- a/javatests/artifacts/dagger-android/simple/build.gradle
+++ b/javatests/artifacts/dagger-android/simple/build.gradle
@@ -16,11 +16,11 @@
buildscript {
ext {
- agp_version = System.getenv('AGP_VERSION') ?: "4.2.0-beta04"
+ agp_version = System.getenv('AGP_VERSION') ?: "4.2.0"
}
repositories {
google()
- jcenter()
+ mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:$agp_version"
@@ -30,7 +30,6 @@ buildscript {
allprojects {
repositories {
google()
- jcenter()
mavenCentral()
mavenLocal()
}
diff --git a/javatests/artifacts/dagger-android/simple/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/dagger-android/simple/gradle/wrapper/gradle-wrapper.properties
index 4d9ca1649..0f80bbf51 100644
--- a/javatests/artifacts/dagger-android/simple/gradle/wrapper/gradle-wrapper.properties
+++ b/javatests/artifacts/dagger-android/simple/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/java/dagger/example/gradle/simple/build.gradle b/javatests/artifacts/dagger/build-tests/build.gradle
index c9e59ef23..407c7ef0f 100644
--- a/java/dagger/example/gradle/simple/build.gradle
+++ b/javatests/artifacts/dagger/build-tests/build.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Dagger Authors.
+ * Copyright (C) 2021 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,22 +19,13 @@ plugins {
id 'application'
}
-repositories {
- mavenCentral()
- mavenLocal()
-}
-
-sourceSets {
- main {
- java {
- srcDir '.'
- }
- }
+// Set the versions in a system property so that tests can access it.
+test {
+ systemProperty 'dagger_version', "$dagger_version"
}
dependencies {
- implementation 'com.google.dagger:dagger:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:dagger-compiler:LOCAL-SNAPSHOT'
-}
-
-mainClassName = 'dagger.example.gradle.simple.SimpleApplication' \ No newline at end of file
+ testImplementation "com.google.truth:truth:$truth_version"
+ testImplementation "junit:junit:$junit_version"
+ testImplementation gradleTestKit()
+} \ No newline at end of file
diff --git a/javatests/artifacts/dagger/build-tests/src/main/java/buildtests/GradleFile.java b/javatests/artifacts/dagger/build-tests/src/main/java/buildtests/GradleFile.java
new file mode 100644
index 000000000..6cd279c91
--- /dev/null
+++ b/javatests/artifacts/dagger/build-tests/src/main/java/buildtests/GradleFile.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package buildtests;
+
+/** Stores the name and content of a file. */
+public final class GradleFile {
+ /** Creates a {@link GradleFile} with the given name and content */
+ public static GradleFile create(String fileName, String... fileContent) {
+ return new GradleFile(fileName, fileContent);
+ }
+
+ private final String fileName;
+ private final String[] fileContent;
+
+ GradleFile(String fileName, String... fileContent) {
+ this.fileName = fileName;
+ this.fileContent = fileContent;
+ }
+
+ String fileName() {
+ return fileName;
+ }
+
+ String[] fileContent() {
+ return fileContent;
+ }
+}
diff --git a/javatests/artifacts/dagger/build-tests/src/main/java/buildtests/GradleModule.java b/javatests/artifacts/dagger/build-tests/src/main/java/buildtests/GradleModule.java
new file mode 100644
index 000000000..d02dd91ea
--- /dev/null
+++ b/javatests/artifacts/dagger/build-tests/src/main/java/buildtests/GradleModule.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package buildtests;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+/** Used to create files for a Gradle module in a particular directory. */
+public final class GradleModule {
+ public static GradleModule create(File moduleDir) {
+ return new GradleModule(moduleDir);
+ }
+
+ public static GradleModule create(File projectDir, String moduleName) {
+ return new GradleModule(new File(projectDir, moduleName));
+ }
+
+ private final File moduleDir;
+ private final File moduleSrcDir;
+
+ private GradleModule(File moduleDir) {
+ this.moduleDir = moduleDir;
+ this.moduleSrcDir = new File(moduleDir, "src/main/java/");
+ }
+
+ public GradleModule addBuildFile(String... content) throws IOException {
+ writeFile(createFile(moduleDir, "build.gradle"), content);
+ return this;
+ }
+
+ public GradleModule addSettingsFile(String... content) throws IOException {
+ writeFile(createFile(moduleDir, "settings.gradle"), content);
+ return this;
+ }
+
+ public GradleModule addFile(GradleFile gradleFile) throws IOException {
+ return addFile(gradleFile.fileName(), gradleFile.fileContent());
+ }
+
+ public GradleModule addFile(String fileName, String... content) throws IOException {
+ writeFile(createFile(moduleDir, fileName), content);
+ return this;
+ }
+
+ public GradleModule addSrcFiles(GradleFile... gradleFiles) throws IOException {
+ for (GradleFile gradleFile : gradleFiles) {
+ addSrcFile(gradleFile.fileName(), gradleFile.fileContent());
+ }
+ return this;
+ }
+
+ public GradleModule addSrcFile(GradleFile gradleFile) throws IOException {
+ return addSrcFile(gradleFile.fileName(), gradleFile.fileContent());
+ }
+
+ public GradleModule addSrcFile(String fileName, String... content) throws IOException {
+ writeFile(createFile(moduleSrcDir, fileName), content);
+ return this;
+ }
+
+ private static File createFile(File dir, String fileName) {
+ File file = new File(dir, fileName);
+ file.getParentFile().mkdirs();
+ return file;
+ }
+
+ private static void writeFile(File destination, String... content) throws IOException {
+ BufferedWriter output = null;
+ try {
+ output = new BufferedWriter(new FileWriter(destination));
+ for (String line : content) {
+ output.write(line + "\n");
+ }
+ } finally {
+ if (output != null) {
+ output.close();
+ }
+ }
+ }
+}
diff --git a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveBindsQualifierTest.java b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveBindsQualifierTest.java
new file mode 100644
index 000000000..6be8e3d3a
--- /dev/null
+++ b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveBindsQualifierTest.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package buildtests;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.GradleRunner;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+// This is a regression test for https://github.com/google/dagger/issues/3136
+@RunWith(Parameterized.class)
+public class TransitiveBindsQualifierTest {
+ @Parameters(name = "{0}")
+ public static Collection<Object[]> parameters() {
+ return Arrays.asList(new Object[][] {{ "implementation" }, { "api" }});
+ }
+
+ @Rule public TemporaryFolder folder = new TemporaryFolder();
+
+ private final String transitiveDependencyType;
+
+ public TransitiveBindsQualifierTest(String transitiveDependencyType) {
+ this.transitiveDependencyType = transitiveDependencyType;
+ }
+
+ @Test
+ public void testQualifierOnBindsMethod() throws IOException {
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ result = setupRunner().buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ assertThat(result.getOutput())
+ .contains(
+ "ComponentProcessingStep was unable to process 'app.MyComponent' because "
+ + "'library2.MyQualifier' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (INTERFACE): library1.MyModule"
+ + "\n => element (METHOD): bindObject(java.lang.Number)"
+ + "\n => element (PARAMETER): arg0"
+ + "\n => annotation: @library2.MyQualifier");
+ break;
+ case "api":
+ result = setupRunner().build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput())
+ .contains("BINDINGS: ["
+ + "@library2.MyQualifier java.lang.Object, "
+ + "@library2.MyQualifier java.lang.Number, "
+ + "java.lang.Integer"
+ + "]");
+ break;
+ }
+ }
+
+ private GradleRunner setupRunner() throws IOException {
+ File projectDir = folder.getRoot();
+ GradleModule.create(projectDir)
+ .addSettingsFile(
+ "include 'app'",
+ "include 'library1'",
+ "include 'library2'",
+ "include 'spi-plugin'")
+ .addBuildFile(
+ "buildscript {",
+ " ext {",
+ String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")),
+ " }",
+ "}",
+ "",
+ "allprojects {",
+ " repositories {",
+ " mavenCentral()",
+ " mavenLocal()",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "app")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'application'",
+ "}",
+ "compileJava {",
+ " options.compilerArgs << '-Adagger.pluginsVisitFullBindingGraphs=ENABLED'",
+ "}",
+ "dependencies {",
+ " implementation project(':library1')",
+ " annotationProcessor project(':spi-plugin')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyComponent.java",
+ "package app;",
+ "",
+ "import dagger.BindsInstance;",
+ "import dagger.Component;",
+ "import library1.MyModule;",
+ "",
+ "@Component(modules = MyModule.class)",
+ "public interface MyComponent {",
+ " @Component.Factory",
+ " interface Factory {",
+ " MyComponent create(@BindsInstance int i);",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "library1")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ transitiveDependencyType + " project(':library2')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyModule.java",
+ "package library1;",
+ "",
+ "import dagger.Binds;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import library2.MyQualifier;",
+ "",
+ "@Module",
+ "public interface MyModule {",
+ " @Binds",
+ " @MyQualifier",
+ " Object bindObject(@MyQualifier Number number);",
+ "",
+ " @Binds",
+ " @MyQualifier",
+ " Number bindNumber(int i);",
+ "}");
+
+ GradleModule.create(projectDir, "library2")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ " implementation 'javax.inject:javax.inject:1'",
+ "}")
+ .addSrcFile(
+ "MyQualifier.java",
+ "package library2;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "public @interface MyQualifier {}");
+
+ // This plugin is used to print output about bindings that we can assert on in tests.
+ GradleModule.create(projectDir, "spi-plugin")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ "}",
+ "dependencies {",
+ " implementation \"com.google.dagger:dagger-spi:$dagger_version\"",
+ " implementation 'com.google.auto.service:auto-service-annotations:1.0.1'",
+ " annotationProcessor 'com.google.auto.service:auto-service:1.0.1'",
+ "}")
+ .addSrcFile(
+ "TestBindingGraphPlugin.java",
+ "package spiplugin;",
+ "",
+ "import com.google.auto.service.AutoService;",
+ "import dagger.model.Binding;",
+ "import dagger.model.BindingGraph;",
+ "import dagger.model.BindingGraph.DependencyEdge;",
+ "import dagger.model.DependencyRequest;",
+ "import dagger.spi.BindingGraphPlugin;",
+ "import dagger.spi.DiagnosticReporter;",
+ "import java.util.stream.Collectors;",
+ "",
+ "@AutoService(BindingGraphPlugin.class)",
+ "public class TestBindingGraphPlugin implements BindingGraphPlugin {",
+ " @Override",
+ " public void visitGraph(",
+ " BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {",
+ " if (!bindingGraph.isFullBindingGraph() || bindingGraph.isModuleBindingGraph()) {",
+ " return;",
+ " }",
+ " System.out.print(",
+ " \"BINDINGS: \"",
+ " + bindingGraph.bindings().stream()",
+ " .map(Binding::key)",
+ " .collect(Collectors.toList()));",
+ " }",
+ "}");
+
+ return GradleRunner.create()
+ .withArguments("--stacktrace", "build")
+ .withProjectDir(projectDir);
+ }
+}
diff --git a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveBindsScopeTest.java b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveBindsScopeTest.java
new file mode 100644
index 000000000..34716fef3
--- /dev/null
+++ b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveBindsScopeTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package buildtests;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.GradleRunner;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+// This is a regression test for https://github.com/google/dagger/issues/3136
+@RunWith(Parameterized.class)
+public class TransitiveBindsScopeTest {
+ @Parameters(name = "{0}")
+ public static Collection<Object[]> parameters() {
+ return Arrays.asList(new Object[][] {{ "implementation" }, { "api" }});
+ }
+
+ @Rule public TemporaryFolder folder = new TemporaryFolder();
+
+ private final String transitiveDependencyType;
+
+ public TransitiveBindsScopeTest(String transitiveDependencyType) {
+ this.transitiveDependencyType = transitiveDependencyType;
+ }
+
+ @Test
+ public void testScopeOnBindsMethod() throws IOException {
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ result = setupRunner().buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ assertThat(result.getOutput())
+ .contains(
+ "ComponentProcessingStep was unable to process 'app.MyComponent' because "
+ + "'library2.MyScope' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (INTERFACE): library1.MyModule"
+ + "\n => element (METHOD): bindObject(java.lang.String)"
+ + "\n => annotation: @library2.MyScope");
+ break;
+ case "api":
+ result = setupRunner().build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput())
+ .contains(
+ "@Binds @library2.MyScope Object library1.MyModule.bindObject(String): SCOPED");
+ break;
+ }
+ }
+
+ private GradleRunner setupRunner() throws IOException {
+ File projectDir = folder.getRoot();
+ GradleModule.create(projectDir)
+ .addSettingsFile(
+ "include 'app'",
+ "include 'library1'",
+ "include 'library2'",
+ "include 'spi-plugin'")
+ .addBuildFile(
+ "buildscript {",
+ " ext {",
+ String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")),
+ " }",
+ "}",
+ "",
+ "allprojects {",
+ " repositories {",
+ " mavenCentral()",
+ " mavenLocal()",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "app")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'application'",
+ "}",
+ "tasks.withType(JavaCompile) {",
+ " options.compilerArgs += '-Adagger.experimentalDaggerErrorMessages=ENABLED'",
+ "}",
+ "dependencies {",
+ " implementation project(':library1')",
+ " annotationProcessor project(':spi-plugin')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyComponent.java",
+ "package app;",
+ "",
+ "import dagger.Component;",
+ "import library1.MySubcomponent;",
+ "",
+ "@Component",
+ "public interface MyComponent {",
+ " MySubcomponent subcomponent();",
+ "}");
+
+ GradleModule.create(projectDir, "library1")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ transitiveDependencyType + " project(':library2')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ // Note: In order to repro the issue we place MyScope on a subcomponent so that it can be a
+ // transitive dependency of the component. If MyScope was placed on directly on the
+ // component, it would need to be a direct dependency of the component.
+ .addSrcFile(
+ "MySubcomponent.java",
+ "package library1;",
+ "",
+ "import dagger.Subcomponent;",
+ "import library2.MyScope;",
+ "",
+ "@MyScope",
+ "@Subcomponent(modules = MyModule.class)",
+ "public interface MySubcomponent {",
+ " Object object();",
+ "}")
+ .addSrcFile(
+ "MyModule.java",
+ "package library1;",
+ "",
+ "import dagger.Binds;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import library2.MyScope;",
+ "",
+ "@Module",
+ "public interface MyModule {",
+ " @MyScope",
+ " @Binds",
+ " Object bindObject(String string);",
+ "",
+ " @Provides",
+ " static String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "library2")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ " implementation 'javax.inject:javax.inject:1'",
+ "}")
+ .addSrcFile(
+ "MyScope.java",
+ "package library2;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope",
+ "public @interface MyScope {}");
+
+ // This plugin is used to print output about bindings that we can assert on in tests.
+ GradleModule.create(projectDir, "spi-plugin")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ "}",
+ "dependencies {",
+ " implementation \"com.google.dagger:dagger-spi:$dagger_version\"",
+ " implementation 'com.google.auto.service:auto-service-annotations:1.0.1'",
+ " annotationProcessor 'com.google.auto.service:auto-service:1.0.1'",
+ "}")
+ .addSrcFile(
+ "TestBindingGraphPlugin.java",
+ "package spiplugin;",
+ "",
+ "import com.google.auto.service.AutoService;",
+ "import dagger.model.BindingGraph;",
+ "import dagger.model.BindingGraph.DependencyEdge;",
+ "import dagger.model.DependencyRequest;",
+ "import dagger.spi.BindingGraphPlugin;",
+ "import dagger.spi.DiagnosticReporter;",
+ "",
+ "@AutoService(BindingGraphPlugin.class)",
+ "public class TestBindingGraphPlugin implements BindingGraphPlugin {",
+ " @Override",
+ " public void visitGraph(",
+ " BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {",
+ " bindingGraph.bindings().stream()",
+ " .filter(binding -> binding.scope().isPresent())",
+ " .forEach(binding -> System.out.println(binding + \": SCOPED\"));",
+ " bindingGraph.bindings().stream()",
+ " .filter(binding -> !binding.scope().isPresent())",
+ " .forEach(binding -> System.out.println(binding + \": UNSCOPED\"));",
+ " }",
+ "}");
+
+ return GradleRunner.create()
+ .withArguments("--stacktrace", "build")
+ .withProjectDir(projectDir);
+ }
+}
diff --git a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveComponentDependenciesTest.java b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveComponentDependenciesTest.java
new file mode 100644
index 000000000..9a1adcf1e
--- /dev/null
+++ b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveComponentDependenciesTest.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package buildtests;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.GradleRunner;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+// This is a regression test for https://github.com/google/dagger/issues/3136
+@RunWith(Parameterized.class)
+public class TransitiveComponentDependenciesTest {
+ @Parameters(name = "{0}")
+ public static Collection<Object[]> parameters() {
+ return Arrays.asList(new Object[][] {{"implementation"}, {"api"}});
+ }
+
+ @Rule public TemporaryFolder folder = new TemporaryFolder();
+
+ private final String transitiveDependencyType;
+
+ public TransitiveComponentDependenciesTest(String transitiveDependencyType) {
+ this.transitiveDependencyType = transitiveDependencyType;
+ }
+
+ @Test
+ public void testsComponentDependencies() throws IOException {
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ result = setupRunner().buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ String expectedErrorMsg =
+ "error: ComponentProcessingStep was unable to process 'app.ComponentC' because"
+ + " 'libraryA.ComponentA' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (CLASS): libraryB.ComponentB"
+ + "\n => annotation:"
+ + " @dagger.Component(dependencies = libraryA.ComponentA.class)"
+ + "\n => annotation method: java.lang.Class<?>[] dependencies()"
+ + "\n => annotation value (ARRAY):"
+ + " value 'libraryA.ComponentA.class' with expected type java.lang.Class<?>[]"
+ + "\n => annotation value (TYPE):"
+ + " value 'libraryA.ComponentA' with expected type java.lang.Class<?>"
+ + "\n => type (ERROR annotation value type): libraryA.ComponentA";
+ assertThat(result.getOutput()).contains(expectedErrorMsg);
+ break;
+ case "api":
+ result = setupRunner().build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ break;
+ }
+ }
+
+ private GradleRunner setupRunner() throws IOException {
+ File projectDir = folder.getRoot();
+ GradleModule.create(projectDir)
+ .addSettingsFile("include 'app'", "include 'libraryB'", "include 'libraryA'")
+ .addBuildFile(
+ "buildscript {",
+ " ext {",
+ String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")),
+ " }",
+ "}",
+ "",
+ "allprojects {",
+ " repositories {",
+ " mavenCentral()",
+ " mavenLocal()",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "app")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'application'",
+ "}",
+ "tasks.withType(JavaCompile) {",
+ " options.compilerArgs += '-Adagger.experimentalDaggerErrorMessages=ENABLED'",
+ "}",
+ "dependencies {",
+ " implementation project(':libraryB')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "ComponentC.java",
+ "package app;",
+ "",
+ "import dagger.Component;",
+ "import libraryB.ComponentB;",
+ "",
+ "@Component(dependencies = ComponentB.class)",
+ "public interface ComponentC {",
+ " public abstract C getC();",
+ "}")
+ .addSrcFile(
+ "C.java",
+ "package app;",
+ "",
+ "import javax.inject.Inject;",
+ "import libraryB.B;",
+ "",
+ "public class C {",
+ " @Inject C(B b) {}",
+ "}");
+
+ GradleModule.create(projectDir, "libraryB")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ transitiveDependencyType + " project(':libraryA')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "ComponentB.java",
+ "package libraryB;",
+ "",
+ "import dagger.Component;",
+ "import libraryA.ComponentA;",
+ "",
+ "@Component(dependencies = ComponentA.class)",
+ "public abstract class ComponentB {",
+ " public abstract B getB();",
+ "}")
+ .addSrcFile(
+ "B.java",
+ "package libraryB;",
+ "",
+ "import javax.inject.Inject;",
+ "import libraryA.A;",
+ "",
+ "public class B {",
+ " @Inject B(A a) {}",
+ "}");
+
+ GradleModule.create(projectDir, "libraryA")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "ComponentA.java",
+ "package libraryA;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "public abstract class ComponentA {",
+ " public abstract A getA();",
+ "}")
+ .addSrcFile(
+ "A.java",
+ "package libraryA;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public class A {",
+ " @Inject A() {}",
+ "}")
+ .addSrcFile(
+ "AScope.java",
+ "package libraryA;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope",
+ "public @interface AScope {}");
+
+ return GradleRunner.create().withArguments("--stacktrace", "build").withProjectDir(projectDir);
+ }
+}
diff --git a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveMapKeyTest.java b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveMapKeyTest.java
new file mode 100644
index 000000000..0458b0874
--- /dev/null
+++ b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveMapKeyTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package buildtests;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
+
+import java.io.File;
+import java.io.IOException;
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.GradleRunner;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+// This is a regression test for https://github.com/google/dagger/issues/3133
+@RunWith(JUnit4.class)
+public class TransitiveMapKeyTest {
+ @Rule public TemporaryFolder folder = new TemporaryFolder();
+
+ @Test
+ public void testTransitiveMapKey_WithImplementation() throws IOException {
+ BuildResult result = setupRunnerWith("implementation").buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ assertThat(result.getOutput())
+ .contains(
+ "Missing map key annotation for method: library1.MyModule#provideString(). "
+ + "That method was annotated with: "
+ + "@dagger.Provides,"
+ + "@dagger.multibindings.IntoMap,"
+ + "@library2.MyMapKey(\"some-key\")");
+ }
+
+ @Test
+ public void testTransitiveMapKey_WithApi() throws IOException {
+ // Test that if we use an "api" dependency for the custom map key things work properly.
+ BuildResult result = setupRunnerWith("api").build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ }
+
+ private GradleRunner setupRunnerWith(String dependencyType) throws IOException {
+ File projectDir = folder.getRoot();
+ GradleModule.create(projectDir)
+ .addSettingsFile(
+ "include 'app'",
+ "include 'library1'",
+ "include 'library2'")
+ .addBuildFile(
+ "buildscript {",
+ " ext {",
+ String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")),
+ " }",
+ "}",
+ "",
+ "allprojects {",
+ " repositories {",
+ " mavenCentral()",
+ " mavenLocal()",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "app")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'application'",
+ "}",
+ "dependencies {",
+ " implementation project(':library1')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyComponent.java",
+ "package app;",
+ "",
+ "import dagger.Component;",
+ "import library1.MyModule;",
+ "import java.util.Map;",
+ "",
+ "@Component(modules = MyModule.class)",
+ "public interface MyComponent {",
+ " Map<String, String> multiMap();",
+ "}");
+
+ GradleModule.create(projectDir, "library1")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ dependencyType + " project(':library2')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyModule.java",
+ "package library1;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoMap;",
+ "import library2.MyMapKey;",
+ "",
+ "@Module",
+ "public interface MyModule {",
+ " @Provides",
+ " @IntoMap",
+ " @MyMapKey(\"some-key\")",
+ " static String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "library2")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyMapKey.java",
+ "package library2;",
+ "",
+ "import dagger.MapKey;",
+ "",
+ "@MapKey",
+ "public @interface MyMapKey {",
+ " String value();",
+ "}");
+
+ return GradleRunner.create()
+ .withArguments("--stacktrace", "build")
+ .withProjectDir(projectDir);
+ }
+}
diff --git a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveProvidesParameterizedTypeTest.java b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveProvidesParameterizedTypeTest.java
new file mode 100644
index 000000000..181c9d2d0
--- /dev/null
+++ b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveProvidesParameterizedTypeTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package buildtests;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.GradleRunner;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+// This is a regression test for https://github.com/google/dagger/issues/3163
+@RunWith(Parameterized.class)
+public class TransitiveProvidesParameterizedTypeTest {
+ @Parameters(name = "{0}")
+ public static Collection<Object[]> parameters() {
+ return Arrays.asList(new Object[][] {{ "implementation" }, { "api" }});
+ }
+
+ @Rule public TemporaryFolder folder = new TemporaryFolder();
+
+ private final String transitiveDependencyType;
+
+ public TransitiveProvidesParameterizedTypeTest(String transitiveDependencyType) {
+ this.transitiveDependencyType = transitiveDependencyType;
+ }
+
+ @Test
+ public void testQualifierOnProvidesMethodParameter() throws IOException {
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ result = setupRunner().buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ assertThat(result.getOutput())
+ .contains(
+ "error: ComponentProcessingStep was unable to process 'app.MyComponent' because"
+ + " 'library2.TransitiveType' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (INTERFACE): library1.MyModule"
+ + "\n => element (METHOD):"
+ + " provideInt(library2.TransitiveType<java.lang.String>)"
+ + "\n => type (EXECUTABLE method):"
+ + " (library2.TransitiveType<java.lang.String>)java.lang.String"
+ + "\n => type (ERROR parameter type):"
+ + " library2.TransitiveType<java.lang.String>");
+ break;
+ case "api":
+ result = setupRunner().build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput())
+ .contains("Binding: library2.TransitiveType<java.lang.String>");
+ break;
+ }
+ }
+
+ private GradleRunner setupRunner() throws IOException {
+ File projectDir = folder.getRoot();
+ GradleModule.create(projectDir)
+ .addSettingsFile(
+ "include 'app'",
+ "include 'library1'",
+ "include 'library2'",
+ "include 'spi-plugin'")
+ .addBuildFile(
+ "buildscript {",
+ " ext {",
+ String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")),
+ " }",
+ "}",
+ "",
+ "allprojects {",
+ " repositories {",
+ " mavenCentral()",
+ " mavenLocal()",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "app")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'application'",
+ "}",
+ "tasks.withType(JavaCompile) {",
+ " options.compilerArgs += '-Adagger.experimentalDaggerErrorMessages=ENABLED'",
+ "}",
+ "dependencies {",
+ " implementation project(':library1')",
+ " annotationProcessor project(':spi-plugin')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyComponent.java",
+ "package app;",
+ "",
+ "import dagger.Component;",
+ "import library1.MyModule;",
+ "",
+ "@Component(modules = MyModule.class)",
+ "public interface MyComponent {",
+ " String string();",
+ "}");
+
+ GradleModule.create(projectDir, "library1")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ transitiveDependencyType + " project(':library2')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyModule.java",
+ "package library1;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import library2.TransitiveType;",
+ "",
+ "@Module",
+ "public interface MyModule {",
+ " @Provides",
+ " static String provideInt(TransitiveType<String> transitiveType) {",
+ " return \"\";",
+ " }",
+ "",
+ " @Provides",
+ " static TransitiveType<String> provideTransitiveType() {",
+ " return new TransitiveType<>();",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "library2")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ " implementation 'javax.inject:javax.inject:1'",
+ "}")
+ .addSrcFile(
+ "TransitiveType.java",
+ "package library2;",
+ "",
+ "public class TransitiveType<T> {}");
+
+ // This plugin is used to print output about bindings that we can assert on in tests.
+ GradleModule.create(projectDir, "spi-plugin")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ "}",
+ "dependencies {",
+ " implementation \"com.google.dagger:dagger-spi:$dagger_version\"",
+ " implementation 'com.google.auto.service:auto-service-annotations:1.0.1'",
+ " annotationProcessor 'com.google.auto.service:auto-service:1.0.1'",
+ "}")
+ .addSrcFile(
+ "TestBindingGraphPlugin.java",
+ "package spiplugin;",
+ "",
+ "import com.google.auto.service.AutoService;",
+ "import dagger.model.Binding;",
+ "import dagger.model.BindingGraph;",
+ "import dagger.model.BindingGraph.DependencyEdge;",
+ "import dagger.model.DependencyRequest;",
+ "import dagger.spi.BindingGraphPlugin;",
+ "import dagger.spi.DiagnosticReporter;",
+ "",
+ "@AutoService(BindingGraphPlugin.class)",
+ "public class TestBindingGraphPlugin implements BindingGraphPlugin {",
+ " @Override",
+ " public void visitGraph(",
+ " BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {",
+ " bindingGraph.bindings().stream()",
+ " .map(Binding::key)",
+ " .forEach(key -> System.out.println(\"Binding: \" + key));",
+ " }",
+ "}");
+
+ return GradleRunner.create()
+ .withArguments("--stacktrace", "build")
+ .withProjectDir(projectDir);
+ }
+}
diff --git a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveProvidesQualifierTest.java b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveProvidesQualifierTest.java
new file mode 100644
index 000000000..aaf7745d8
--- /dev/null
+++ b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveProvidesQualifierTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package buildtests;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.GradleRunner;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+// This is a regression test for https://github.com/google/dagger/issues/3136
+@RunWith(Parameterized.class)
+public class TransitiveProvidesQualifierTest {
+ @Parameters(name = "{0}")
+ public static Collection<Object[]> parameters() {
+ return Arrays.asList(new Object[][] {{ "implementation" }, { "api" }});
+ }
+
+ @Rule public TemporaryFolder folder = new TemporaryFolder();
+
+ private final String transitiveDependencyType;
+
+ public TransitiveProvidesQualifierTest(String transitiveDependencyType) {
+ this.transitiveDependencyType = transitiveDependencyType;
+ }
+
+ @Test
+ public void testQualifierOnProvidesMethodParameter() throws IOException {
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ result = setupRunner().buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ assertThat(result.getOutput())
+ .contains(
+ "ComponentProcessingStep was unable to process 'app.MyComponent' because "
+ + "'library2.MyQualifier' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (INTERFACE): library1.MyModule"
+ + "\n => element (METHOD): provideString(int)"
+ + "\n => element (PARAMETER): i"
+ + "\n => annotation: @library2.MyQualifier");
+ break;
+ case "api":
+ result = setupRunner().build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput()).contains("REQUEST: @library2.MyQualifier java.lang.Integer");
+ break;
+ }
+ }
+
+ private GradleRunner setupRunner() throws IOException {
+ File projectDir = folder.getRoot();
+ GradleModule.create(projectDir)
+ .addSettingsFile(
+ "include 'app'",
+ "include 'library1'",
+ "include 'library2'",
+ "include 'spi-plugin'")
+ .addBuildFile(
+ "buildscript {",
+ " ext {",
+ String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")),
+ " }",
+ "}",
+ "",
+ "allprojects {",
+ " repositories {",
+ " mavenCentral()",
+ " mavenLocal()",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "app")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'application'",
+ "}",
+ "tasks.withType(JavaCompile) {",
+ " options.compilerArgs += '-Adagger.experimentalDaggerErrorMessages=ENABLED'",
+ "}",
+ "dependencies {",
+ " implementation project(':library1')",
+ " annotationProcessor project(':spi-plugin')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyComponent.java",
+ "package app;",
+ "",
+ "import dagger.Component;",
+ "import library1.MyModule;",
+ "",
+ "@Component(modules = MyModule.class)",
+ "public interface MyComponent {",
+ " String string();",
+ "}");
+
+ GradleModule.create(projectDir, "library1")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ transitiveDependencyType + " project(':library2')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyModule.java",
+ "package library1;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import library2.MyQualifier;",
+ "",
+ "@Module",
+ "public interface MyModule {",
+ " @Provides",
+ " static String provideString(@MyQualifier int i) {",
+ " return \"\";",
+ " }",
+ "",
+ " @Provides",
+ " @MyQualifier",
+ " static int provideInt() {",
+ " return 0;",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "library2")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ " implementation 'javax.inject:javax.inject:1'",
+ "}")
+ .addSrcFile(
+ "MyQualifier.java",
+ "package library2;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "public @interface MyQualifier {}");
+
+ // This plugin is used to print output about bindings that we can assert on in tests.
+ GradleModule.create(projectDir, "spi-plugin")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ "}",
+ "dependencies {",
+ " implementation \"com.google.dagger:dagger-spi:$dagger_version\"",
+ " implementation 'com.google.auto.service:auto-service-annotations:1.0.1'",
+ " annotationProcessor 'com.google.auto.service:auto-service:1.0.1'",
+ "}")
+ .addSrcFile(
+ "TestBindingGraphPlugin.java",
+ "package spiplugin;",
+ "",
+ "import com.google.auto.service.AutoService;",
+ "import dagger.model.BindingGraph;",
+ "import dagger.model.BindingGraph.DependencyEdge;",
+ "import dagger.model.DependencyRequest;",
+ "import dagger.spi.BindingGraphPlugin;",
+ "import dagger.spi.DiagnosticReporter;",
+ "",
+ "@AutoService(BindingGraphPlugin.class)",
+ "public class TestBindingGraphPlugin implements BindingGraphPlugin {",
+ " @Override",
+ " public void visitGraph(",
+ " BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {",
+ " bindingGraph.dependencyEdges().stream()",
+ " .map(DependencyEdge::dependencyRequest)",
+ " .map(DependencyRequest::key)",
+ " .forEach(key -> System.out.println(\"REQUEST: \" + key));",
+ " }",
+ "}");
+
+ return GradleRunner.create()
+ .withArguments("--stacktrace", "build")
+ .withProjectDir(projectDir);
+ }
+}
diff --git a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveProvidesScopeTest.java b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveProvidesScopeTest.java
new file mode 100644
index 000000000..36f3cdc2a
--- /dev/null
+++ b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveProvidesScopeTest.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package buildtests;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.GradleRunner;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+// This is a regression test for https://github.com/google/dagger/issues/3136
+@RunWith(Parameterized.class)
+public class TransitiveProvidesScopeTest {
+ @Parameters(name = "{0}")
+ public static Collection<Object[]> parameters() {
+ return Arrays.asList(new Object[][] {{ "implementation" }, { "api" }});
+ }
+
+ @Rule public TemporaryFolder folder = new TemporaryFolder();
+
+ private final String transitiveDependencyType;
+
+ public TransitiveProvidesScopeTest(String transitiveDependencyType) {
+ this.transitiveDependencyType = transitiveDependencyType;
+ }
+
+ @Test
+ public void testScopeOnProvidesMethod() throws IOException {
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ result = setupRunner().buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ assertThat(result.getOutput())
+ .contains(
+ "ComponentProcessingStep was unable to process 'app.MyComponent' because "
+ + "'library2.MyScope' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (INTERFACE): library1.MyModule"
+ + "\n => element (METHOD): provideString()"
+ + "\n => annotation: @library2.MyScope");
+ break;
+ case "api":
+ result = setupRunner().build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput())
+ .contains(
+ "@Provides @library2.MyScope String library1.MyModule.provideString(): SCOPED");
+ break;
+ }
+ }
+
+ private GradleRunner setupRunner() throws IOException {
+ File projectDir = folder.getRoot();
+ GradleModule.create(projectDir)
+ .addSettingsFile(
+ "include 'app'",
+ "include 'library1'",
+ "include 'library2'",
+ "include 'spi-plugin'")
+ .addBuildFile(
+ "buildscript {",
+ " ext {",
+ String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")),
+ " }",
+ "}",
+ "",
+ "allprojects {",
+ " repositories {",
+ " mavenCentral()",
+ " mavenLocal()",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "app")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'application'",
+ "}",
+ "tasks.withType(JavaCompile) {",
+ " options.compilerArgs += '-Adagger.experimentalDaggerErrorMessages=ENABLED'",
+ "}",
+ "dependencies {",
+ " implementation project(':library1')",
+ " annotationProcessor project(':spi-plugin')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyComponent.java",
+ "package app;",
+ "",
+ "import dagger.Component;",
+ "import library1.MySubcomponent;",
+ "",
+ "@Component",
+ "public interface MyComponent {",
+ " MySubcomponent subcomponent();",
+ "}");
+
+ GradleModule.create(projectDir, "library1")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ transitiveDependencyType + " project(':library2')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ // Note: In order to repro the issue we place MyScope on a subcomponent so that it can be a
+ // transitive dependency of the component. If MyScope was placed on directly on the
+ // component, it would need to be a direct dependency of the component.
+ .addSrcFile(
+ "MySubcomponent.java",
+ "package library1;",
+ "",
+ "import dagger.Subcomponent;",
+ "import library2.MyScope;",
+ "",
+ "@MyScope",
+ "@Subcomponent(modules = MyModule.class)",
+ "public interface MySubcomponent {",
+ " String string();",
+ "}")
+ .addSrcFile(
+ "MyModule.java",
+ "package library1;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import library2.MyScope;",
+ "",
+ "@Module",
+ "public interface MyModule {",
+ " @MyScope",
+ " @Provides",
+ " static String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "library2")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ " implementation 'javax.inject:javax.inject:1'",
+ "}")
+ .addSrcFile(
+ "MyScope.java",
+ "package library2;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope",
+ "public @interface MyScope {}");
+
+ // This plugin is used to print output about bindings that we can assert on in tests.
+ GradleModule.create(projectDir, "spi-plugin")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ "}",
+ "dependencies {",
+ " implementation \"com.google.dagger:dagger-spi:$dagger_version\"",
+ " implementation 'com.google.auto.service:auto-service-annotations:1.0.1'",
+ " annotationProcessor 'com.google.auto.service:auto-service:1.0.1'",
+ "}")
+ .addSrcFile(
+ "TestBindingGraphPlugin.java",
+ "package spiplugin;",
+ "",
+ "import com.google.auto.service.AutoService;",
+ "import dagger.model.BindingGraph;",
+ "import dagger.model.BindingGraph.DependencyEdge;",
+ "import dagger.model.DependencyRequest;",
+ "import dagger.spi.BindingGraphPlugin;",
+ "import dagger.spi.DiagnosticReporter;",
+ "",
+ "@AutoService(BindingGraphPlugin.class)",
+ "public class TestBindingGraphPlugin implements BindingGraphPlugin {",
+ " @Override",
+ " public void visitGraph(",
+ " BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {",
+ " bindingGraph.bindings().stream()",
+ " .filter(binding -> binding.scope().isPresent())",
+ " .forEach(binding -> System.out.println(binding + \": SCOPED\"));",
+ " bindingGraph.bindings().stream()",
+ " .filter(binding -> !binding.scope().isPresent())",
+ " .forEach(binding -> System.out.println(binding + \": UNSCOPED\"));",
+ " }",
+ "}");
+
+ return GradleRunner.create()
+ .withArguments("--stacktrace", "build")
+ .withProjectDir(projectDir);
+ }
+}
diff --git a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveQualifierTest.java b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveQualifierTest.java
new file mode 100644
index 000000000..1cf1ba553
--- /dev/null
+++ b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveQualifierTest.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package buildtests;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.GradleRunner;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+// This is a regression test for https://github.com/google/dagger/issues/3136
+@RunWith(Parameterized.class)
+public class TransitiveQualifierTest {
+ @Parameters(name = "transitiveDependencyType = {0}, strictSuperficialValidationMode = {1}")
+ public static Collection<Object[]> parameters() {
+ return Arrays.asList(
+ new Object[][] {
+ { "implementation", "ENABLED" },
+ { "implementation", "DISABLED" },
+ { "api", "ENABLED" },
+ { "api", "DISABLED" }
+ });
+ }
+
+ @Rule public TemporaryFolder folder = new TemporaryFolder();
+
+ private final String transitiveDependencyType;
+ private final String strictSuperficialValidationMode;
+
+ public TransitiveQualifierTest(
+ String transitiveDependencyType, String strictSuperficialValidationMode) {
+ this.transitiveDependencyType = transitiveDependencyType;
+ this.strictSuperficialValidationMode = strictSuperficialValidationMode;
+ }
+
+ @Test
+ public void testQualifierOnInjectConstructorParameter() throws IOException {
+ GradleRunner runner =
+ setupRunnerWith(
+ GradleFile.create(
+ "QualifierUsage.java",
+ "package library1;",
+ "",
+ "import javax.inject.Inject;",
+ "import library2.MyQualifier;",
+ "",
+ "public class QualifierUsage {",
+ " @Inject QualifierUsage(@MyQualifier int i) {}",
+ "}"));
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ switch (strictSuperficialValidationMode) {
+ case "ENABLED":
+ result = runner.buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ // TODO(bcorso): Give more context about what couldn't be resolved once we've fixed the
+ // issue described in https://github.com/google/dagger/issues/2208.
+ assertThat(result.getOutput())
+ .contains(
+ "ComponentProcessingStep was unable to process 'app.MyComponent' because "
+ + "'library2.MyQualifier' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (INTERFACE): library1.MyModule"
+ + "\n => element (METHOD): provideInt()"
+ + "\n => annotation: @library2.MyQualifier");
+ break;
+ case "DISABLED":
+ // When strict mode is disabled we fall back to the old behavior where the qualifier is
+ // missing and we do not throw an exception.
+ result = runner.build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput()).contains("REQUEST: java.lang.Integer");
+ break;
+ default: throw new AssertionError("Unexpected mode: " + strictSuperficialValidationMode);
+ }
+ break;
+ case "api":
+ result = runner.build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput()).contains("REQUEST: @library2.MyQualifier java.lang.Integer");
+ break;
+ }
+ }
+
+ @Test
+ public void testQualifierOnInjectField() throws IOException {
+ GradleRunner runner =
+ setupRunnerWith(
+ GradleFile.create(
+ "QualifierUsage.java",
+ "package library1;",
+ "",
+ "import javax.inject.Inject;",
+ "import library2.MyQualifier;",
+ "",
+ "public class QualifierUsage {",
+ " @Inject @MyQualifier int i;",
+ "",
+ " @Inject QualifierUsage() {}",
+ "}"));
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ switch (strictSuperficialValidationMode) {
+ case "ENABLED":
+ result = runner.buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ // TODO(bcorso): Give more context about what couldn't be resolved once we've fixed the
+ // issue described in https://github.com/google/dagger/issues/2208.
+ assertThat(result.getOutput())
+ .contains(
+ "ComponentProcessingStep was unable to process 'app.MyComponent' because "
+ + "'library2.MyQualifier' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (INTERFACE): library1.MyModule"
+ + "\n => element (METHOD): provideInt()"
+ + "\n => annotation: @library2.MyQualifier");
+ break;
+ case "DISABLED":
+ // When strict mode is disabled we fall back to the old behavior where the qualifier is
+ // missing and we do not throw an exception.
+ result = runner.build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput()).contains("REQUEST: java.lang.Integer");
+ break;
+ default: throw new AssertionError("Unexpected mode: " + strictSuperficialValidationMode);
+ }
+ break;
+ case "api":
+ result = runner.build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput()).contains("REQUEST: @library2.MyQualifier java.lang.Integer");
+ break;
+ }
+ }
+
+ @Test
+ public void testQualifierOnInjectMethodParameter() throws IOException {
+ GradleRunner runner =
+ setupRunnerWith(
+ GradleFile.create(
+ "QualifierUsage.java",
+ "package library1;",
+ "",
+ "import javax.inject.Inject;",
+ "import library2.MyQualifier;",
+ "",
+ "public class QualifierUsage {",
+ " @Inject QualifierUsage() {}",
+ "",
+ " @Inject void injectMethod(@MyQualifier int i) {}",
+ "}"));
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ switch (strictSuperficialValidationMode) {
+ case "ENABLED":
+ result = runner.buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ // TODO(bcorso): Give more context about what couldn't be resolved once we've fixed the
+ // issue described in https://github.com/google/dagger/issues/2208.
+ assertThat(result.getOutput())
+ .contains(
+ "ComponentProcessingStep was unable to process 'app.MyComponent' because "
+ + "'library2.MyQualifier' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (INTERFACE): library1.MyModule"
+ + "\n => element (METHOD): provideInt()"
+ + "\n => annotation: @library2.MyQualifier");
+ break;
+ case "DISABLED":
+ // When strict mode is disabled we fall back to the old behavior where the qualifier is
+ // missing and we do not throw an exception.
+ result = runner.build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput()).contains("REQUEST: java.lang.Integer");
+ break;
+ default: throw new AssertionError("Unexpected mode: " + strictSuperficialValidationMode);
+ }
+ break;
+ case "api":
+ result = runner.build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput()).contains("REQUEST: @library2.MyQualifier java.lang.Integer");
+ break;
+ }
+ }
+
+ private GradleRunner setupRunnerWith(GradleFile qualifierUsage) throws IOException {
+ File projectDir = folder.getRoot();
+ GradleModule.create(projectDir)
+ .addSettingsFile(
+ "include 'app'",
+ "include 'library1'",
+ "include 'library2'",
+ "include 'spi-plugin'")
+ .addBuildFile(
+ "buildscript {",
+ " ext {",
+ String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")),
+ " }",
+ "}",
+ "",
+ "allprojects {",
+ " repositories {",
+ " mavenCentral()",
+ " mavenLocal()",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "app")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'application'",
+ "}",
+ "tasks.withType(JavaCompile) {",
+ String.format(
+ " options.compilerArgs += '-Adagger.strictSuperficialValidation=%s'",
+ strictSuperficialValidationMode),
+ "}",
+ "dependencies {",
+ " implementation project(':library1')",
+ " annotationProcessor project(':spi-plugin')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyComponent.java",
+ "package app;",
+ "",
+ "import dagger.Component;",
+ "import library1.MyModule;",
+ "import library1.QualifierUsage;",
+ "",
+ "@Component(modules = MyModule.class)",
+ "public interface MyComponent {",
+ " QualifierUsage qualifierUsage();",
+ "}");
+
+ GradleModule.create(projectDir, "library1")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ transitiveDependencyType + " project(':library2')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyModule.java",
+ "package library1;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import library2.MyQualifier;",
+ "",
+ "@Module",
+ "public interface MyModule {",
+ " @Provides",
+ " @MyQualifier",
+ " static int provideInt() {",
+ " return 0;",
+ " }",
+ "}")
+ .addSrcFile(qualifierUsage);
+
+ GradleModule.create(projectDir, "library2")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ " implementation 'javax.inject:javax.inject:1'",
+ "}")
+ .addSrcFile(
+ "MyQualifier.java",
+ "package library2;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "public @interface MyQualifier {}");
+
+ // This plugin is used to print output about bindings that we can assert on in tests.
+ GradleModule.create(projectDir, "spi-plugin")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ "}",
+ "dependencies {",
+ " implementation \"com.google.dagger:dagger-spi:$dagger_version\"",
+ " implementation 'com.google.auto.service:auto-service-annotations:1.0.1'",
+ " annotationProcessor 'com.google.auto.service:auto-service:1.0.1'",
+ "}")
+ .addSrcFile(
+ "TestBindingGraphPlugin.java",
+ "package spiplugin;",
+ "",
+ "import com.google.auto.service.AutoService;",
+ "import dagger.model.BindingGraph;",
+ "import dagger.model.BindingGraph.DependencyEdge;",
+ "import dagger.model.DependencyRequest;",
+ "import dagger.spi.BindingGraphPlugin;",
+ "import dagger.spi.DiagnosticReporter;",
+ "",
+ "@AutoService(BindingGraphPlugin.class)",
+ "public class TestBindingGraphPlugin implements BindingGraphPlugin {",
+ " @Override",
+ " public void visitGraph(",
+ " BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {",
+ " bindingGraph.dependencyEdges().stream()",
+ " .map(DependencyEdge::dependencyRequest)",
+ " .map(DependencyRequest::key)",
+ " .forEach(key -> System.out.println(\"REQUEST: \" + key));",
+ " }",
+ "}");
+
+ return GradleRunner.create()
+ .withArguments("--stacktrace", "build")
+ .withProjectDir(projectDir);
+ }
+}
diff --git a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveScopeTest.java b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveScopeTest.java
new file mode 100644
index 000000000..ec54605dd
--- /dev/null
+++ b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveScopeTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package buildtests;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
+
+import java.io.File;
+import java.io.IOException;
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.GradleRunner;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+// This is a regression test for https://github.com/google/dagger/issues/3136
+@RunWith(JUnit4.class)
+public class TransitiveScopeTest {
+ @Rule public TemporaryFolder folder = new TemporaryFolder();
+
+ @Test
+ public void testTransitiveScope_WithImplementation() throws IOException {
+ BuildResult result = setupRunnerWith("implementation").buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ assertThat(result.getOutput())
+ .contains(
+ "ComponentProcessingStep was unable to process 'app.MyComponent' because "
+ + "'library2.MyScope' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ // Note: this fails on the subcomponent rather than Foo because the subcomponent is
+ // validated before any of its dependencies.
+ + "\n => element (INTERFACE): library1.MySubcomponent"
+ + "\n => annotation: @library2.MyScope");
+ }
+
+ @Test
+ public void testTransitiveScope_WithApi() throws IOException {
+ BuildResult result = setupRunnerWith("api").build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput()).contains("@Inject library1.Foo(): SCOPED");
+ }
+
+ private GradleRunner setupRunnerWith(String dependencyType) throws IOException {
+ File projectDir = folder.getRoot();
+ GradleModule.create(projectDir)
+ .addSettingsFile(
+ "include 'app'",
+ "include 'library1'",
+ "include 'library2'",
+ "include 'spi-plugin'")
+ .addBuildFile(
+ "buildscript {",
+ " ext {",
+ String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")),
+ " }",
+ "}",
+ "",
+ "allprojects {",
+ " repositories {",
+ " mavenCentral()",
+ " mavenLocal()",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "app")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'application'",
+ "}",
+ "dependencies {",
+ " implementation project(':library1')",
+ " annotationProcessor project(':spi-plugin')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyComponent.java",
+ "package app;",
+ "",
+ "import dagger.Component;",
+ "import library1.MySubcomponent;",
+ "",
+ "@Component",
+ "public interface MyComponent {",
+ " MySubcomponent subcomponent();",
+ "}");
+
+ GradleModule.create(projectDir, "library1")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ dependencyType + " project(':library2')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "Foo.java",
+ "package library1;",
+ "",
+ "import javax.inject.Inject;",
+ "import library2.MyScope;",
+ "",
+ "@MyScope",
+ "public class Foo {",
+ " @Inject Foo() {}",
+ "}")
+ // Note: In order to repro the issue we place MyScope on a subcomponent so that it can be a
+ // transitive dependency of the component. If MyScope was placed on directly on the
+ // component, it would need to be a direct dependency of the component.
+ .addSrcFile(
+ "MySubcomponent.java",
+ "package library1;",
+ "",
+ "import dagger.Subcomponent;",
+ "import library2.MyScope;",
+ "",
+ "@MyScope",
+ "@Subcomponent",
+ "public interface MySubcomponent {",
+ " Foo foo();",
+ "}");
+
+ GradleModule.create(projectDir, "library2")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ " implementation 'javax.inject:javax.inject:1'",
+ "}")
+ .addSrcFile(
+ "MyScope.java",
+ "package library2;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope",
+ "public @interface MyScope {}");
+
+ // This plugin is used to print output about bindings that we can assert on in tests.
+ GradleModule.create(projectDir, "spi-plugin")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ "}",
+ "dependencies {",
+ " implementation \"com.google.dagger:dagger-spi:$dagger_version\"",
+ " implementation 'com.google.auto.service:auto-service-annotations:1.0.1'",
+ " annotationProcessor 'com.google.auto.service:auto-service:1.0.1'",
+ "}")
+ .addSrcFile(
+ "TestBindingGraphPlugin.java",
+ "package spiplugin;",
+ "",
+ "import com.google.auto.service.AutoService;",
+ "import dagger.model.BindingGraph;",
+ "import dagger.spi.BindingGraphPlugin;",
+ "import dagger.spi.DiagnosticReporter;",
+ "",
+ "@AutoService(BindingGraphPlugin.class)",
+ "public class TestBindingGraphPlugin implements BindingGraphPlugin {",
+ " @Override",
+ " public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter"
+ + " diagnosticReporter) {",
+ " bindingGraph.bindings().stream()",
+ " .filter(binding -> binding.scope().isPresent())",
+ " .forEach(binding -> System.out.println(binding + \": SCOPED\"));",
+ " bindingGraph.bindings().stream()",
+ " .filter(binding -> !binding.scope().isPresent())",
+ " .forEach(binding -> System.out.println(binding + \": UNSCOPED\"));",
+ " }",
+ "}");
+
+ return GradleRunner.create()
+ .withArguments("--stacktrace", "build")
+ .withProjectDir(projectDir);
+ }
+}
diff --git a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentModulesTest.java b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentModulesTest.java
new file mode 100644
index 000000000..31376c09d
--- /dev/null
+++ b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentModulesTest.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package buildtests;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.GradleRunner;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+// This is a regression test for https://github.com/google/dagger/issues/3136
+@RunWith(Parameterized.class)
+public class TransitiveSubcomponentModulesTest {
+ @Parameters(name = "{0}")
+ public static Collection<Object[]> parameters() {
+ return Arrays.asList(new Object[][] {{"implementation"}, {"api"}});
+ }
+
+ @Rule public TemporaryFolder folder = new TemporaryFolder();
+
+ private final String transitiveDependencyType;
+
+ public TransitiveSubcomponentModulesTest(String transitiveDependencyType) {
+ this.transitiveDependencyType = transitiveDependencyType;
+ }
+
+ @Test
+ public void testSubcomponentAnnotationWithTransitiveModule() throws IOException {
+ GradleRunner runner =
+ setupRunner(
+ GradleFile.create(
+ "MySubcomponent.java",
+ "package library1;",
+ "",
+ "import dagger.Subcomponent;",
+ "import library2.TransitiveModule;",
+ "",
+ "@Subcomponent(modules = TransitiveModule.class)",
+ "public abstract class MySubcomponent {",
+ " public abstract int getInt();",
+ "}"));
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ result = runner.buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ String expectedErrorMsg =
+ "error: ComponentProcessingStep was unable to process 'app.MyComponent' because"
+ + " 'library2.TransitiveModule' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (CLASS): library1.MySubcomponent"
+ + "\n => annotation:"
+ + " @dagger.Subcomponent(modules = library2.TransitiveModule.class)"
+ + "\n => annotation method: java.lang.Class<?>[] modules()"
+ + "\n => annotation value (ARRAY):"
+ + " value 'library2.TransitiveModule.class' with expected type java.lang.Class<?>[]"
+ + "\n => annotation value (TYPE):"
+ + " value 'library2.TransitiveModule' with expected type java.lang.Class<?>"
+ + "\n => type (ERROR annotation value type): library2.TransitiveModule";
+ assertThat(result.getOutput()).contains(expectedErrorMsg);
+ break;
+ case "api":
+ result = runner.build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ break;
+ }
+ }
+
+ @Test
+ public void testSubcomponentAnnotationWithModuleIncludesTransitiveModuleDependencies()
+ throws IOException {
+ GradleRunner runner =
+ setupRunner(
+ GradleFile.create(
+ "MySubcomponent.java",
+ "package library1;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = IncludesTransitiveModule.class)",
+ "public abstract class MySubcomponent {",
+ " public abstract int getInt();",
+ "}"));
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ result = runner.buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ String expectedErrorMsg =
+ "error: ComponentProcessingStep was unable to process 'app.MyComponent' because"
+ + " 'library2.TransitiveModule' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (INTERFACE): library1.IncludesTransitiveModule"
+ + "\n => annotation:"
+ + " @dagger.Module(includes = library2.TransitiveModule.class)"
+ + "\n => annotation method: java.lang.Class<?>[] includes()"
+ + "\n => annotation value (ARRAY):"
+ + " value 'library2.TransitiveModule.class' with expected type java.lang.Class<?>[]"
+ + "\n => annotation value (TYPE):"
+ + " value 'library2.TransitiveModule' with expected type java.lang.Class<?>";
+ assertThat(result.getOutput()).contains(expectedErrorMsg);
+ break;
+ case "api":
+ result = runner.build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ break;
+ }
+ }
+
+ private GradleRunner setupRunner(GradleFile subcomponent) throws IOException {
+ File projectDir = folder.getRoot();
+ GradleModule.create(projectDir)
+ .addSettingsFile("include 'app'", "include 'library1'", "include 'library2'")
+ .addBuildFile(
+ "buildscript {",
+ " ext {",
+ String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")),
+ " }",
+ "}",
+ "",
+ "allprojects {",
+ " repositories {",
+ " mavenCentral()",
+ " mavenLocal()",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "app")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'application'",
+ "}",
+ "tasks.withType(JavaCompile) {",
+ " options.compilerArgs += '-Adagger.experimentalDaggerErrorMessages=ENABLED'",
+ "}",
+ "dependencies {",
+ " implementation project(':library1')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyComponent.java",
+ "package app;",
+ "",
+ "import dagger.Component;",
+ "import library1.MySubcomponent;",
+ "",
+ "@Component",
+ "public interface MyComponent {",
+ " MySubcomponent mySubcomponent();",
+ "}");
+
+ GradleModule.create(projectDir, "library1")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ transitiveDependencyType + " project(':library2')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "IncludesTransitiveModule.java",
+ "package library1;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import library2.TransitiveModule;",
+ "",
+ "@Module(includes = TransitiveModule.class)",
+ "public interface IncludesTransitiveModule {}")
+ .addSrcFile(subcomponent);
+
+ GradleModule.create(projectDir, "library2")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "TransitiveModule.java",
+ "package library2;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "public interface TransitiveModule {",
+ " @Provides",
+ " static int provideInt() {",
+ " return 0;",
+ " }",
+ "}");
+
+ return GradleRunner.create().withArguments("--stacktrace", "build").withProjectDir(projectDir);
+ }
+}
diff --git a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentQualifierTest.java b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentQualifierTest.java
new file mode 100644
index 000000000..c135d742b
--- /dev/null
+++ b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentQualifierTest.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package buildtests;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.GradleRunner;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+// This is a regression test for https://github.com/google/dagger/issues/3136
+@RunWith(Parameterized.class)
+public class TransitiveSubcomponentQualifierTest {
+ @Parameters(name = "{0}")
+ public static Collection<Object[]> parameters() {
+ return Arrays.asList(new Object[][] {{"implementation"}, {"api"}});
+ }
+
+ @Rule public TemporaryFolder folder = new TemporaryFolder();
+
+ private final String transitiveDependencyType;
+
+ public TransitiveSubcomponentQualifierTest(String transitiveDependencyType) {
+ this.transitiveDependencyType = transitiveDependencyType;
+ }
+
+ @Test
+ public void testQualifierWithFactory() throws IOException {
+ GradleRunner runner =
+ setupRunnerWith(
+ GradleFile.create(
+ "MySubcomponent.java",
+ "package library1;",
+ "",
+ "import dagger.BindsInstance;",
+ "import dagger.Subcomponent;",
+ "import library2.MyQualifier;",
+ "",
+ "@Subcomponent",
+ "public abstract class MySubcomponent {",
+ " @MyQualifier",
+ " public abstract int getQualifiedInt();",
+ "",
+ " @Subcomponent.Factory",
+ " public abstract static class Creator {",
+ " public abstract MySubcomponent create(",
+ " @BindsInstance @MyQualifier int qualifiedInt);",
+ " }",
+ "}"));
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ result = runner.buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ assertThat(result.getOutput())
+ .contains(
+ "error: ComponentProcessingStep was unable to process 'app.MyComponent' because "
+ + "'library2.MyQualifier' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (CLASS): library1.MySubcomponent"
+ + "\n => element (METHOD): getQualifiedInt()"
+ + "\n => annotation: @library2.MyQualifier");
+ break;
+ case "api":
+ result = runner.build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput())
+ .contains("ENTRY_POINT_REQUEST: @library2.MyQualifier java.lang.Integer");
+ break;
+ }
+ }
+
+ @Test
+ public void testQualifierOnBaseClassWithFactory() throws IOException {
+ GradleRunner runner =
+ setupRunnerWith(
+ GradleFile.create(
+ "MySubcomponent.java",
+ "package library1;",
+ "",
+ "import dagger.Subcomponent;",
+ "import library2.MyQualifier;",
+ "",
+ "@Subcomponent",
+ "public abstract class MySubcomponent extends MyBaseSubcomponent {",
+ " @Subcomponent.Factory",
+ " public abstract static class Creator extends MyBaseSubcomponent.Creator {}",
+ "}"),
+ GradleFile.create(
+ "MyBaseSubcomponent.java",
+ "package library1;",
+ "",
+ "import dagger.BindsInstance;",
+ "import library2.MyQualifier;",
+ "",
+ "public abstract class MyBaseSubcomponent {",
+ " @MyQualifier",
+ " public abstract int getQualifiedInt();",
+ "",
+ " public abstract static class Creator {",
+ " public abstract MySubcomponent create(",
+ " @BindsInstance @MyQualifier int qualifiedInt);",
+ " }",
+ "}"));
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ result = runner.buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ assertThat(result.getOutput())
+ .contains(
+ "error: ComponentProcessingStep was unable to process 'app.MyComponent' because "
+ + "'library2.MyQualifier' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (CLASS): library1.MyBaseSubcomponent"
+ + "\n => element (METHOD): getQualifiedInt()"
+ + "\n => annotation: @library2.MyQualifier");
+ break;
+ case "api":
+ result = runner.build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput())
+ .contains("ENTRY_POINT_REQUEST: @library2.MyQualifier java.lang.Integer");
+ break;
+ }
+ }
+
+ @Test
+ public void testQualifierWithBuilder() throws IOException {
+ GradleRunner runner =
+ setupRunnerWith(
+ GradleFile.create(
+ "MySubcomponent.java",
+ "package library1;",
+ "",
+ "import dagger.BindsInstance;",
+ "import dagger.Subcomponent;",
+ "import library2.MyQualifier;",
+ "",
+ "@Subcomponent",
+ "public abstract class MySubcomponent {",
+ " @MyQualifier",
+ " public abstract int getQualifiedInt();",
+ "",
+ " @Subcomponent.Builder",
+ " public abstract static class Creator {",
+ " public abstract MySubcomponent build();",
+ " public abstract Creator qualifiedInt(",
+ " @BindsInstance @MyQualifier int qualifiedInt);",
+ " }",
+ "}"));
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ result = runner.buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ assertThat(result.getOutput())
+ .contains(
+ "error: ComponentProcessingStep was unable to process 'app.MyComponent' because "
+ + "'library2.MyQualifier' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (CLASS): library1.MySubcomponent"
+ + "\n => element (METHOD): getQualifiedInt()"
+ + "\n => annotation: @library2.MyQualifier");
+ break;
+ case "api":
+ result = runner.build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput())
+ .contains("ENTRY_POINT_REQUEST: @library2.MyQualifier java.lang.Integer");
+ break;
+ }
+ }
+
+ @Test
+ public void testQualifierOnBaseClassWithBuilder() throws IOException {
+ GradleRunner runner =
+ setupRunnerWith(
+ GradleFile.create(
+ "MySubcomponent.java",
+ "package library1;",
+ "",
+ "import dagger.Subcomponent;",
+ "import library2.MyQualifier;",
+ "",
+ "@Subcomponent",
+ "public abstract class MySubcomponent extends MyBaseSubcomponent {",
+ " @Subcomponent.Builder",
+ " public abstract static class Creator extends MyBaseSubcomponent.Creator {}",
+ "}"),
+ GradleFile.create(
+ "MyBaseSubcomponent.java",
+ "package library1;",
+ "",
+ "import dagger.BindsInstance;",
+ "import library2.MyQualifier;",
+ "",
+ "public abstract class MyBaseSubcomponent {",
+ " @MyQualifier",
+ " public abstract int getQualifiedInt();",
+ "",
+ " public abstract static class Creator {",
+ " public abstract MySubcomponent build();",
+ " public abstract Creator qualifiedInt(",
+ " @BindsInstance @MyQualifier int qualifiedInt);",
+ " }",
+ "}"));
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ result = runner.buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ // TODO(bcorso): Give more context about what couldn't be resolved once we've fixed the
+ // issue described in https://github.com/google/dagger/issues/2208.
+ assertThat(result.getOutput())
+ .contains(
+ "error: ComponentProcessingStep was unable to process 'app.MyComponent' because "
+ + "'library2.MyQualifier' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (CLASS): library1.MyBaseSubcomponent"
+ + "\n => element (METHOD): getQualifiedInt()"
+ + "\n => annotation: @library2.MyQualifier");
+ break;
+ case "api":
+ result = runner.build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput())
+ .contains("ENTRY_POINT_REQUEST: @library2.MyQualifier java.lang.Integer");
+ break;
+ }
+ }
+
+ private GradleRunner setupRunnerWith(GradleFile... library1Files) throws IOException {
+ File projectDir = folder.getRoot();
+ GradleModule.create(projectDir)
+ .addSettingsFile(
+ "include 'app'", "include 'library1'", "include 'library2'", "include 'spi-plugin'")
+ .addBuildFile(
+ "buildscript {",
+ " ext {",
+ String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")),
+ " }",
+ "}",
+ "",
+ "allprojects {",
+ " repositories {",
+ " mavenCentral()",
+ " mavenLocal()",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "app")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'application'",
+ "}",
+ "tasks.withType(JavaCompile) {",
+ " options.compilerArgs += '-Adagger.experimentalDaggerErrorMessages=ENABLED'",
+ "}",
+ "dependencies {",
+ " implementation project(':library1')",
+ " annotationProcessor project(':spi-plugin')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyComponent.java",
+ "package app;",
+ "",
+ "import dagger.Component;",
+ "import library1.MySubcomponent;",
+ "",
+ "@Component",
+ "public interface MyComponent {",
+ " MySubcomponent.Creator mySubcomponentCreator();",
+ "}");
+
+ GradleModule.create(projectDir, "library1")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ transitiveDependencyType + " project(':library2')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFiles(library1Files);
+
+ GradleModule.create(projectDir, "library2")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ " implementation 'javax.inject:javax.inject:1'",
+ "}")
+ .addSrcFile(
+ "MyQualifier.java",
+ "package library2;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "public @interface MyQualifier {}");
+
+ // This plugin is used to print output about bindings that we can assert on in tests.
+ GradleModule.create(projectDir, "spi-plugin")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ "}",
+ "dependencies {",
+ " implementation \"com.google.dagger:dagger-spi:$dagger_version\"",
+ " implementation 'com.google.auto.service:auto-service-annotations:1.0.1'",
+ " annotationProcessor 'com.google.auto.service:auto-service:1.0.1'",
+ "}")
+ .addSrcFile(
+ "TestBindingGraphPlugin.java",
+ "package spiplugin;",
+ "",
+ "import com.google.auto.service.AutoService;",
+ "import dagger.model.BindingGraph;",
+ "import dagger.model.BindingGraph.DependencyEdge;",
+ "import dagger.model.DependencyRequest;",
+ "import dagger.spi.BindingGraphPlugin;",
+ "import dagger.spi.DiagnosticReporter;",
+ "",
+ "@AutoService(BindingGraphPlugin.class)",
+ "public class TestBindingGraphPlugin implements BindingGraphPlugin {",
+ " @Override",
+ " public void visitGraph(",
+ " BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {",
+ " bindingGraph.entryPointEdges().stream()",
+ " .map(DependencyEdge::dependencyRequest)",
+ " .map(DependencyRequest::key)",
+ " .forEach(key -> System.out.println(\"ENTRY_POINT_REQUEST: \" + key));",
+ " }",
+ "}");
+
+ return GradleRunner.create().withArguments("--stacktrace", "build").withProjectDir(projectDir);
+ }
+}
diff --git a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentScopeTest.java b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentScopeTest.java
new file mode 100644
index 000000000..82d089504
--- /dev/null
+++ b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentScopeTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package buildtests;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.GradleRunner;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+// This is a regression test for https://github.com/google/dagger/issues/3136
+@RunWith(Parameterized.class)
+public class TransitiveSubcomponentScopeTest {
+ @Parameters(name = "{0}")
+ public static Collection<Object[]> parameters() {
+ return Arrays.asList(new Object[][] {{"implementation"}, {"api"}});
+ }
+
+ @Rule public TemporaryFolder folder = new TemporaryFolder();
+
+ private final String transitiveDependencyType;
+
+ public TransitiveSubcomponentScopeTest(String transitiveDependencyType) {
+ this.transitiveDependencyType = transitiveDependencyType;
+ }
+
+ @Test
+ public void testScopeWithSubcomponent() throws IOException {
+ BuildResult result;
+ switch (transitiveDependencyType) {
+ case "implementation":
+ result = setupRunner().buildAndFail();
+ assertThat(result.getOutput()).contains("Task :app:compileJava FAILED");
+ assertThat(result.getOutput())
+ .contains(
+ "error: ComponentProcessingStep was unable to process 'app.MyComponent' because "
+ + "'library2.MySubcomponentScope' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (INTERFACE): library1.MySubcomponent.MySubcomponentModule"
+ + "\n => element (METHOD): provideScopedInt()"
+ + "\n => annotation: @library2.MySubcomponentScope");
+ break;
+ case "api":
+ result = setupRunner().build();
+ assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
+ assertThat(result.getOutput())
+ .contains(
+ "@Provides @library2.MySubcomponentScope int"
+ + " library1.MySubcomponent.MySubcomponentModule.provideScopedInt(): SCOPED");
+ break;
+ }
+ }
+
+ private GradleRunner setupRunner() throws IOException {
+ File projectDir = folder.getRoot();
+ GradleModule.create(projectDir)
+ .addSettingsFile(
+ "include 'app'", "include 'library1'", "include 'library2'", "include 'spi-plugin'")
+ .addBuildFile(
+ "buildscript {",
+ " ext {",
+ String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")),
+ " }",
+ "}",
+ "",
+ "allprojects {",
+ " repositories {",
+ " mavenCentral()",
+ " mavenLocal()",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "app")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'application'",
+ "}",
+ "tasks.withType(JavaCompile) {",
+ " options.compilerArgs += '-Adagger.experimentalDaggerErrorMessages=ENABLED'",
+ "}",
+ "dependencies {",
+ " implementation project(':library1')",
+ " annotationProcessor project(':spi-plugin')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MyComponent.java",
+ "package app;",
+ "",
+ "import dagger.Component;",
+ "import library1.MySubcomponent;",
+ "",
+ "@Component",
+ "public interface MyComponent {",
+ " MySubcomponent mySubcomponent();",
+ "}");
+
+ GradleModule.create(projectDir, "library1")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ transitiveDependencyType + " project(':library2')",
+ " implementation \"com.google.dagger:dagger:$dagger_version\"",
+ " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
+ "}")
+ .addSrcFile(
+ "MySubcomponent.java",
+ "package library1;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.Subcomponent;",
+ "import library2.MySubcomponentScope;",
+ "",
+ "@MySubcomponentScope",
+ "@Subcomponent(modules = MySubcomponent.MySubcomponentModule.class)",
+ "public abstract class MySubcomponent {",
+ " public abstract int getScopedInt();",
+ "",
+ " @Module",
+ " public interface MySubcomponentModule {",
+ " @Provides",
+ " @MySubcomponentScope",
+ " static int provideScopedInt() {",
+ " return 0;",
+ " }",
+ " }",
+ "}");
+
+ GradleModule.create(projectDir, "library2")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ " id 'java-library'",
+ "}",
+ "dependencies {",
+ " implementation 'javax.inject:javax.inject:1'",
+ "}")
+ .addSrcFile(
+ "MySubcomponentScope.java",
+ "package library2;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope",
+ "public @interface MySubcomponentScope {}");
+
+ // This plugin is used to print output about bindings that we can assert on in tests.
+ GradleModule.create(projectDir, "spi-plugin")
+ .addBuildFile(
+ "plugins {",
+ " id 'java'",
+ "}",
+ "dependencies {",
+ " implementation \"com.google.dagger:dagger-spi:$dagger_version\"",
+ " implementation 'com.google.auto.service:auto-service-annotations:1.0.1'",
+ " annotationProcessor 'com.google.auto.service:auto-service:1.0.1'",
+ "}")
+ .addSrcFile(
+ "TestBindingGraphPlugin.java",
+ "package spiplugin;",
+ "",
+ "import com.google.auto.service.AutoService;",
+ "import dagger.model.BindingGraph;",
+ "import dagger.spi.BindingGraphPlugin;",
+ "import dagger.spi.DiagnosticReporter;",
+ "",
+ "@AutoService(BindingGraphPlugin.class)",
+ "public class TestBindingGraphPlugin implements BindingGraphPlugin {",
+ " @Override",
+ " public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter"
+ + " diagnosticReporter) {",
+ " bindingGraph.bindings().stream()",
+ " .filter(binding -> binding.scope().isPresent())",
+ " .forEach(binding -> System.out.println(binding + \": SCOPED\"));",
+ " bindingGraph.bindings().stream()",
+ " .filter(binding -> !binding.scope().isPresent())",
+ " .forEach(binding -> System.out.println(binding + \": UNSCOPED\"));",
+ " }",
+ "}");
+
+ return GradleRunner.create().withArguments("--stacktrace", "build").withProjectDir(projectDir);
+ }
+}
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/build.gradle b/javatests/artifacts/dagger/build.gradle
index 7a02482df..89f9efe0b 100644
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/build.gradle
+++ b/javatests/artifacts/dagger/build.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Dagger Authors.
+ * Copyright (C) 2021 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,27 +15,27 @@
*/
buildscript {
- ext {
- kotlin_version = '1.3.61'
- agp_version = "4.2.0-beta04"
- }
- repositories {
- google()
- jcenter()
- mavenLocal()
- }
- dependencies {
- classpath "com.android.tools.build:gradle:$agp_version"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath 'com.google.dagger:hilt-android-gradle-plugin:LOCAL-SNAPSHOT'
- }
+ ext {
+ dagger_version = "LOCAL-SNAPSHOT"
+ kotlin_version = "1.5.32"
+ junit_version = "4.13"
+ truth_version = "1.0.1"
+ }
}
allprojects {
- repositories {
- google()
- jcenter()
- mavenCentral()
- mavenLocal()
+ repositories {
+ mavenCentral()
+ mavenLocal()
+ }
+
+ configurations.all {
+ resolutionStrategy.eachDependency { DependencyResolveDetails details ->
+ if (details.requested.group == 'com.google.dagger'
+ && "$dagger_version" == 'LOCAL-SNAPSHOT') {
+ details.useVersion 'LOCAL-SNAPSHOT'
+ details.because 'LOCAL-SNAPSHOT should act as latest version.'
+ }
}
+ }
}
diff --git a/java/dagger/example/gradle/android/simple/gradle/wrapper/gradle-wrapper.jar b/javatests/artifacts/dagger/gradle/wrapper/gradle-wrapper.jar
index 5c2d1cf01..5c2d1cf01 100644
--- a/java/dagger/example/gradle/android/simple/gradle/wrapper/gradle-wrapper.jar
+++ b/javatests/artifacts/dagger/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/java/dagger/example/gradle/android/simple/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/dagger/gradle/wrapper/gradle-wrapper.properties
index 4d9ca1649..0f80bbf51 100644
--- a/java/dagger/example/gradle/android/simple/gradle/wrapper/gradle-wrapper.properties
+++ b/javatests/artifacts/dagger/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/java/dagger/example/gradle/android/simple/gradlew b/javatests/artifacts/dagger/gradlew
index b0d6d0ab5..b0d6d0ab5 100755
--- a/java/dagger/example/gradle/android/simple/gradlew
+++ b/javatests/artifacts/dagger/gradlew
diff --git a/javatests/artifacts/dagger/simple/build.gradle b/javatests/artifacts/dagger/java-app/build.gradle
index 97c966e50..e709d7db5 100644
--- a/javatests/artifacts/dagger/simple/build.gradle
+++ b/javatests/artifacts/dagger/java-app/build.gradle
@@ -19,19 +19,14 @@ plugins {
id 'application'
}
-repositories {
- mavenCentral()
- mavenLocal()
-}
-
java {
// Make sure the generated source is compatible with Java 7.
sourceCompatibility = JavaVersion.VERSION_1_7
}
dependencies {
- implementation 'com.google.dagger:dagger:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:dagger-compiler:LOCAL-SNAPSHOT'
+ implementation "com.google.dagger:dagger:$dagger_version"
+ annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
}
-mainClassName = 'dagger.simple.SimpleApplication' \ No newline at end of file
+mainClassName = 'app.SimpleApplication' \ No newline at end of file
diff --git a/javatests/artifacts/dagger/simple/src/main/java/dagger/simple/AssistedInjects.java b/javatests/artifacts/dagger/java-app/src/main/java/app/AssistedInjects.java
index eb4946fe3..246c541c4 100644
--- a/javatests/artifacts/dagger/simple/src/main/java/dagger/simple/AssistedInjects.java
+++ b/javatests/artifacts/dagger/java-app/src/main/java/app/AssistedInjects.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package dagger.simple;
+package app;
import dagger.Component;
import dagger.assisted.Assisted;
diff --git a/javatests/artifacts/dagger/simple/src/main/java/dagger/simple/SimpleApplication.java b/javatests/artifacts/dagger/java-app/src/main/java/app/SimpleApplication.java
index f13610101..dfe95ca0f 100644
--- a/javatests/artifacts/dagger/simple/src/main/java/dagger/simple/SimpleApplication.java
+++ b/javatests/artifacts/dagger/java-app/src/main/java/app/SimpleApplication.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package dagger.simple;
+package app;
import dagger.Component;
import dagger.Module;
@@ -44,5 +44,8 @@ public class SimpleApplication {
public static void main(String[] args) {
Foo foo = DaggerSimpleApplication_SimpleComponent.create().foo();
+
+ // Execute other classes
+ AssistedInjects.main(args);
}
}
diff --git a/javatests/artifacts/dagger/kotlin-app/build.gradle b/javatests/artifacts/dagger/kotlin-app/build.gradle
new file mode 100644
index 000000000..2f4f7f3c5
--- /dev/null
+++ b/javatests/artifacts/dagger/kotlin-app/build.gradle
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+plugins {
+ id 'application'
+ id 'org.jetbrains.kotlin.jvm' version "$kotlin_version"
+ id 'org.jetbrains.kotlin.kapt' version "$kotlin_version"
+}
+
+java {
+ // Make sure the generated source is compatible with Java 8.
+ sourceCompatibility = JavaVersion.VERSION_1_8
+}
+
+dependencies {
+ implementation project(path: ':kotlin-app:kotlin-library')
+
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ implementation "com.google.dagger:dagger:$dagger_version"
+ kapt "com.google.dagger:dagger-compiler:$dagger_version"
+
+ // This is testImplementation rather than kaptTest because we're actually
+ // testing the reference to ComponentProcessor.
+ // See https://github.com/google/dagger/issues/2765
+ testImplementation "com.google.dagger:dagger-compiler:$dagger_version"
+ testImplementation "com.google.truth:truth:$truth_version"
+ testImplementation "junit:junit:$junit_version"
+}
+
+application {
+ mainClass = 'app.SimpleApplicationKt'
+} \ No newline at end of file
diff --git a/javatests/artifacts/dagger/kotlin-app/kotlin-library/build.gradle b/javatests/artifacts/dagger/kotlin-app/kotlin-library/build.gradle
new file mode 100644
index 000000000..954bd9f5a
--- /dev/null
+++ b/javatests/artifacts/dagger/kotlin-app/kotlin-library/build.gradle
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+plugins {
+ id 'org.jetbrains.kotlin.jvm'
+ id 'org.jetbrains.kotlin.kapt'
+}
+
+java {
+ // Make sure the generated source is compatible with Java 8.
+ sourceCompatibility = JavaVersion.VERSION_1_8
+}
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ implementation "com.google.dagger:dagger:$dagger_version"
+ kapt "com.google.dagger:dagger-compiler:$dagger_version"
+
+ // This is testImplementation rather than kaptTest because we're actually
+ // testing the reference to ComponentProcessor.
+ // See https://github.com/google/dagger/issues/2765
+ testImplementation "com.google.dagger:dagger-compiler:$dagger_version"
+ testImplementation "com.google.truth:truth:$truth_version"
+ testImplementation "junit:junit:$junit_version"
+}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/ModelModule.java b/javatests/artifacts/dagger/kotlin-app/kotlin-library/src/main/kotlin/library/MySubcomponent.kt
index d933c813e..70e9d3b70 100644
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/ModelModule.java
+++ b/javatests/artifacts/dagger/kotlin-app/kotlin-library/src/main/kotlin/library/MySubcomponent.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Dagger Authors.
+ * Copyright (C) 2021 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,23 +14,22 @@
* limitations under the License.
*/
-package dagger.hilt.android.example.gradle.simple;
+package library
-import static android.os.Build.MODEL;
+import dagger.BindsInstance
+import dagger.Subcomponent
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.components.SingletonComponent;
-
-@Module
-@InstallIn(SingletonComponent.class)
-final class ModelModule {
- @Provides
- @Model
- static String provideModel() {
- return MODEL;
- }
+/**
+ * This subcomponent reproduces a regression in https://github.com/google/dagger/issues/2997.
+ */
+@Subcomponent
+abstract class MySubcomponent {
+ abstract fun instance(): InstanceType
- private ModelModule() {}
+ @Subcomponent.Factory
+ interface Factory {
+ fun create(@BindsInstance instance: InstanceType): MySubcomponent
+ }
}
+
+class InstanceType
diff --git a/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/AssistedInjects.kt b/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/AssistedInjects.kt
new file mode 100644
index 000000000..0fe65fd4f
--- /dev/null
+++ b/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/AssistedInjects.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app
+
+import dagger.Component
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import javax.inject.Inject
+
+// This is a regression test for https://github.com/google/dagger/issues/2309
+/** A simple, skeletal application that defines an assisted inject binding. */
+class AssistedInjects {
+ @Component
+ interface MyComponent {
+ fun fooFactory(): FooFactory
+
+ fun parameterizedFooFactory(): ParameterizedFooFactory<Bar, String>
+ }
+
+ class Bar @Inject constructor()
+
+ class Foo @AssistedInject constructor(val bar: Bar, @Assisted val str: String)
+
+ @AssistedFactory
+ interface FooFactory {
+ fun create(str: String): Foo
+ }
+
+ class ParameterizedFoo<T1, T2> @AssistedInject constructor(val t1: T1, @Assisted val t2: T2)
+
+ @AssistedFactory
+ interface ParameterizedFooFactory<T1, T2> {
+ fun create(t2: T2): ParameterizedFoo<T1, T2>
+ }
+
+ companion object {
+ // Called from SimpleApplication.main()
+ fun main() {
+ val foo: Foo = DaggerAssistedInjects_MyComponent.create().fooFactory().create("")
+
+ val parameterizedFoo: ParameterizedFoo<Bar, String> =
+ DaggerAssistedInjects_MyComponent.create().parameterizedFooFactory().create("")
+ }
+ }
+}
diff --git a/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/SimpleApplication.kt b/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/SimpleApplication.kt
new file mode 100644
index 000000000..599d7039d
--- /dev/null
+++ b/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/SimpleApplication.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app
+
+import dagger.Component
+import dagger.Module
+import dagger.Provides
+import javax.inject.Inject
+import javax.inject.Singleton
+import library.MySubcomponent
+
+/** A simple, skeletal application that defines a simple component. */
+class SimpleApplication {
+ class Foo @Inject constructor()
+
+ @Module
+ object SimpleModule {
+ @Provides
+ fun provideFoo(): Foo {
+ return Foo()
+ }
+ }
+
+ @Singleton
+ @Component(modules = [SimpleModule::class])
+ interface SimpleComponent {
+ fun foo(): Foo
+
+ // Reproduces a regression in https://github.com/google/dagger/issues/2997.
+ fun mySubcomponentFactory(): MySubcomponent.Factory
+ }
+
+ companion object {
+ fun main() {
+ val foo: Foo = DaggerSimpleApplication_SimpleComponent.create().foo()
+ }
+ }
+}
+
+fun main() {
+ SimpleApplication.main()
+ AssistedInjects.main()
+}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleGreeter.java b/javatests/artifacts/dagger/kotlin-app/src/test/kotlin/app/ComponentProcessorBuildTest.kt
index 6c35600b3..1b050f82d 100644
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleGreeter.java
+++ b/javatests/artifacts/dagger/kotlin-app/src/test/kotlin/app/ComponentProcessorBuildTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Dagger Authors.
+ * Copyright (C) 2021 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,23 +14,23 @@
* limitations under the License.
*/
-package dagger.hilt.android.example.gradle.simple;
+package app
-import android.app.Activity;
-import javax.inject.Inject;
+import com.google.common.truth.Truth.assertThat
+import dagger.internal.codegen.ComponentProcessor
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
-/** A class that returns a greeting for {@link SimpleActivity}. */
-final class SimpleGreeter {
- private final Activity activity;
- private final String userName;
+@RunWith(JUnit4::class)
+class ComponentProcessorBuildTest {
- @Inject
- SimpleGreeter(Activity activity, @UserName String userName) {
- this.activity = activity;
- this.userName = userName;
- }
+ // This is a regression test for https://github.com/google/dagger/issues/2765
+ // to make sure ComponentProcessor builds in kotlin.
+ @Test
+ fun testComponentProcessor() {
+ val processor = ComponentProcessor.forTesting()
- public String greet() {
- return activity.getResources().getString(R.string.welcome, userName);
+ assertThat(processor).isNotNull()
}
}
diff --git a/javatests/artifacts/dagger/settings.gradle b/javatests/artifacts/dagger/settings.gradle
new file mode 100644
index 000000000..6ba1baebe
--- /dev/null
+++ b/javatests/artifacts/dagger/settings.gradle
@@ -0,0 +1,8 @@
+rootProject.name = 'Dagger Apps'
+include ':build-tests'
+include ':java-app'
+include ':kotlin-app'
+include ':kotlin-app:kotlin-library'
+include ':transitive-annotation-app'
+include ':transitive-annotation-app:library1'
+include ':transitive-annotation-app:library2'
diff --git a/javatests/artifacts/dagger/simple/gradle/wrapper/gradle-wrapper.jar b/javatests/artifacts/dagger/simple/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 5c2d1cf01..000000000
--- a/javatests/artifacts/dagger/simple/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/javatests/artifacts/dagger/simple/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/dagger/simple/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 4d9ca1649..000000000
--- a/javatests/artifacts/dagger/simple/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/javatests/artifacts/dagger/simple/gradlew b/javatests/artifacts/dagger/simple/gradlew
deleted file mode 100755
index b0d6d0ab5..000000000
--- a/javatests/artifacts/dagger/simple/gradlew
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/usr/bin/env sh
-
-#
-# Copyright 2015 the original author or authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-##############################################################################
-##
-## Gradle start up script for UN*X
-##
-##############################################################################
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn () {
- echo "$*"
-}
-
-die () {
- echo
- echo "$*"
- echo
- exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
- else
- JAVACMD="$JAVA_HOME/bin/java"
- fi
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
- fi
- i=$((i+1))
- done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
-fi
-
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=$(save "$@")
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
- cd "$(dirname "$0")"
-fi
-
-exec "$JAVACMD" "$@"
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/build.gradle b/javatests/artifacts/dagger/transitive-annotation-app/build.gradle
new file mode 100644
index 000000000..22933a4a3
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/build.gradle
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+plugins {
+ id 'java'
+ id 'application'
+}
+
+java {
+ // Make sure the generated source is compatible with Java 7.
+ sourceCompatibility = JavaVersion.VERSION_1_7
+}
+
+dependencies {
+ implementation project(":transitive-annotation-app:library1")
+ implementation "com.google.dagger:dagger:$dagger_version"
+ annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
+
+ testImplementation "junit:junit:$junit_version"
+ testImplementation "com.google.truth:truth:$truth_version"
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/build.gradle b/javatests/artifacts/dagger/transitive-annotation-app/library1/build.gradle
new file mode 100644
index 000000000..2126f0923
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/build.gradle
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+plugins {
+ id 'java'
+ id 'java-library'
+}
+
+java {
+ // Make sure the generated source is compatible with Java 7.
+ sourceCompatibility = JavaVersion.VERSION_1_7
+}
+
+dependencies {
+ implementation project(":transitive-annotation-app:library2")
+ implementation "com.google.dagger:dagger:$dagger_version"
+ annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/AssistedFoo.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/AssistedFoo.java
new file mode 100644
index 000000000..8377d1c24
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/AssistedFoo.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1;
+
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import javax.inject.Inject;
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/**
+ * A class used to test that Dagger won't fail when non-dagger related annotations cannot be
+ * resolved.
+ *
+ * <p>During the compilation of {@code :app}, {@link MyTransitiveAnnotation} will no longer be on
+ * the classpath. In most cases, Dagger shouldn't care that the annotation isn't on the classpath
+ */
+@MyTransitiveAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+public final class AssistedFoo extends FooBase {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerField;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ @MyQualifier
+ Dep daggerField;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ AssistedFoo(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ super(nonDaggerParameter);
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @AssistedInject
+ AssistedFoo(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Assisted
+ int i,
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @MyQualifier
+ Dep dep) {
+ super(dep);
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ void daggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @MyQualifier
+ Dep dep) {}
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @AssistedFactory
+ public interface Factory {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ AssistedFoo create(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ int i);
+ }
+}
diff --git a/java/dagger/internal/MemoizedSentinel.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/Dep.java
index dd24dcd85..fa64e3428 100644
--- a/java/dagger/internal/MemoizedSentinel.java
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/Dep.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Dagger Authors.
+ * Copyright (C) 2022 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-package dagger.internal;
+package library1;
-/** A sentinel used to memoize a scoped binding in a component. */
-public final class MemoizedSentinel {}
+public final class Dep {}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/Foo.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/Foo.java
new file mode 100644
index 000000000..062acbe5a
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/Foo.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/**
+ * A class used to test that Dagger won't fail when non-dagger related annotations cannot be
+ * resolved.
+ *
+ * <p>During the compilation of {@code :app}, {@link MyTransitiveAnnotation} will no longer be on
+ * the classpath. In most cases, Dagger shouldn't care that the annotation isn't on the classpath
+ */
+@Singleton
+@MyTransitiveAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+public final class Foo extends FooBase {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerField;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ @MyQualifier
+ Dep daggerField;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ Foo(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ super(nonDaggerParameter);
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ Foo(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @MyQualifier
+ Dep dep) {
+ super(dep);
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ void daggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @MyQualifier
+ Dep dep) {}
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/FooBase.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/FooBase.java
new file mode 100644
index 000000000..ad113dd91
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/FooBase.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1;
+
+import javax.inject.Inject;
+import library2.MyTransitiveBaseAnnotation;
+import library2.MyTransitiveType;
+
+/** A baseclass for {@link Foo}. */
+@MyTransitiveBaseAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+public class FooBase {
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ int baseNonDaggerField;
+
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ @MyQualifier
+ Dep baseDaggerField;
+
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ FooBase(
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {}
+
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ FooBase(
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @MyQualifier
+ Dep dep) {}
+
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ void baseNonDaggerMethod(
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ int i) {}
+
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ void baseDaggerMethod(
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @MyQualifier
+ Dep dep) {}
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyAnnotation.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyAnnotation.java
new file mode 100644
index 000000000..58ba4e7f5
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyAnnotation.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1;
+
+/** An annotation that is a direct dependency of the app. */
+public @interface MyAnnotation {
+ int value();
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyBaseComponent.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyBaseComponent.java
new file mode 100644
index 000000000..d647f54f6
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyBaseComponent.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1;
+
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/**
+ * A class used to test that Dagger won't fail on unresolvable transitive types used in non-dagger
+ * related elements and annotations.
+ */
+// @MyTransitiveAnnotation: Not yet supported
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+public abstract class MyBaseComponent {
+ @MyQualifier
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MyComponentModule.UnscopedQualifiedBindsType unscopedQualifiedBindsTypeBase();
+
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MyComponentModule.UnscopedUnqualifiedBindsType unscopedUnqualifiedBindsTypeBase();
+
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract void injectFooBase(
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE) @MyOtherAnnotation(MyTransitiveType.class) Foo binding);
+
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract static class Factory {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MyBaseComponent create(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyComponentModule myComponentModule,
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyComponentDependency myComponentDependency);
+
+ // Non-dagger factory code
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+ }
+
+ // Non-dagger code
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyComponentDependency.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyComponentDependency.java
new file mode 100644
index 000000000..bb17021b7
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyComponentDependency.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1;
+
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/**
+ * A class used to test that Dagger won't fail on unresolvable transitive types used in non-dagger
+ * related elements and annotations.
+ */
+// @MyTransitiveAnnotation: Not yet supported
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+public final class MyComponentDependency {
+ private final MyComponentDependencyBinding qualifiedMyComponentDependencyBinding =
+ new MyComponentDependencyBinding();
+ private final MyComponentDependencyBinding unqualifiedMyComponentDependencyBinding =
+ new MyComponentDependencyBinding();
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyComponentDependency() {}
+
+ @MyQualifier
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyComponentDependencyBinding qualifiedMyComponentDependencyBinding() {
+ return qualifiedMyComponentDependencyBinding;
+ }
+
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyComponentDependencyBinding unqualifiedMyComponentDependencyBinding() {
+ return unqualifiedMyComponentDependencyBinding;
+ }
+
+ // Non-dagger code
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyComponentDependencyBinding.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyComponentDependencyBinding.java
new file mode 100644
index 000000000..c5d6bc917
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyComponentDependencyBinding.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1;
+
+/** Used as a binding in {@link MyComponentDependency}. */
+public final class MyComponentDependencyBinding {}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyComponentModule.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyComponentModule.java
new file mode 100644
index 000000000..2c7a36334
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyComponentModule.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.Provides;
+import javax.inject.Singleton;
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/**
+ * A class used to test that Dagger won't fail when non-dagger related annotations cannot be
+ * resolved.
+ *
+ * <p>During the compilation of {@code :app}, {@link MyTransitiveAnnotation} will no longer be on
+ * the classpath. In most cases, Dagger shouldn't care that the annotation isn't on the classpath
+ */
+@MyTransitiveAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+@Module(includes = {MyComponentModule.MyAbstractModule.class})
+public final class MyComponentModule {
+ // Define bindings for each configuration: Scoped/Unscoped, Qualified/UnQualified, Provides/Binds
+ public static class ScopedQualifiedBindsType {}
+ public static final class ScopedQualifiedProvidesType extends ScopedQualifiedBindsType {}
+ public static class ScopedUnqualifiedBindsType {}
+ public static final class ScopedUnqualifiedProvidesType extends ScopedUnqualifiedBindsType {}
+ public static class UnscopedQualifiedBindsType {}
+ public static final class UnscopedQualifiedProvidesType extends UnscopedQualifiedBindsType {}
+ public static class UnscopedUnqualifiedBindsType {}
+ public static final class UnscopedUnqualifiedProvidesType extends UnscopedUnqualifiedBindsType {}
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Provides
+ @Singleton
+ @MyQualifier
+ ScopedQualifiedProvidesType scopedQualifiedProvidesType(
+ @MyQualifier
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ Dep dep) {
+ return new ScopedQualifiedProvidesType();
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Provides
+ @Singleton
+ ScopedUnqualifiedProvidesType scopedUnqualifiedProvidesType(
+ @MyQualifier
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ Dep dep) {
+ return new ScopedUnqualifiedProvidesType();
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Provides
+ @MyQualifier
+ UnscopedQualifiedProvidesType unscopedQualifiedProvidesType(
+ @MyQualifier
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ Dep dep) {
+ return new UnscopedQualifiedProvidesType();
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Provides
+ UnscopedUnqualifiedProvidesType unscopedUnqualifiedProvidesType(
+ @MyQualifier
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ Dep dep) {
+ return new UnscopedUnqualifiedProvidesType();
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Module
+ interface MyAbstractModule {
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Binds
+ @Singleton
+ @MyQualifier
+ ScopedQualifiedBindsType scopedQualifiedBindsType(
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyQualifier
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ ScopedQualifiedProvidesType scopedQualifiedProvidesType);
+
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Binds
+ @Singleton
+ ScopedUnqualifiedBindsType scopedUnqualifiedBindsType(
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE) @MyOtherAnnotation(MyTransitiveType.class)
+ ScopedUnqualifiedProvidesType scopedUnqualifiedProvidesType);
+
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Binds
+ @MyQualifier
+ UnscopedQualifiedBindsType unscopedQualifiedBindsType(
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyQualifier
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ UnscopedQualifiedProvidesType unscopedQualifiedProvidesType);
+
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Binds
+ UnscopedUnqualifiedBindsType unscopedUnqualifiedBindsType(
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE) @MyOtherAnnotation(MyTransitiveType.class)
+ UnscopedUnqualifiedProvidesType unscopedUnqualifiedProvidesType);
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Provides
+ @MyQualifier
+ Dep provideQualifiedDep() {
+ return new Dep();
+ }
+
+ // Provide an unqualified Dep to ensure that if we accidentally drop the qualifier
+ // we'll get a runtime exception.
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Provides
+ Dep provideDep() {
+ throw new UnsupportedOperationException();
+ }
+
+ // Non-Dagger elements
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ private Dep dep;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ private MyTransitiveType nonDaggerField;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyComponentModule(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ Dep dep) {
+ this.dep = dep;
+ this.nonDaggerField = new MyTransitiveType();
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ static MyTransitiveType nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyOtherAnnotation.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyOtherAnnotation.java
new file mode 100644
index 000000000..c1cb6ae95
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyOtherAnnotation.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1;
+
+/** An annotation that is a direct dependency of the app. */
+public @interface MyOtherAnnotation {
+ Class<?> value();
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyQualifier.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyQualifier.java
new file mode 100644
index 000000000..c08ac9864
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MyQualifier.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+public @interface MyQualifier {}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentBinding.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentBinding.java
new file mode 100644
index 000000000..61bb3f7b3
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentBinding.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1;
+
+/** A simple binding that needs to be passed in when creating this component. */
+public final class MySubcomponentBinding {}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentModule.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentModule.java
new file mode 100644
index 000000000..da8de7bea
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentModule.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1;
+
+import dagger.Module;
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/** A simple module that needs to be passed in when creating this component. */
+@MyTransitiveAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+@Module
+public final class MySubcomponentModule {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MySubcomponentModule(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ int i) {}
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentScope.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentScope.java
new file mode 100644
index 000000000..e76b0b658
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentScope.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1;
+
+import javax.inject.Scope;
+
+/** A scope for {@link MySubcomponent}. */
+@Scope
+public @interface MySubcomponentScope {}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentWithBuilder.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentWithBuilder.java
new file mode 100644
index 000000000..456eb2539
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentWithBuilder.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/**
+ * A class used to test that Dagger won't fail when non-dagger related annotations cannot be
+ * resolved.
+ *
+ * <p>During the compilation of {@code :app}, {@link MyTransitiveAnnotation} will no longer be on
+ * the classpath. In most cases, Dagger shouldn't care that the annotation isn't on the classpath
+ */
+// @MyTransitiveAnnotation: Not yet supported
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+@MySubcomponentScope
+@Subcomponent(modules = MySubcomponentModule.class)
+public abstract class MySubcomponentWithBuilder {
+ @MyQualifier
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MySubcomponentBinding qualifiedMySubcomponentBinding();
+
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MySubcomponentBinding unqualifiedMySubcomponentBinding();
+
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract void injectFoo(
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE) @MyOtherAnnotation(MyTransitiveType.class) Foo foo);
+
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Subcomponent.Builder
+ public abstract static class Builder {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract Builder mySubcomponentModule(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MySubcomponentModule mySubcomponentModule);
+
+ @BindsInstance
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract Builder qualifiedMySubcomponentBinding(
+ @MyQualifier
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MySubcomponentBinding subcomponentBinding);
+
+ @BindsInstance
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract Builder unqualifiedMySubcomponentBinding(
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE) @MyOtherAnnotation(MyTransitiveType.class)
+ MySubcomponentBinding subcomponentBinding);
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MySubcomponentWithBuilder build();
+
+ // Non-dagger code
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public String nonDaggerField = "";
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static String nonDaggerStaticField = "";
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public void nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ String str) {}
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static void nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ String str) {}
+ }
+
+ // Non-dagger code
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentWithFactory.java b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentWithFactory.java
new file mode 100644
index 000000000..f3c6f930a
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentWithFactory.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/**
+ * A class used to test that Dagger won't fail when non-dagger related annotations cannot be
+ * resolved.
+ *
+ * <p>During the compilation of {@code :app}, {@link MyTransitiveAnnotation} will no longer be on
+ * the classpath. In most cases, Dagger shouldn't care that the annotation isn't on the classpath
+ */
+// @MyTransitiveAnnotation: Not yet supported
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+@MySubcomponentScope
+@Subcomponent(modules = MySubcomponentModule.class)
+public abstract class MySubcomponentWithFactory {
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyQualifier
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MySubcomponentBinding qualifiedMySubcomponentBinding();
+
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MySubcomponentBinding unqualifiedMySubcomponentBinding();
+
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract void injectFoo(
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE) @MyOtherAnnotation(MyTransitiveType.class) Foo foo);
+
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Subcomponent.Factory
+ public abstract static class Factory {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MySubcomponentWithFactory create(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MySubcomponentModule mySubcomponentModule,
+ @BindsInstance
+ @MyQualifier
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MySubcomponentBinding qualifiedSubcomponentBinding,
+ @BindsInstance
+ // @MyTransitiveAnnotation: Not yet supported
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MySubcomponentBinding unqualifiedSubcomponentBinding);
+
+ // Non-dagger code
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+ }
+
+ // Non-dagger code
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library2/build.gradle b/javatests/artifacts/dagger/transitive-annotation-app/library2/build.gradle
new file mode 100644
index 000000000..b4d45e475
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library2/build.gradle
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+plugins {
+ id 'java'
+ id 'java-library'
+}
+
+java {
+ // Make sure the generated source is compatible with Java 7.
+ sourceCompatibility = JavaVersion.VERSION_1_7
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveAnnotation.java b/javatests/artifacts/dagger/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveAnnotation.java
new file mode 100644
index 000000000..5f1f4bc8f
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveAnnotation.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library2;
+
+/** A simple annotation that is a transitive dependency of the app. */
+public @interface MyTransitiveAnnotation {}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveBaseAnnotation.java b/javatests/artifacts/dagger/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveBaseAnnotation.java
new file mode 100644
index 000000000..dcc6739da
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveBaseAnnotation.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library2;
+
+/** A simple annotation that is a transitive dependency of the app. */
+public @interface MyTransitiveBaseAnnotation {}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveType.java b/javatests/artifacts/dagger/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveType.java
new file mode 100644
index 000000000..c6ecd5d93
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveType.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library2;
+
+
+/** A class that is a transitive dependency of the app. */
+public final class MyTransitiveType {
+ public static final int VALUE = 3;
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/src/main/java/app/MyComponent.java b/javatests/artifacts/dagger/transitive-annotation-app/src/main/java/app/MyComponent.java
new file mode 100644
index 000000000..ee55d3a48
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/src/main/java/app/MyComponent.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app;
+
+import dagger.Component;
+import javax.inject.Singleton;
+import library1.AssistedFoo;
+import library1.Foo;
+import library1.MyBaseComponent;
+import library1.MyComponentDependency;
+import library1.MyComponentDependencyBinding;
+import library1.MyComponentModule;
+import library1.MyQualifier;
+import library1.MySubcomponentWithBuilder;
+import library1.MySubcomponentWithFactory;
+
+@Singleton
+@Component(dependencies = MyComponentDependency.class, modules = MyComponentModule.class)
+abstract class MyComponent extends MyBaseComponent {
+ abstract Foo foo();
+
+ abstract AssistedFoo.Factory assistedFooFactory();
+
+ @MyQualifier
+ abstract MyComponentModule.ScopedQualifiedBindsType scopedQualifiedBindsType();
+
+ abstract MyComponentModule.ScopedUnqualifiedBindsType scopedUnqualifiedBindsType();
+
+ @MyQualifier
+ abstract MyComponentModule.UnscopedQualifiedBindsType unscopedQualifiedBindsType();
+
+ abstract MyComponentModule.UnscopedUnqualifiedBindsType unscopedUnqualifiedBindsType();
+
+ @MyQualifier
+ abstract MyComponentModule.ScopedQualifiedProvidesType scopedQualifiedProvidesType();
+
+ abstract MyComponentModule.ScopedUnqualifiedProvidesType scopedUnqualifiedProvidesType();
+
+ @MyQualifier
+ abstract MyComponentModule.UnscopedQualifiedProvidesType unscopedQualifiedProvidesType();
+
+ abstract MyComponentModule.UnscopedUnqualifiedProvidesType unscopedUnqualifiedProvidesType();
+
+ abstract MySubcomponentWithFactory.Factory mySubcomponentWithFactory();
+
+ abstract MySubcomponentWithBuilder.Builder mySubcomponentWithBuilder();
+
+ @MyQualifier
+ abstract MyComponentDependencyBinding qualifiedMyComponentDependencyBinding();
+
+ abstract MyComponentDependencyBinding unqualifiedMyComponentDependencyBinding();
+
+ @Component.Factory
+ abstract static class Factory extends MyBaseComponent.Factory {
+ public abstract MyComponent create(
+ MyComponentModule myComponentModule,
+ MyComponentDependency myComponentDependency);
+ }
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/src/test/java/app/MyComponentTest.java b/javatests/artifacts/dagger/transitive-annotation-app/src/test/java/app/MyComponentTest.java
new file mode 100644
index 000000000..438d5db60
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/src/test/java/app/MyComponentTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import library1.Dep;
+import library1.MyComponentDependency;
+import library1.MyComponentModule;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class MyComponentTest {
+ private MyComponent component;
+
+ @Before
+ public void setup() {
+ component = DaggerMyComponent.factory()
+ .create(new MyComponentModule(new Dep()), new MyComponentDependency());
+ }
+
+ @Test
+ public void testFooIsScoped() {
+ assertThat(component.foo()).isEqualTo(component.foo());
+ }
+
+ @Test
+ public void testAssistedFoo() {
+ assertThat(component.assistedFooFactory().create(5)).isNotNull();
+ }
+
+ @Test
+ public void testScopedQualifiedBindsTypeIsScoped() {
+ assertThat(component.scopedQualifiedBindsType())
+ .isEqualTo(component.scopedQualifiedBindsType());
+ }
+
+ @Test
+ public void testScopedUnqualifiedBindsTypeIsScoped() {
+ assertThat(component.scopedUnqualifiedBindsType())
+ .isEqualTo(component.scopedUnqualifiedBindsType());
+ }
+
+ @Test
+ public void testUnscopedQualifiedBindsTypeIsNotScoped() {
+ assertThat(component.unscopedQualifiedBindsType())
+ .isNotEqualTo(component.unscopedQualifiedBindsType());
+ }
+
+ @Test
+ public void testUnscopedUnqualifiedBindsTypeIsNotScoped() {
+ assertThat(component.unscopedUnqualifiedBindsType())
+ .isNotEqualTo(component.unscopedUnqualifiedBindsType());
+ }
+
+ @Test
+ public void testScopedQualifiedProvidesTypeIsScoped() {
+ assertThat(component.scopedQualifiedProvidesType())
+ .isEqualTo(component.scopedQualifiedProvidesType());
+ }
+
+ @Test
+ public void testScopedUnqualifiedProvidesTypeIsScoped() {
+ assertThat(component.scopedUnqualifiedProvidesType())
+ .isEqualTo(component.scopedUnqualifiedProvidesType());
+ }
+
+ @Test
+ public void testUnscopedQualifiedProvidesTypeIsNotScoped() {
+ assertThat(component.unscopedQualifiedProvidesType())
+ .isNotEqualTo(component.unscopedQualifiedProvidesType());
+ }
+
+ @Test
+ public void testUnscopedUnqualifiedProvidesTypeIsNotScoped() {
+ assertThat(component.unscopedUnqualifiedProvidesType())
+ .isNotEqualTo(component.unscopedUnqualifiedProvidesType());
+ }
+
+ @Test
+ public void testMyComponentDependencyBinding() {
+ assertThat(component.qualifiedMyComponentDependencyBinding())
+ .isNotEqualTo(component.unqualifiedMyComponentDependencyBinding());
+ }
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/src/test/java/app/MySubcomponentWithBuilderTest.java b/javatests/artifacts/dagger/transitive-annotation-app/src/test/java/app/MySubcomponentWithBuilderTest.java
new file mode 100644
index 000000000..3db241b43
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/src/test/java/app/MySubcomponentWithBuilderTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import library1.Dep;
+import library1.MyComponentDependency;
+import library1.MyComponentModule;
+import library1.MySubcomponentBinding;
+import library1.MySubcomponentModule;
+import library1.MySubcomponentWithBuilder;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class MySubcomponentWithBuilderTest {
+ private MySubcomponentWithBuilder subcomponentWithBuilder;
+
+ @Before
+ public void setup() {
+ subcomponentWithBuilder =
+ DaggerMyComponent.factory()
+ .create(new MyComponentModule(new Dep()), new MyComponentDependency())
+ .mySubcomponentWithBuilder()
+ .mySubcomponentModule(new MySubcomponentModule(3))
+ .qualifiedMySubcomponentBinding(new MySubcomponentBinding())
+ .unqualifiedMySubcomponentBinding(new MySubcomponentBinding())
+ .build();
+ }
+
+ // Test that the qualified and unqualified bindings are two separate objects
+ @Test
+ public void testMySubcomponentBinding() {
+ assertThat(subcomponentWithBuilder.qualifiedMySubcomponentBinding())
+ .isNotEqualTo(subcomponentWithBuilder.unqualifiedMySubcomponentBinding());
+ }
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/src/test/java/app/MySubcomponentWithFactoryTest.java b/javatests/artifacts/dagger/transitive-annotation-app/src/test/java/app/MySubcomponentWithFactoryTest.java
new file mode 100644
index 000000000..a45dcc75f
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-app/src/test/java/app/MySubcomponentWithFactoryTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import library1.Dep;
+import library1.MyComponentDependency;
+import library1.MyComponentModule;
+import library1.MySubcomponentBinding;
+import library1.MySubcomponentModule;
+import library1.MySubcomponentWithFactory;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class MySubcomponentWithFactoryTest {
+ private MySubcomponentWithFactory subcomponentWithFactory;
+
+ @Before
+ public void setup() {
+ subcomponentWithFactory =
+ DaggerMyComponent.factory()
+ .create(new MyComponentModule(new Dep()), new MyComponentDependency())
+ .mySubcomponentWithFactory()
+ .create(
+ new MySubcomponentModule(1),
+ new MySubcomponentBinding(),
+ new MySubcomponentBinding());
+ }
+
+ // Test that the qualified and unqualified bindings are two separate objects
+ @Test
+ public void testMySubcomponentBinding() {
+ assertThat(subcomponentWithFactory.qualifiedMySubcomponentBinding())
+ .isNotEqualTo(subcomponentWithFactory.unqualifiedMySubcomponentBinding());
+ }
+}
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/build.gradle b/javatests/artifacts/hilt-android/gradleConfigCache/app/build.gradle
deleted file mode 100644
index 4f21d0a38..000000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/build.gradle
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-kapt'
-apply plugin: 'dagger.hilt.android.plugin'
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- applicationId "dagger.hilt.android.gradleConfigCache"
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "dagger.hilt.android.gradleConfigCache.TestRunner"
- }
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
- kotlinOptions {
- jvmTarget = '1.8'
- }
- lintOptions {
- checkReleaseBuilds = false
- }
- testOptions {
- unitTests.includeAndroidResources = true
- }
-}
-
-hilt {
- enableTransformForLocalTests = true
- enableExperimentalClasspathAggregation = true
-}
-
-dependencies {
- implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
- implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation 'androidx.activity:activity-ktx:1.1.0'
- implementation 'androidx.multidex:multidex:2.0.0'
- implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- kapt 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
-
- testImplementation 'junit:junit:4.13'
- testImplementation 'androidx.test.ext:junit:1.1.2'
- testImplementation 'androidx.test:runner:1.3.0'
- testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
- testImplementation 'com.google.dagger:hilt-android-testing:LOCAL-SNAPSHOT'
- kaptTest 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
-
- androidTestImplementation 'androidx.test.ext:junit:1.1.2'
- androidTestImplementation 'androidx.test:runner:1.3.0'
- androidTestImplementation 'com.google.dagger:hilt-android-testing:LOCAL-SNAPSHOT'
- kaptAndroidTest 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
-}
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/androidTest/java/dagger/hilt/android/gradleConfigCache/EmulatorTest.kt b/javatests/artifacts/hilt-android/gradleConfigCache/app/src/androidTest/java/dagger/hilt/android/gradleConfigCache/EmulatorTest.kt
deleted file mode 100644
index 9099db42e..000000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/androidTest/java/dagger/hilt/android/gradleConfigCache/EmulatorTest.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.gradleConfigCache
-
-import androidx.test.core.app.ActivityScenario
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import dagger.hilt.android.testing.HiltAndroidRule
-import dagger.hilt.android.testing.HiltAndroidTest
-import org.junit.Assert.assertNotNull
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@HiltAndroidTest
-@RunWith(AndroidJUnit4::class)
-class EmulatorTest {
-
- @get:Rule
- val rule = HiltAndroidRule(this)
-
- @Test
- fun testFooInjected() {
- ActivityScenario.launch(MainActivity::class.java).use {
- it.onActivity { activity ->
- assertNotNull(activity.foo)
- }
- }
- }
-}
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/androidTest/java/dagger/hilt/android/gradleConfigCache/TestRunner.kt b/javatests/artifacts/hilt-android/gradleConfigCache/app/src/androidTest/java/dagger/hilt/android/gradleConfigCache/TestRunner.kt
deleted file mode 100644
index 9fce7cdb0..000000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/androidTest/java/dagger/hilt/android/gradleConfigCache/TestRunner.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.gradleConfigCache
-
-import android.app.Application
-import android.content.Context
-import androidx.test.runner.AndroidJUnitRunner
-import dagger.hilt.android.testing.HiltTestApplication
-
-class TestRunner : AndroidJUnitRunner() {
- override fun newApplication(cl: ClassLoader, appName: String, context: Context): Application {
- return super.newApplication(cl, HiltTestApplication::class.java.name, context)
- }
-}
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/AndroidManifest.xml b/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/AndroidManifest.xml
deleted file mode 100644
index ce1fb7129..000000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Dagger Authors.
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.gradleConfigCache">
-
- <application
- android:name=".App"
- android:allowBackup="true"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/Theme.AppCompat.Light">
- <activity android:name=".MainActivity" android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/Foo.kt b/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/Foo.kt
deleted file mode 100644
index 969e183eb..000000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/Foo.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-package dagger.hilt.android.gradleConfigCache
-
-import javax.inject.Inject
-
-class Foo @Inject constructor()
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/test/java/dagger/hilt/android/gradleConfigCache/LocalTest.kt b/javatests/artifacts/hilt-android/gradleConfigCache/app/src/test/java/dagger/hilt/android/gradleConfigCache/LocalTest.kt
deleted file mode 100644
index 527d88739..000000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/test/java/dagger/hilt/android/gradleConfigCache/LocalTest.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.gradleConfigCache
-
-import androidx.test.core.app.ActivityScenario
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import dagger.hilt.android.testing.HiltAndroidRule
-import dagger.hilt.android.testing.HiltAndroidTest
-import dagger.hilt.android.testing.HiltTestApplication
-import org.junit.Assert.assertNotNull
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.robolectric.annotation.Config
-
-@HiltAndroidTest
-@RunWith(AndroidJUnit4::class)
-@Config(application = HiltTestApplication::class)
-class LocalTest {
-
- @get:Rule
- val rule = HiltAndroidRule(this)
-
- @Test
- fun testFooInjected() {
- ActivityScenario.launch(MainActivity::class.java).use {
- it.onActivity { activity ->
- assertNotNull(activity.foo)
- }
- }
- }
-}
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/build.gradle b/javatests/artifacts/hilt-android/gradleConfigCache/build.gradle
deleted file mode 100644
index de0566c5d..000000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/build.gradle
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-buildscript {
- ext {
- kotlin_version = '1.4.20'
- agp_version = "4.2.0-beta04"
- }
- repositories {
- google()
- jcenter()
- mavenLocal()
- }
- dependencies {
- classpath "com.android.tools.build:gradle:$agp_version"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath 'com.google.dagger:hilt-android-gradle-plugin:LOCAL-SNAPSHOT'
- }
-}
-
-allprojects {
- repositories {
- google()
- jcenter()
- mavenCentral()
- mavenLocal()
- }
- // TODO(bcorso): Consider organizing all projects under a single project
- // that share a build.gradle configuration to reduce the copy-paste.
- // Local tests: Adds logs for individual local tests
- tasks.withType(Test) {
- testLogging {
- exceptionFormat "full"
- showCauses true
- showExceptions true
- showStackTraces true
- showStandardStreams true
- events = ["passed", "skipped", "failed", "standardOut", "standardError"]
- }
- }
-}
-
-// Instrumentation tests: Combines test reports for all modules
-apply plugin: 'android-reporting' \ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/gradle.properties b/javatests/artifacts/hilt-android/gradleConfigCache/gradle.properties
deleted file mode 100644
index 1813493a2..000000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/gradle.properties
+++ /dev/null
@@ -1,8 +0,0 @@
-android.useAndroidX=true
-android.enableJetifier=true
-
-# Error out if an issue is found that disallows the configuration cache.
-# These options along with this app being built in presubmit helps us cache
-# changes that would cause config cache to be disabled via the HiltGradlePlugin.
-org.gradle.unsafe.configuration-cache=ERROR
-org.gradle.unsafe.configuration-cache.max-problems=0
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/gradle/wrapper/gradle-wrapper.jar b/javatests/artifacts/hilt-android/gradleConfigCache/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 62d4c0535..000000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/hilt-android/gradleConfigCache/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 4d9ca1649..000000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/gradlew b/javatests/artifacts/hilt-android/gradleConfigCache/gradlew
deleted file mode 100755
index fbd7c5158..000000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/gradlew
+++ /dev/null
@@ -1,185 +0,0 @@
-#!/usr/bin/env sh
-
-#
-# Copyright 2015 the original author or authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-##############################################################################
-##
-## Gradle start up script for UN*X
-##
-##############################################################################
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn () {
- echo "$*"
-}
-
-die () {
- echo
- echo "$*"
- echo
- exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
- else
- JAVACMD="$JAVA_HOME/bin/java"
- fi
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
- fi
- i=`expr $i + 1`
- done
- case $i in
- 0) set -- ;;
- 1) set -- "$args0" ;;
- 2) set -- "$args0" "$args1" ;;
- 3) set -- "$args0" "$args1" "$args2" ;;
- 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
-fi
-
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=`save "$@"`
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-
-exec "$JAVACMD" "$@"
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/gradlew.bat b/javatests/artifacts/hilt-android/gradleConfigCache/gradlew.bat
deleted file mode 100644
index a9f778a7a..000000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/gradlew.bat
+++ /dev/null
@@ -1,104 +0,0 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/settings.gradle b/javatests/artifacts/hilt-android/gradleConfigCache/settings.gradle
deleted file mode 100644
index d0d5fee1d..000000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/settings.gradle
+++ /dev/null
@@ -1,2 +0,0 @@
-rootProject.name='Gradle Configuration Cache App'
-include ':app'
diff --git a/java/dagger/hilt/android/example/gradle/simple/feature/build.gradle b/javatests/artifacts/hilt-android/pluginMarker/app/build.gradle
index 462aefc1e..b288628be 100644
--- a/java/dagger/hilt/android/example/gradle/simple/feature/build.gradle
+++ b/javatests/artifacts/hilt-android/pluginMarker/app/build.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Dagger Authors.
+ * Copyright (C) 2022 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,37 +14,28 @@
* limitations under the License.
*/
-apply plugin: 'com.android.library'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-kapt'
-apply plugin: 'dagger.hilt.android.plugin'
+plugins {
+ id 'com.android.application' version '7.0.0'
+ id 'com.google.dagger.hilt.android' version 'LOCAL-SNAPSHOT'
+}
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
defaultConfig {
- minSdkVersion 15
+ applicationId "dagger.hilt.android.simple"
+ minSdkVersion 21
targetSdkVersion 30
- versionCode 1
- versionName "1.0"
}
+
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}
}
-kapt {
- correctErrorTypes true
-}
-
dependencies {
- // This is api instead of implementation since Kotlin modules here consumed
- // by the app need to expose @kotlin.Metadata
- api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
-
- implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- kapt 'com.google.dagger:hilt-android-compiler:LOCAL-SNAPSHOT'
-}
+ annotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
+} \ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/res/layout/activity_main.xml b/javatests/artifacts/hilt-android/pluginMarker/app/src/main/AndroidManifest.xml
index cb5a8df9c..60fb594b9 100644
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/res/layout/activity_main.xml
+++ b/javatests/artifacts/hilt-android/pluginMarker/app/src/main/AndroidManifest.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2020 The Dagger Authors.
+ ~ Copyright (C) 2022 The Dagger Authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,9 +13,6 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/background_light">
-</RelativeLayout>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="dagger.hilt.android.simple">
+</manifest> \ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/pluginMarker/gradle.properties b/javatests/artifacts/hilt-android/pluginMarker/gradle.properties
new file mode 100644
index 000000000..5bac8ac50
--- /dev/null
+++ b/javatests/artifacts/hilt-android/pluginMarker/gradle.properties
@@ -0,0 +1 @@
+android.useAndroidX=true
diff --git a/java/dagger/example/gradle/simple/gradle/wrapper/gradle-wrapper.jar b/javatests/artifacts/hilt-android/pluginMarker/gradle/wrapper/gradle-wrapper.jar
index 5c2d1cf01..5c2d1cf01 100644
--- a/java/dagger/example/gradle/simple/gradle/wrapper/gradle-wrapper.jar
+++ b/javatests/artifacts/hilt-android/pluginMarker/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/java/dagger/example/gradle/simple/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/hilt-android/pluginMarker/gradle/wrapper/gradle-wrapper.properties
index 4d9ca1649..0f80bbf51 100644
--- a/java/dagger/example/gradle/simple/gradle/wrapper/gradle-wrapper.properties
+++ b/javatests/artifacts/hilt-android/pluginMarker/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/java/dagger/example/gradle/simple/gradlew b/javatests/artifacts/hilt-android/pluginMarker/gradlew
index b0d6d0ab5..b0d6d0ab5 100755
--- a/java/dagger/example/gradle/simple/gradlew
+++ b/javatests/artifacts/hilt-android/pluginMarker/gradlew
diff --git a/javatests/artifacts/hilt-android/pluginMarker/settings.gradle b/javatests/artifacts/hilt-android/pluginMarker/settings.gradle
new file mode 100644
index 000000000..f32d22538
--- /dev/null
+++ b/javatests/artifacts/hilt-android/pluginMarker/settings.gradle
@@ -0,0 +1,18 @@
+pluginManagement {
+ repositories {
+ gradlePluginPortal()
+ google()
+ mavenCentral()
+ mavenLocal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ mavenLocal()
+ }
+}
+rootProject.name = "PluginMarkerCheck"
+include ':app' \ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simple/app-java-only/build.gradle b/javatests/artifacts/hilt-android/simple/app-java-only/build.gradle
new file mode 100644
index 000000000..9d17cd917
--- /dev/null
+++ b/javatests/artifacts/hilt-android/simple/app-java-only/build.gradle
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+apply plugin: 'com.android.application'
+apply plugin: 'dagger.hilt.android.plugin'
+
+android {
+ compileSdkVersion 30
+ buildToolsVersion "30.0.2"
+
+ defaultConfig {
+ applicationId "dagger.hilt.android.simple"
+ minSdkVersion 15
+ targetSdkVersion 30
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ compileOptions {
+ sourceCompatibility 1.8
+ targetCompatibility 1.8
+ }
+ testOptions {
+ unitTests.includeAndroidResources = true
+ }
+ lintOptions {
+ checkReleaseBuilds = false
+ }
+}
+
+hilt {
+ enableTransformForLocalTests = true
+}
+
+configurations.all {
+ resolutionStrategy.eachDependency { DependencyResolveDetails details ->
+ if ("$dagger_version" == 'LOCAL-SNAPSHOT'
+ && details.requested.group == 'com.google.dagger') {
+ details.useVersion 'LOCAL-SNAPSHOT'
+ details.because 'LOCAL-SNAPSHOT should act as latest version.'
+ }
+ }
+}
+
+dependencies {
+ implementation "com.google.dagger:hilt-android:$dagger_version"
+ annotationProcessor "com.google.dagger:hilt-compiler:$dagger_version"
+
+ testImplementation 'com.google.truth:truth:1.0.1'
+ testImplementation 'junit:junit:4.13'
+ testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
+ testImplementation 'androidx.core:core:1.3.2'
+ testImplementation 'androidx.test.ext:junit:1.1.2'
+ testImplementation 'androidx.test:runner:1.3.0'
+ testImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+}
diff --git a/javatests/artifacts/hilt-android/simple/app-java-only/src/main/AndroidManifest.xml b/javatests/artifacts/hilt-android/simple/app-java-only/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..cae4e88fa
--- /dev/null
+++ b/javatests/artifacts/hilt-android/simple/app-java-only/src/main/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2021 The Dagger Authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="dagger.hilt.android.simple">
+
+ <application
+ android:name=".SimpleApplication"
+ android:label="Java-only Hilt Android"
+ android:taskAffinity="">
+ </application>
+</manifest>
diff --git a/javatests/artifacts/hilt-android/simple/app-java-only/src/main/java/dagger/hilt/android/simple/SimpleApplication.java b/javatests/artifacts/hilt-android/simple/app-java-only/src/main/java/dagger/hilt/android/simple/SimpleApplication.java
new file mode 100644
index 000000000..2a0d8be9a
--- /dev/null
+++ b/javatests/artifacts/hilt-android/simple/app-java-only/src/main/java/dagger/hilt/android/simple/SimpleApplication.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.simple;
+
+import android.app.Application;
+import dagger.Module;
+import dagger.Provides;
+import dagger.hilt.EntryPoint;
+import dagger.hilt.InstallIn;
+import dagger.hilt.android.EntryPointAccessors;
+import dagger.hilt.android.HiltAndroidApp;
+import dagger.hilt.components.SingletonComponent;
+import javax.inject.Inject;
+
+/** A java-only application that uses Hilt. */
+@HiltAndroidApp
+public class SimpleApplication extends Application {
+ @Module
+ @InstallIn(SingletonComponent.class)
+ interface MyModule {
+ @Provides
+ static String provideString() {
+ return "some string";
+ }
+ }
+
+ @EntryPoint
+ @InstallIn(SingletonComponent.class)
+ interface MyEntryPoint {
+ String getString();
+ }
+
+ @Inject String str;
+
+ public String getStringEntryPoint() {
+ return EntryPointAccessors.fromApplication(this, MyEntryPoint.class).getString();
+ }
+}
diff --git a/javatests/artifacts/hilt-android/simple/app-java-only/src/test/java/dagger/hilt/android/simple/BuildTest.java b/javatests/artifacts/hilt-android/simple/app-java-only/src/test/java/dagger/hilt/android/simple/BuildTest.java
new file mode 100644
index 000000000..9411852d2
--- /dev/null
+++ b/javatests/artifacts/hilt-android/simple/app-java-only/src/test/java/dagger/hilt/android/simple/BuildTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.simple;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Build;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+/**
+ * Regression test for https://github.com/google/dagger/issues/3119
+ */
+@RunWith(AndroidJUnit4.class)
+// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
+@Config(sdk = Build.VERSION_CODES.P, application = SimpleApplication.class)
+public class BuildTest {
+ @Test
+ public void useAppContext() {
+ assertThat((Object) ApplicationProvider.getApplicationContext())
+ .isInstanceOf(SimpleApplication.class);
+ SimpleApplication app = (SimpleApplication) ApplicationProvider.getApplicationContext();
+ assertThat(app.str).isNotNull();
+ assertThat(app.str).isEqualTo(app.getStringEntryPoint());
+ }
+}
diff --git a/javatests/artifacts/hilt-android/simple/app/build.gradle b/javatests/artifacts/hilt-android/simple/app/build.gradle
index 1d76ec26c..34043ad29 100644
--- a/javatests/artifacts/hilt-android/simple/app/build.gradle
+++ b/javatests/artifacts/hilt-android/simple/app/build.gradle
@@ -13,10 +13,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import org.gradle.util.VersionNumber
apply plugin: 'com.android.application'
apply plugin: 'dagger.hilt.android.plugin'
+// Gets additional test directories to be added to test and androidTest source
+// sets. If the directory name is appended with '-agp-x.x.x' then the directory
+// is conditionally added based on the AGP version of the project.
+def getAdditionalTestDirs(String variant) {
+ def testDirs = [
+ 'androidTest': [],
+ 'sharedTest': ['src/sharedTest/java'],
+ 'test': []
+ ]
+ def suffix = '-agp-'
+ def agpVersion = VersionNumber.parse(agp_version)
+ file("${getProjectDir().absolutePath}/src").eachFile { file ->
+ int indexOf = file.name.indexOf(suffix)
+ if (file.isDirectory() && indexOf != -1) {
+ def dirAgpVersion =
+ VersionNumber.parse(file.name.substring(indexOf + suffix.length()))
+ if (agpVersion >= dirAgpVersion) {
+ testDirs[file.name.substring(0, indexOf)].add("src/${file.name}/java")
+ }
+ }
+ }
+ return testDirs[variant] + testDirs['sharedTest']
+}
+
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
@@ -40,19 +65,18 @@ android {
checkReleaseBuilds = false
}
sourceSets {
- String sharedTestDir = 'src/sharedTest/java'
test {
- java.srcDirs += sharedTestDir
+ java.srcDirs += getAdditionalTestDirs("test")
}
androidTest {
- java.srcDirs += sharedTestDir
+ java.srcDirs += getAdditionalTestDirs("androidTest")
}
}
}
hilt {
- enableExperimentalClasspathAggregation = true
enableTransformForLocalTests = true
+ enableAggregatingTask = true
}
configurations.all {
@@ -97,8 +121,8 @@ dependencies {
// To help us catch version skew related issues in hilt extensions.
// TODO(bcorso): Add examples testing the actual API.
- implementation 'androidx.hilt:hilt-work:1.0.0-alpha01'
- annotationProcessor 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
- testAnnotationProcessor 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
- androidTestAnnotationProcessor 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
+ implementation 'androidx.hilt:hilt-work:1.0.0'
+ annotationProcessor 'androidx.hilt:hilt-compiler:1.0.0'
+ testAnnotationProcessor 'androidx.hilt:hilt-compiler:1.0.0'
+ androidTestAnnotationProcessor 'androidx.hilt:hilt-compiler:1.0.0'
}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/BroadcastReceiverTest.java b/javatests/artifacts/hilt-android/simple/app/src/androidTest-agp-4.2.0/java/dagger/hilt/android/simple/BroadcastReceiverTest.java
index 7585bbb1d..265869ab5 100644
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/BroadcastReceiverTest.java
+++ b/javatests/artifacts/hilt-android/simple/app/src/androidTest-agp-4.2.0/java/dagger/hilt/android/simple/BroadcastReceiverTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package dagger.hilt.android.example.gradle.simple;
+package dagger.hilt.android.simple;
import static com.google.common.truth.Truth.assertThat;
@@ -111,7 +111,7 @@ public class BroadcastReceiverTest {
/** Test receiver */
@AndroidEntryPoint
- static class TestReceiverOne extends BroadcastReceiver {
+ public static class TestReceiverOne extends BroadcastReceiver {
final CountDownLatch latch = new CountDownLatch(1);
@@ -126,7 +126,7 @@ public class BroadcastReceiverTest {
/** Test receiver */
@AndroidEntryPoint
- static class TestReceiverTwo extends BaseReceiverAbstractMethod {
+ public static class TestReceiverTwo extends BaseReceiverAbstractMethod {
final CountDownLatch latch = new CountDownLatch(1);
@@ -141,7 +141,7 @@ public class BroadcastReceiverTest {
/** Test receiver */
@AndroidEntryPoint
- static class TestReceiverThree extends BaseReceiverConcreteMethod {
+ public static class TestReceiverThree extends BaseReceiverConcreteMethod {
final CountDownLatch latch = new CountDownLatch(1);
@@ -157,7 +157,7 @@ public class BroadcastReceiverTest {
/** Complex-ish test receiver */
@AndroidEntryPoint
- static class TestReceiverFour extends BroadcastReceiver {
+ public static class TestReceiverFour extends BroadcastReceiver {
final CountDownLatch latch = new CountDownLatch(1);
diff --git a/javatests/artifacts/hilt-android/simple/app/src/debug/AndroidManifest.xml b/javatests/artifacts/hilt-android/simple/app/src/debug/AndroidManifest.xml
index 14d33b0c7..76c6afad3 100644
--- a/javatests/artifacts/hilt-android/simple/app/src/debug/AndroidManifest.xml
+++ b/javatests/artifacts/hilt-android/simple/app/src/debug/AndroidManifest.xml
@@ -18,6 +18,10 @@
<application>
<activity
+ android:name=".AliasOfMultipleScopesTest$TestActivity"
+ android:theme="@style/Theme.AppCompat.Light"
+ android:exported="false" />
+ <activity
android:name=".Injection1Test$TestActivity"
android:theme="@style/Theme.AppCompat.Light"
android:exported="false" />
@@ -26,6 +30,10 @@
android:theme="@style/Theme.AppCompat.Light"
android:exported="false"/>
<activity
+ android:name=".InvokeSpecialTransformTest$TestActivity"
+ android:theme="@style/Theme.AppCompat.Light"
+ android:exported="false"/>
+ <activity
android:name=".ActivityScenarioRuleTest$TestActivity"
android:theme="@style/Theme.AppCompat.Light"
android:exported="false"/>
diff --git a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/AliasOfMultipleScopesTest.java b/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/AliasOfMultipleScopesTest.java
new file mode 100644
index 000000000..7175f78a9
--- /dev/null
+++ b/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/AliasOfMultipleScopesTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.simple;
+
+import static com.google.common.truth.Truth.assertThat;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+import android.content.Context;
+import androidx.activity.ComponentActivity;
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import dagger.Module;
+import dagger.Provides;
+import dagger.hilt.DefineComponent;
+import dagger.hilt.EntryPoint;
+import dagger.hilt.EntryPoints;
+import dagger.hilt.InstallIn;
+import dagger.hilt.android.AndroidEntryPoint;
+import dagger.hilt.android.components.ActivityComponent;
+import dagger.hilt.android.qualifiers.ApplicationContext;
+import dagger.hilt.android.scopes.ActivityScoped;
+import dagger.hilt.android.testing.HiltAndroidRule;
+import dagger.hilt.android.testing.HiltAndroidTest;
+import dagger.hilt.components.SingletonComponent;
+import dagger.hilt.migration.AliasOf;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Scope;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@HiltAndroidTest
+@RunWith(AndroidJUnit4.class)
+public final class AliasOfMultipleScopesTest {
+
+ @Rule public final HiltAndroidRule rule = new HiltAndroidRule(this);
+
+ @Inject @ApplicationContext Context context;
+ @Inject CustomComponent.Builder customComponentBuilder;
+
+ @Scope
+ @Retention(CLASS)
+ @Target({ElementType.METHOD, ElementType.TYPE})
+ public @interface CustomScoped {}
+
+ @DefineComponent(parent = SingletonComponent.class)
+ @CustomScoped
+ public interface CustomComponent {
+ @DefineComponent.Builder
+ public interface Builder {
+ CustomComponent build();
+ }
+ }
+
+ @Scope
+ @AliasOf({ActivityScoped.class, CustomScoped.class})
+ public @interface AliasScoped {}
+
+ public interface UnscopedDep {}
+
+ public interface ActivityScopedDep {}
+
+ public interface CustomScopedDep {}
+
+ public interface AliasScopedDep {}
+
+ @Module
+ @InstallIn(SingletonComponent.class)
+ interface SingletonTestModule {
+ @Provides
+ static UnscopedDep unscopedDep() {
+ return new UnscopedDep() {};
+ }
+ }
+
+ @Module
+ @InstallIn(ActivityComponent.class)
+ interface ActivityTestModule {
+ @Provides
+ @ActivityScoped
+ static ActivityScopedDep activityScopedDep() {
+ return new ActivityScopedDep() {};
+ }
+
+ @Provides
+ @AliasScoped
+ static AliasScopedDep aliasScopedDep() {
+ return new AliasScopedDep() {};
+ }
+ }
+
+ @Module
+ @InstallIn(CustomComponent.class)
+ interface CustomTestModule {
+ @Provides
+ @CustomScoped
+ static CustomScopedDep customScopedDep() {
+ return new CustomScopedDep() {};
+ }
+
+ @Provides
+ @AliasScoped
+ static AliasScopedDep aliasScopedDep() {
+ return new AliasScopedDep() {};
+ }
+ }
+
+ /** An activity to test injection. */
+ @AndroidEntryPoint(ComponentActivity.class)
+ public static final class TestActivity extends Hilt_AliasOfMultipleScopesTest_TestActivity {
+ @Inject Provider<UnscopedDep> unscopedDep;
+ @Inject Provider<ActivityScopedDep> activityScopedDep;
+ @Inject Provider<AliasScopedDep> aliasScopedDep;
+ }
+
+ @EntryPoint
+ @InstallIn(SingletonComponent.class)
+ interface CustomComponentBuilderEntryPoint {
+ CustomComponent.Builder customComponentBuilder();
+ }
+
+ @EntryPoint
+ @InstallIn(CustomComponent.class)
+ interface CustomComponentEntryPoint {
+ Provider<UnscopedDep> unscopedDep();
+
+ Provider<CustomScopedDep> customScopedDep();
+
+ Provider<AliasScopedDep> aliasScopedDep();
+ }
+
+ @Before
+ public void setUp() {
+ rule.inject();
+ }
+
+ @Test
+ public void testActivityScoped() {
+ try (ActivityScenario<TestActivity> scenario = ActivityScenario.launch(TestActivity.class)) {
+ scenario.onActivity(
+ activity -> {
+ assertThat(activity.unscopedDep.get()).isNotSameInstanceAs(activity.unscopedDep.get());
+ assertThat(activity.activityScopedDep.get())
+ .isSameInstanceAs(activity.activityScopedDep.get());
+ assertThat(activity.aliasScopedDep.get())
+ .isSameInstanceAs(activity.aliasScopedDep.get());
+ });
+ }
+ }
+
+ @Test
+ public void testCustomScoped() {
+ CustomComponent customComponent =
+ EntryPoints.get(context, CustomComponentBuilderEntryPoint.class)
+ .customComponentBuilder()
+ .build();
+ CustomComponentEntryPoint entryPoint =
+ EntryPoints.get(customComponent, CustomComponentEntryPoint.class);
+ assertThat(entryPoint.unscopedDep().get()).isNotSameInstanceAs(entryPoint.unscopedDep().get());
+ assertThat(entryPoint.customScopedDep().get())
+ .isSameInstanceAs(entryPoint.customScopedDep().get());
+ assertThat(entryPoint.aliasScopedDep().get())
+ .isSameInstanceAs(entryPoint.aliasScopedDep().get());
+ }
+}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/InvokeSpecialTransformTest.java b/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/InvokeSpecialTransformTest.java
new file mode 100644
index 000000000..9fed04a6a
--- /dev/null
+++ b/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/InvokeSpecialTransformTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.simple;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.widget.FrameLayout;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.lifecycle.Lifecycle.State;
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import dagger.hilt.android.AndroidEntryPoint;
+import dagger.hilt.android.testing.HiltAndroidRule;
+import dagger.hilt.android.testing.HiltAndroidTest;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Test that verifies edge cases of invokespecial instructions transformation. */
+@HiltAndroidTest
+@RunWith(AndroidJUnit4.class)
+public class InvokeSpecialTransformTest {
+
+ @Rule
+ public HiltAndroidRule rule = new HiltAndroidRule(this);
+
+ @Test
+ public void constructorCallOfOldSuperclass() {
+ try (ActivityScenario<TestActivity> scenario = ActivityScenario.launch(TestActivity.class)) {
+ scenario.moveToState(State.DESTROYED);
+ }
+ }
+
+ /** A test activity */
+ @AndroidEntryPoint
+ public static final class TestActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(new CustomView(this).createBrother());
+ }
+ }
+
+ /** A custom view for testing */
+ @AndroidEntryPoint
+ public static class CustomView extends FrameLayout {
+
+ public CustomView(@NonNull Context context) {
+ // This super call is an invokespecial that should be transformed
+ super(context);
+ // This invokespecial that should not be transformed.
+ FrameLayout secondInvokeSpecial = new FrameLayout(getContext());
+ }
+
+ FrameLayout createBrother() {
+ // This invokespecial that should not be transformed.
+ return new FrameLayout(getContext());
+ }
+ }
+} \ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simple/build.gradle b/javatests/artifacts/hilt-android/simple/build.gradle
index 59336bcbf..d869b39ee 100644
--- a/javatests/artifacts/hilt-android/simple/build.gradle
+++ b/javatests/artifacts/hilt-android/simple/build.gradle
@@ -17,12 +17,12 @@
buildscript {
ext {
dagger_version = 'LOCAL-SNAPSHOT'
- kotlin_version = '1.3.61'
- agp_version = System.getenv('AGP_VERSION') ?: "4.2.0-beta04"
+ kotlin_version = '1.5.32'
+ agp_version = System.getenv('AGP_VERSION') ?: "4.2.0"
}
repositories {
google()
- jcenter()
+ mavenCentral()
mavenLocal()
}
dependencies {
@@ -35,7 +35,6 @@ buildscript {
allprojects {
repositories {
google()
- jcenter()
mavenCentral()
mavenLocal()
}
diff --git a/javatests/artifacts/hilt-android/simple/earlyentrypoint/build.gradle b/javatests/artifacts/hilt-android/simple/earlyentrypoint/build.gradle
new file mode 100644
index 000000000..1428fb125
--- /dev/null
+++ b/javatests/artifacts/hilt-android/simple/earlyentrypoint/build.gradle
@@ -0,0 +1,68 @@
+plugins {
+ id 'com.android.library'
+ id 'dagger.hilt.android.plugin'
+}
+
+android {
+ compileSdkVersion 30
+ buildToolsVersion "30.0.2"
+
+ defaultConfig {
+ minSdkVersion 15
+ targetSdkVersion 30
+ versionCode 1
+ versionName "1.0"
+ }
+ compileOptions {
+ sourceCompatibility 1.8
+ targetCompatibility 1.8
+ }
+ testOptions {
+ unitTests.includeAndroidResources = true
+ }
+}
+
+hilt {
+ enableTransformForLocalTests = true
+ enableAggregatingTask = true
+}
+
+// This is a regression test for https://github.com/google/dagger/issues/2789.
+// Reproducing this issue requires that we don't have unexpected tests, so this
+// check validates that. In particular, if we accidentally add a test with no
+// test-specific bindings the EarlyEntryPoints will use the component for that
+// test instead of generating a component just for the EarlyEntryPoints, which
+// causes this issue.
+task checkSourceSetTask(){
+ sourceSets {
+ test {
+ def actualSrcs = allSource.files.name as Set
+ def expectedSrcs = [
+ 'EarlyEntryPointWithBindValueTest.java',
+ 'EarlyEntryPointWithBindValueObjects.java'
+ ] as Set
+ if (!actualSrcs.equals(expectedSrcs)) {
+ throw new StopExecutionException(
+ 'Unexpected test sources: ' + allSource.files.name)
+ }
+ }
+ }
+}
+
+gradle.projectsEvaluated {
+ preBuild.dependsOn checkSourceSetTask
+}
+
+dependencies {
+ implementation "com.google.dagger:hilt-android:$dagger_version"
+ annotationProcessor "com.google.dagger:hilt-compiler:$dagger_version"
+
+ testImplementation 'com.google.truth:truth:1.0.1'
+ testImplementation 'junit:junit:4.13'
+ testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
+ testImplementation 'androidx.core:core:1.3.2'
+ testImplementation 'androidx.test.ext:junit:1.1.2'
+ testImplementation 'androidx.test:runner:1.3.0'
+ testImplementation "com.google.dagger:hilt-android-testing:$dagger_version"
+ testAnnotationProcessor "com.google.dagger:hilt-compiler:$dagger_version"
+} \ No newline at end of file
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/debug/AndroidManifest.xml b/javatests/artifacts/hilt-android/simple/earlyentrypoint/src/main/AndroidManifest.xml
index 081c7ade7..7197111ea 100644
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/debug/AndroidManifest.xml
+++ b/javatests/artifacts/hilt-android/simple/earlyentrypoint/src/main/AndroidManifest.xml
@@ -16,9 +16,6 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.example.gradle.simpleKotlin">
+ package="dagger.hilt.android.simple.earlyentrypoint">
- <application>
- <activity android:name=".SimpleTest$TestActivity" android:exported="false"/>
- </application>
</manifest>
diff --git a/java/dagger/example/gradle/simple/SimpleApplication.java b/javatests/artifacts/hilt-android/simple/earlyentrypoint/src/test/java/dagger/hilt/android/simple/earlyentrypoint/EarlyEntryPointWithBindValueObjects.java
index 11552f869..c86f90025 100644
--- a/java/dagger/example/gradle/simple/SimpleApplication.java
+++ b/javatests/artifacts/hilt-android/simple/earlyentrypoint/src/test/java/dagger/hilt/android/simple/earlyentrypoint/EarlyEntryPointWithBindValueObjects.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Dagger Authors.
+ * Copyright (C) 2021 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,35 +14,28 @@
* limitations under the License.
*/
-package dagger.example.gradle.simple;
+package dagger.hilt.android.simple;
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
+import dagger.hilt.InstallIn;
+import dagger.hilt.android.EarlyEntryPoint;
+import dagger.hilt.components.SingletonComponent;
import javax.inject.Inject;
import javax.inject.Singleton;
-/** A simple, skeletal application that defines a simple component. */
-public class SimpleApplication {
- static final class Foo {
- @Inject Foo() {}
- }
-
- @Module
- static final class SimpleModule {
- @Provides
- static Foo provideFoo() {
- return new Foo();
- }
- }
+// This is defined outside of the tests since EarlyEntryPoint cannot be nested in tests.
+public final class EarlyEntryPointWithBindValueObjects {
+ private EarlyEntryPointWithBindValueObjects() {}
@Singleton
- @Component(modules = { SimpleModule.class })
- interface SimpleComponent {
- Foo foo();
+ public static final class Foo {
+ @Inject
+ Foo() {}
}
- public static void main(String[] args) {
- Foo foo = DaggerSimpleApplication_SimpleComponent.create().foo();
+ /** Used to test {@link EarlyEntryPoint} */
+ @EarlyEntryPoint
+ @InstallIn(SingletonComponent.class)
+ public interface FooEarlyEntryPoint {
+ Foo getEarlyFoo();
}
}
diff --git a/javatests/artifacts/hilt-android/simple/earlyentrypoint/src/test/java/dagger/hilt/android/simple/earlyentrypoint/EarlyEntryPointWithBindValueTest.java b/javatests/artifacts/hilt-android/simple/earlyentrypoint/src/test/java/dagger/hilt/android/simple/earlyentrypoint/EarlyEntryPointWithBindValueTest.java
new file mode 100644
index 000000000..0b2acfd0e
--- /dev/null
+++ b/javatests/artifacts/hilt-android/simple/earlyentrypoint/src/test/java/dagger/hilt/android/simple/earlyentrypoint/EarlyEntryPointWithBindValueTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.simple;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.Build;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import dagger.hilt.EntryPoint;
+import dagger.hilt.EntryPoints;
+import dagger.hilt.InstallIn;
+import dagger.hilt.android.EarlyEntryPoints;
+import dagger.hilt.android.simple.EarlyEntryPointWithBindValueObjects.Foo;
+import dagger.hilt.android.simple.EarlyEntryPointWithBindValueObjects.FooEarlyEntryPoint;
+import dagger.hilt.android.testing.BindValue;
+import dagger.hilt.android.testing.HiltAndroidRule;
+import dagger.hilt.android.testing.HiltAndroidTest;
+import dagger.hilt.android.testing.HiltTestApplication;
+import dagger.hilt.components.SingletonComponent;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+@HiltAndroidTest
+@RunWith(AndroidJUnit4.class)
+// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
+@Config(sdk = Build.VERSION_CODES.P, application = HiltTestApplication.class)
+public final class EarlyEntryPointWithBindValueTest {
+ @EntryPoint
+ @InstallIn(SingletonComponent.class)
+ interface FooEntryPoint {
+ Foo foo();
+ }
+
+ @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
+
+ @BindValue String bindString = "TestValue";
+
+ @Test
+ public void testBindValue() throws Exception {
+ rule.inject();
+ assertThat(bindString).isNotNull();
+ assertThat(bindString).isEqualTo("TestValue");
+ }
+
+ @Test
+ public void testEarlyEntryPoint() throws Exception {
+ Context appContext = getApplicationContext();
+
+ // Assert that all scoped Foo instances from EarlyEntryPoint are equal
+ Foo earlyFoo1 = EarlyEntryPoints.get(appContext, FooEarlyEntryPoint.class).getEarlyFoo();
+ Foo earlyFoo2 = EarlyEntryPoints.get(appContext, FooEarlyEntryPoint.class).getEarlyFoo();
+ assertThat(earlyFoo1).isNotNull();
+ assertThat(earlyFoo2).isNotNull();
+ assertThat(earlyFoo1).isEqualTo(earlyFoo2);
+
+ // Assert that all scoped Foo instances from EntryPoint are equal
+ Foo foo1 = EntryPoints.get(appContext, FooEntryPoint.class).foo();
+ Foo foo2 = EntryPoints.get(appContext, FooEntryPoint.class).foo();
+ assertThat(foo1).isNotNull();
+ assertThat(foo2).isNotNull();
+ assertThat(foo1).isEqualTo(foo2);
+
+ // Assert that scoped Foo instances from EarlyEntryPoint and EntryPoint are not equal
+ assertThat(foo1).isNotEqualTo(earlyFoo1);
+ }
+}
diff --git a/javatests/artifacts/hilt-android/simple/gradle.properties b/javatests/artifacts/hilt-android/simple/gradle.properties
index 646c51b97..cc9cc5521 100644
--- a/javatests/artifacts/hilt-android/simple/gradle.properties
+++ b/javatests/artifacts/hilt-android/simple/gradle.properties
@@ -1,2 +1,9 @@
android.useAndroidX=true
android.enableJetifier=true
+
+# Enable and fail the build if an issue is found that disallows the
+# configuration cache. These options along with this app being built in
+# presubmit helps us cache changes that would cause config cache to be disabled
+# via the HiltGradlePlugin.
+org.gradle.unsafe.configuration-cache-problems=fail
+org.gradle.unsafe.configuration-cache.max-problems=0
diff --git a/javatests/artifacts/hilt-android/simple/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/hilt-android/simple/gradle/wrapper/gradle-wrapper.properties
index 4d9ca1649..0f80bbf51 100644
--- a/javatests/artifacts/hilt-android/simple/gradle/wrapper/gradle-wrapper.properties
+++ b/javatests/artifacts/hilt-android/simple/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/javatests/artifacts/hilt-android/simple/settings.gradle b/javatests/artifacts/hilt-android/simple/settings.gradle
index bad895d28..9dc59db7e 100644
--- a/javatests/artifacts/hilt-android/simple/settings.gradle
+++ b/javatests/artifacts/hilt-android/simple/settings.gradle
@@ -1,6 +1,8 @@
rootProject.name='Simple Hilt Android'
include ':app'
+include ':app-java-only'
include ':feature'
include ':lib'
include ':deep-android-lib'
-include ':deep-lib' \ No newline at end of file
+include ':deep-lib'
+include ':earlyentrypoint' \ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/android-library/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/android-library/build.gradle
index 383c4be2f..f682247a8 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/android-library/build.gradle
+++ b/javatests/artifacts/hilt-android/simpleKotlin/android-library/build.gradle
@@ -26,6 +26,7 @@ android {
dependencies {
implementation project(':deep-android-lib')
implementation project(':deep-kotlin-lib')
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
kapt 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
} \ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle
index ecfaf6e92..d8104d712 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle
+++ b/javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle
@@ -62,8 +62,8 @@ android {
}
hilt {
- enableExperimentalClasspathAggregation = true
enableTransformForLocalTests = true
+ enableAggregatingTask = true
}
dependencies {
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/MainActivity.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/sharedTest/java/dagger/hilt/android/simpleKotlin/KotlinSuppressClasses.kt
index 0011bdefc..c9bc671c3 100644
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/MainActivity.kt
+++ b/javatests/artifacts/hilt-android/simpleKotlin/app/src/sharedTest/java/dagger/hilt/android/simpleKotlin/KotlinSuppressClasses.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Dagger Authors.
+ * Copyright (C) 2021 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,23 +14,16 @@
* limitations under the License.
*/
-package dagger.hilt.android.gradleConfigCache
+package dagger.hilt.android.simpleKotlin
-import android.os.Bundle
-import android.util.Log
-import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.FragmentActivity
import dagger.hilt.android.AndroidEntryPoint
-import javax.inject.Inject
-@AndroidEntryPoint
-class MainActivity : AppCompatActivity() {
-
- @Inject
- lateinit var foo: Foo
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- Log.d("Hilt", "Foo is $foo")
- }
+// Regression test for https://github.com/google/dagger/issues/2898
+// TODO(bcorso):Replace this with a Kotlin compiler test and verify the SuppressWarnings is
+// propagated to the generated Hilt class.
+class KotlinSuppressClasses {
+ @Suppress("deprecation")
+ @AndroidEntryPoint
+ class MyActivity : FragmentActivity()
}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/build.gradle
index e7eb9b252..249387c46 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/build.gradle
+++ b/javatests/artifacts/hilt-android/simpleKotlin/build.gradle
@@ -16,12 +16,12 @@
buildscript {
ext {
- kotlin_version = '1.3.61'
- agp_version = System.getenv('AGP_VERSION') ?: "4.2.0-beta04"
+ kotlin_version = '1.5.32'
+ agp_version = System.getenv('AGP_VERSION') ?: "4.2.0"
}
repositories {
google()
- jcenter()
+ mavenCentral()
mavenLocal()
}
dependencies {
@@ -34,7 +34,6 @@ buildscript {
allprojects {
repositories {
google()
- jcenter()
mavenCentral()
mavenLocal()
}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle
index 3a1923aff..8bfadf048 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle
+++ b/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle
@@ -30,6 +30,8 @@ android {
}
dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+
implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
kapt 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
@@ -42,5 +44,5 @@ dependencies {
}
hilt {
- enableExperimentalClasspathAggregation = true
+ enableAggregatingTask = true
} \ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/gradle.properties b/javatests/artifacts/hilt-android/simpleKotlin/gradle.properties
index 646c51b97..cc9cc5521 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/gradle.properties
+++ b/javatests/artifacts/hilt-android/simpleKotlin/gradle.properties
@@ -1,2 +1,9 @@
android.useAndroidX=true
android.enableJetifier=true
+
+# Enable and fail the build if an issue is found that disallows the
+# configuration cache. These options along with this app being built in
+# presubmit helps us cache changes that would cause config cache to be disabled
+# via the HiltGradlePlugin.
+org.gradle.unsafe.configuration-cache-problems=fail
+org.gradle.unsafe.configuration-cache.max-problems=0
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/hilt-android/simpleKotlin/gradle/wrapper/gradle-wrapper.properties
index 4d9ca1649..0f80bbf51 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/gradle/wrapper/gradle-wrapper.properties
+++ b/javatests/artifacts/hilt-android/simpleKotlin/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/javatests/dagger/BUILD b/javatests/dagger/BUILD
index c6ab360b7..f3153d945 100644
--- a/javatests/dagger/BUILD
+++ b/javatests/dagger/BUILD
@@ -27,10 +27,10 @@ GenJavaTests(
javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
deps = [
"//java/dagger:core",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/util/concurrent",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/android/BUILD b/javatests/dagger/android/BUILD
index 38efb3afa..09dc4ae40 100644
--- a/javatests/dagger/android/BUILD
+++ b/javatests/dagger/android/BUILD
@@ -29,8 +29,8 @@ GenRobolectricTests(
deps = [
"//:dagger_with_compiler",
"//java/dagger/android",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/guava/collect",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/android/processor/BUILD b/javatests/dagger/android/processor/BUILD
index c639a4191..4dbd26074 100644
--- a/javatests/dagger/android/processor/BUILD
+++ b/javatests/dagger/android/processor/BUILD
@@ -30,12 +30,12 @@ GenJavaTests(
"//java/dagger/android",
"//java/dagger/android/processor",
"//java/dagger/internal/codegen:processor",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
+ "//third_party/java/compile_testing",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
"@androidsdk//:platforms/android-30/android.jar",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
"@maven//:androidx_activity_activity",
"@maven//:androidx_fragment_fragment",
"@maven//:androidx_lifecycle_lifecycle_common",
diff --git a/javatests/dagger/android/support/BUILD b/javatests/dagger/android/support/BUILD
index 2ef1ece6e..de1b2d3cf 100644
--- a/javatests/dagger/android/support/BUILD
+++ b/javatests/dagger/android/support/BUILD
@@ -32,11 +32,11 @@ GenRobolectricTests(
"//:dagger_with_compiler",
"//java/dagger/android",
"//java/dagger/android/support",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/util/concurrent",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
"@maven//:androidx_activity_activity",
"@maven//:androidx_appcompat_appcompat",
"@maven//:androidx_fragment_fragment",
diff --git a/javatests/dagger/android/support/functional/BUILD b/javatests/dagger/android/support/functional/BUILD
index 459d55fee..0281ea10e 100644
--- a/javatests/dagger/android/support/functional/BUILD
+++ b/javatests/dagger/android/support/functional/BUILD
@@ -40,7 +40,7 @@ android_library(
"//:android",
"//:android-support",
# TODO(ronshapiro): figure out why strict deps is failing without this
- "@google_bazel_common//third_party/java/jsr250_annotations",
+ "//third_party/java/jsr250_annotations",
],
)
@@ -55,7 +55,7 @@ GenRobolectricTests(
"//:android",
"//:android-support",
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/truth",
"@maven//:androidx_activity_activity",
"@maven//:androidx_fragment_fragment",
"@maven//:androidx_lifecycle_lifecycle_common",
diff --git a/javatests/dagger/functional/BUILD b/javatests/dagger/functional/BUILD
index 8e6a5551e..81469a241 100644
--- a/javatests/dagger/functional/BUILD
+++ b/javatests/dagger/functional/BUILD
@@ -28,19 +28,19 @@ GenJavaTests(
javacopts = DOCLINT_HTML_AND_SYNTAX,
lib_javacopts = SOURCE_7_TARGET_7,
test_only_deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "@google_bazel_common//third_party/java/guava:testlib",
- "@google_bazel_common//third_party/java/truth",
- "@google_bazel_common//third_party/java/junit",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/util/concurrent",
+ "//third_party/java/guava:testlib",
+ "//third_party/java/truth",
+ "//third_party/java/junit",
],
# NOTE: This should not depend on Guava or jsr305 to ensure that Dagger can be
# used without Guava and jsr305 deps.
deps = [
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/auto:factory",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/jsr330_inject",
+ "//third_party/java/auto:factory",
+ "//third_party/java/auto:value",
+ "//third_party/java/jsr330_inject",
],
)
diff --git a/javatests/dagger/functional/ComponentNestedTypeTest.java b/javatests/dagger/functional/ComponentNestedTypeTest.java
new file mode 100644
index 000000000..e39c42994
--- /dev/null
+++ b/javatests/dagger/functional/ComponentNestedTypeTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.functional;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import dagger.Component;
+import dagger.Module;
+import dagger.Provides;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Regression test for b/212604806. */
+@RunWith(JUnit4.class)
+public final class ComponentNestedTypeTest {
+ @Component(modules = TestModule.class)
+ interface TestComponent {
+
+ // Dagger generated component implementation that extends TestComponent will implement this
+ // method, so the component implementation will keep a reference to the {@link
+ // dagger.functional.sub.NestedType}. The reference to {@link dagger.functional.sub.NestedType}
+ // may collide with the NestedType defined inside of TestComponent, because javapoet may strip
+ // the package prefix of the type as it does not have enough information about the super
+ // class/interfaces.
+ dagger.functional.sub.NestedType nestedType();
+
+ interface NestedType {}
+ }
+
+ public static final class SomeType implements dagger.functional.sub.NestedType {}
+
+ @Module
+ static final class TestModule {
+ @Provides
+ static dagger.functional.sub.NestedType provideSomeType() {
+ return new SomeType();
+ }
+ }
+
+ @Test
+ public void typeNameWontClashWithNestedTypeName() {
+ TestComponent component =
+ DaggerComponentNestedTypeTest_TestComponent.builder().testModule(new TestModule()).build();
+ assertThat(component.nestedType()).isNotNull();
+ }
+}
diff --git a/javatests/dagger/functional/assisted/AssistedFactoryDuplicatedParamNamesTest.java b/javatests/dagger/functional/assisted/AssistedFactoryDuplicatedParamNamesTest.java
new file mode 100644
index 000000000..af9b40e10
--- /dev/null
+++ b/javatests/dagger/functional/assisted/AssistedFactoryDuplicatedParamNamesTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.functional.assisted;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import dagger.BindsInstance;
+import dagger.Component;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class AssistedFactoryDuplicatedParamNamesTest {
+ static final class Foo {
+ private final String arg;
+ private final Bar bar;
+
+ @AssistedInject
+ Foo(@Assisted String arg, Bar bar) {
+ this.arg = arg;
+ this.bar = bar;
+ }
+
+ Bar getBar() {
+ return bar;
+ }
+
+ String getArg() {
+ return arg;
+ }
+ }
+
+ static final class Bar {}
+
+ @AssistedFactory
+ interface FooFactory {
+ Foo create(String arg);
+ }
+
+ @Component
+ interface TestComponent {
+ @Component.Factory
+ interface Factory {
+ TestComponent create(@BindsInstance Bar arg);
+ }
+
+ FooFactory fooFactory();
+ }
+
+ @Test
+ public void duplicatedParameterNames_doesNotConflict() {
+ String str = "test";
+ Bar bar = new Bar();
+
+ Foo foo =
+ DaggerAssistedFactoryDuplicatedParamNamesTest_TestComponent.factory()
+ .create(bar)
+ .fooFactory()
+ .create(str);
+
+ assertThat(foo.getArg()).isEqualTo(str);
+ assertThat(foo.getBar()).isEqualTo(bar);
+ }
+}
diff --git a/javatests/dagger/functional/assisted/AssistedFactoryTest.java b/javatests/dagger/functional/assisted/AssistedFactoryTest.java
index 3176add46..d8ef53ad6 100644
--- a/javatests/dagger/functional/assisted/AssistedFactoryTest.java
+++ b/javatests/dagger/functional/assisted/AssistedFactoryTest.java
@@ -35,6 +35,8 @@ public final class AssistedFactoryTest {
// Simple factory using a nested factory.
SimpleFoo.Factory nestedSimpleFooFactory();
+ Provider<SimpleFoo.Factory> nestedSimpleFooFactoryProvider();
+
// Simple factory using a non-nested factory.
SimpleFooFactory nonNestedSimpleFooFactory();
@@ -58,6 +60,7 @@ public final class AssistedFactoryTest {
static class SomeEntryPoint {
private final SimpleFoo.Factory nestedSimpleFooFactory;
private final SimpleFooFactory nonNestedSimpleFooFactory;
+ private final Provider<SimpleFoo.Factory> nestedSimpleFooFactoryProvider;
private final ExtendedSimpleFooFactory extendedSimpleFooFactory;
private final FooFactory fooFactory;
private final AbstractFooFactory abstractFooFactory;
@@ -66,12 +69,14 @@ public final class AssistedFactoryTest {
@Inject
SomeEntryPoint(
SimpleFoo.Factory nestedSimpleFooFactory,
+ Provider<SimpleFoo.Factory> nestedSimpleFooFactoryProvider,
SimpleFooFactory nonNestedSimpleFooFactory,
ExtendedSimpleFooFactory extendedSimpleFooFactory,
FooFactory fooFactory,
AbstractFooFactory abstractFooFactory,
NoAssistedParametersFooFactory noAssistedParametersFooFactory) {
this.nestedSimpleFooFactory = nestedSimpleFooFactory;
+ this.nestedSimpleFooFactoryProvider = nestedSimpleFooFactoryProvider;
this.nonNestedSimpleFooFactory = nonNestedSimpleFooFactory;
this.extendedSimpleFooFactory = extendedSimpleFooFactory;
this.fooFactory = fooFactory;
@@ -265,6 +270,25 @@ public final class AssistedFactoryTest {
}
@Test
+ public void testNestedSimpleFooFactoryProvider() {
+ AssistedDep1 assistedDep1 = new AssistedDep1();
+ SimpleFoo simpleFoo1 =
+ DaggerAssistedFactoryTest_ParentComponent.create()
+ .nestedSimpleFooFactoryProvider()
+ .get()
+ .createSimpleFoo(assistedDep1);
+ assertThat(simpleFoo1.assistedDep).isEqualTo(assistedDep1);
+
+ AssistedDep2 assistedDep2 = new AssistedDep2();
+ SimpleFoo simpleFoo2 =
+ DaggerAssistedFactoryTest_ParentComponent.create()
+ .nestedSimpleFooFactoryProvider()
+ .get()
+ .createSimpleFoo(assistedDep2);
+ assertThat(simpleFoo2.assistedDep).isEqualTo(assistedDep2);
+ }
+
+ @Test
public void testNonNestedSimpleFooFactory() {
AssistedDep1 assistedDep1 = new AssistedDep1();
SimpleFoo simpleFoo =
@@ -323,6 +347,7 @@ public final class AssistedFactoryTest {
SomeEntryPoint someEntryPoint =
DaggerAssistedFactoryTest_ParentComponent.create().someEntryPoint();
assertThat(someEntryPoint.nestedSimpleFooFactory).isNotNull();
+ assertThat(someEntryPoint.nestedSimpleFooFactoryProvider).isNotNull();
assertThat(someEntryPoint.nonNestedSimpleFooFactory).isNotNull();
assertThat(someEntryPoint.extendedSimpleFooFactory).isNotNull();
assertThat(someEntryPoint.fooFactory).isNotNull();
diff --git a/javatests/dagger/functional/assisted/AssistedFactoryWithMultibindingsTest.java b/javatests/dagger/functional/assisted/AssistedFactoryWithMultibindingsTest.java
new file mode 100644
index 000000000..1e4bd60db
--- /dev/null
+++ b/javatests/dagger/functional/assisted/AssistedFactoryWithMultibindingsTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.functional.assisted;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import dagger.Component;
+import dagger.Module;
+import dagger.Provides;
+import dagger.Subcomponent;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import dagger.multibindings.IntoSet;
+import java.util.Set;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class AssistedFactoryWithMultibindingsTest {
+ @Component(modules = ParentModule.class)
+ interface ParentComponent {
+ // Factory for assisted injection binding with multi binding contribution.
+ MultibindingFooFactory multibindingFooFactory();
+
+ ChildComponent.Builder childComponent();
+ }
+
+ static final class AssistedDep {}
+
+ static final class MultibindingFoo {
+ private final AssistedDep assistedDep;
+ private final Set<String> stringSet;
+
+ @AssistedInject
+ MultibindingFoo(@Assisted AssistedDep assistedDep, Set<String> stringSet) {
+ this.assistedDep = assistedDep;
+ this.stringSet = stringSet;
+ }
+
+ AssistedDep assistedDep() {
+ return assistedDep;
+ }
+
+ Set<String> stringSet() {
+ return stringSet;
+ }
+ }
+
+ @Subcomponent(modules = ChildModule.class)
+ static interface ChildComponent {
+ MultibindingFooFactory multibindingFooFactory();
+
+ @Subcomponent.Builder
+ interface Builder {
+ ChildComponent build();
+ }
+ }
+
+ @Module(subcomponents = ChildComponent.class)
+ static class ParentModule {
+ @Provides
+ @IntoSet
+ String parentString() {
+ return "parent";
+ }
+ }
+
+ @Module
+ static class ChildModule {
+ @Provides
+ @IntoSet
+ String childString() {
+ return "child";
+ }
+ }
+
+ @AssistedFactory
+ interface MultibindingFooFactory {
+ MultibindingFoo createFoo(AssistedDep factoryAssistedDep1);
+ }
+
+ @Test
+ public void testAssistedFactoryWithMultibinding() {
+ AssistedDep assistedDep1 = new AssistedDep();
+ ParentComponent parent = DaggerAssistedFactoryWithMultibindingsTest_ParentComponent.create();
+ ChildComponent child = parent.childComponent().build();
+ MultibindingFoo foo1 = parent.multibindingFooFactory().createFoo(assistedDep1);
+ MultibindingFoo foo2 = child.multibindingFooFactory().createFoo(assistedDep1);
+ assertThat(foo1.assistedDep()).isEqualTo(foo2.assistedDep);
+ assertThat(foo1.stringSet()).containsExactly("parent");
+ assertThat(foo2.stringSet()).containsExactly("child", "parent");
+ }
+}
diff --git a/javatests/dagger/functional/assisted/BUILD b/javatests/dagger/functional/assisted/BUILD
index 5e663e7e9..b94b3576f 100644
--- a/javatests/dagger/functional/assisted/BUILD
+++ b/javatests/dagger/functional/assisted/BUILD
@@ -26,20 +26,20 @@ GenJavaTests(
javacopts = DOCLINT_HTML_AND_SYNTAX,
lib_javacopts = SOURCE_7_TARGET_7,
test_only_deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "@google_bazel_common//third_party/java/guava:testlib",
- "@google_bazel_common//third_party/java/truth",
- "@google_bazel_common//third_party/java/junit",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/util/concurrent",
+ "//third_party/java/guava:testlib",
+ "//third_party/java/truth",
+ "//third_party/java/junit",
"//javatests/dagger/functional/assisted/subpackage",
],
# NOTE: This should not depend on Guava or jsr305 to ensure that Dagger can be
# used without Guava and jsr305 deps.
deps = [
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/auto:factory",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/jsr330_inject",
+ "//third_party/java/auto:factory",
+ "//third_party/java/auto:value",
+ "//third_party/java/jsr330_inject",
],
)
diff --git a/javatests/dagger/functional/assisted/kotlin/BUILD b/javatests/dagger/functional/assisted/kotlin/BUILD
index 3c3421d2a..efb785e59 100644
--- a/javatests/dagger/functional/assisted/kotlin/BUILD
+++ b/javatests/dagger/functional/assisted/kotlin/BUILD
@@ -25,6 +25,7 @@ kt_jvm_library(
srcs = ["KotlinAssistedInjectionClasses.kt"],
deps = [
"//:dagger_with_compiler",
+ "//third_party/java/auto:factory",
],
)
@@ -38,8 +39,8 @@ GenJavaTests(
lib_javacopts = SOURCE_7_TARGET_7,
test_only_deps = [
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
# NOTE: This should not depend on Guava or jsr305 to ensure that Dagger can be
# used without Guava and jsr305 deps.
diff --git a/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionClasses.kt b/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionClasses.kt
index e78873d69..18cc43d2e 100644
--- a/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionClasses.kt
+++ b/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionClasses.kt
@@ -21,6 +21,7 @@ import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import javax.inject.Inject
+
class Dep @Inject constructor()
class AssistedDep
@@ -29,7 +30,9 @@ class AssistedDep
class Foo @AssistedInject constructor(val dep: Dep, @Assisted val assistedDep: AssistedDep)
/** Assisted injection for a kotlin data class. */
-data class FooData @AssistedInject constructor(val dep: Dep, @Assisted val assistedDep: AssistedDep)
+data class FooData
+@AssistedInject
+constructor(val dep: Dep, @Assisted val assistedDep: AssistedDep)
/** Assisted factory for a kotlin class */
@AssistedFactory
@@ -42,3 +45,15 @@ interface FooFactory {
interface FooDataFactory {
fun create(assistedDep: AssistedDep): FooData
}
+
+/** Kotlin classes for regression test of https://github.com/google/dagger/issues/3065. */
+class BarManager
+@AssistedInject
+internal constructor(@Assisted val bar: Bar, @Assisted val name: String) {
+ @AssistedFactory
+ interface Factory {
+ operator fun Bar.invoke(name: String): BarManager
+ }
+}
+
+class Bar
diff --git a/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionTest.java b/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionTest.java
index 7c597f858..b7a0a1b27 100644
--- a/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionTest.java
+++ b/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionTest.java
@@ -31,6 +31,9 @@ public final class KotlinAssistedInjectionTest {
FooFactory fooFactory();
FooDataFactory fooDataFactory();
+
+ BarManager.Factory barManagerFactory();
+
}
@Test
@@ -49,4 +52,15 @@ public final class KotlinAssistedInjectionTest {
FooData fooData = fooDataFactory.create(assistedDep);
assertThat(fooData.getAssistedDep()).isEqualTo(assistedDep);
}
+
+ @Test
+ public void testBarManager() {
+ BarManager.Factory barManagerFactory =
+ DaggerKotlinAssistedInjectionTest_TestComponent.create().barManagerFactory();
+ Bar bar = new Bar();
+ String name = "someName";
+ BarManager barManager = barManagerFactory.invoke(bar, name);
+ assertThat(barManager.getBar()).isEqualTo(bar);
+ assertThat(barManager.getName()).isEqualTo(name);
+ }
}
diff --git a/javatests/dagger/functional/assisted/subpackage/BUILD b/javatests/dagger/functional/assisted/subpackage/BUILD
index 644cf4410..8f0698417 100644
--- a/javatests/dagger/functional/assisted/subpackage/BUILD
+++ b/javatests/dagger/functional/assisted/subpackage/BUILD
@@ -22,6 +22,6 @@ java_library(
srcs = glob(["*.java"]),
deps = [
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/jsr330_inject",
+ "//third_party/java/jsr330_inject",
],
)
diff --git a/javatests/dagger/functional/binds/AccessesExposedComponent.java b/javatests/dagger/functional/binds/AccessesExposedComponent.java
index 61952b6b3..075ae9605 100644
--- a/javatests/dagger/functional/binds/AccessesExposedComponent.java
+++ b/javatests/dagger/functional/binds/AccessesExposedComponent.java
@@ -29,7 +29,7 @@ import javax.inject.Singleton;
* accessible from the component, but the left-hand-side is. If the right-hand-side is represented
* as a Provider (e.g. because it is scoped), then the raw {@code Provider.get()} will return {@link
* Object}, which must be downcasted to the type accessible from the component. See {@code
- * instanceRequiresCast()} in {@link dagger.internal.codegen.DelegateBindingExpression}.
+ * instanceRequiresCast()} in {@link dagger.internal.codegen.DelegateRequestRepresentation}.
*/
@Singleton
@Component(modules = ExposedModule.class)
diff --git a/javatests/dagger/functional/binds/BindsTest.java b/javatests/dagger/functional/binds/BindsTest.java
index 999c30327..e89dee60a 100644
--- a/javatests/dagger/functional/binds/BindsTest.java
+++ b/javatests/dagger/functional/binds/BindsTest.java
@@ -52,6 +52,7 @@ public class BindsTest {
assertThat(component.foosOfNumbers()).hasSize(2);
assertThat(component.objects()).hasSize(3);
assertThat(component.charSequences()).hasSize(5);
+ assertThat(component.notExposedString()).isEqualTo("not exposed");
assertThat(component.integerObjectMap())
.containsExactly(123, "123-string", 456, "456-string", 789, "789-string");
diff --git a/javatests/dagger/functional/binds/ScopedBindsTest.java b/javatests/dagger/functional/binds/ScopedBindsTest.java
new file mode 100644
index 000000000..90feb8bbb
--- /dev/null
+++ b/javatests/dagger/functional/binds/ScopedBindsTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.functional.binds;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import dagger.Binds;
+import dagger.Component;
+import dagger.Module;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ScopedBindsTest {
+ interface Foo {}
+
+ static final class FooImpl implements Foo {
+ @Inject FooImpl() {}
+ }
+
+ @Module
+ interface FooModule {
+ @Binds
+ @Singleton
+ Foo bindFoo(FooImpl impl);
+ }
+
+ @Component(modules = FooModule.class)
+ @Singleton
+ interface TestComponent {
+ Foo foo();
+
+ Provider<Foo> fooProvider();
+ }
+
+ @Test
+ public void fooVsFooProvider_sameInstanceTest() {
+ TestComponent component = DaggerScopedBindsTest_TestComponent.create();
+
+ // These should be the same instance because Foo is scoped
+ assertThat(component.foo()).isSameInstanceAs(component.fooProvider().get());
+ }
+}
diff --git a/javatests/dagger/functional/binds/TestComponent.java b/javatests/dagger/functional/binds/TestComponent.java
index 3299dc832..5e459be2c 100644
--- a/javatests/dagger/functional/binds/TestComponent.java
+++ b/javatests/dagger/functional/binds/TestComponent.java
@@ -18,16 +18,19 @@ package dagger.functional.binds;
import dagger.Component;
import dagger.functional.SomeQualifier;
+import dagger.functional.binds.subpackage.ExposedModule;
import java.util.Map;
import java.util.Set;
import javax.inject.Provider;
import javax.inject.Singleton;
@Singleton
-@Component(modules = SimpleBindingModule.class)
+@Component(modules = {SimpleBindingModule.class, ExposedModule.class})
public interface TestComponent {
Object object();
+ String notExposedString();
+
@SomeQualifier
Object reusableObject();
diff --git a/javatests/dagger/functional/binds/subpackage/ExposedModule.java b/javatests/dagger/functional/binds/subpackage/ExposedModule.java
index a2660d95c..5f428d9b6 100644
--- a/javatests/dagger/functional/binds/subpackage/ExposedModule.java
+++ b/javatests/dagger/functional/binds/subpackage/ExposedModule.java
@@ -19,8 +19,14 @@ package dagger.functional.binds.subpackage;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
+import dagger.multibindings.ElementsIntoSet;
+import dagger.multibindings.IntoSet;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
+import java.util.Set;
+import javax.inject.Provider;
import javax.inject.Singleton;
@Module
@@ -40,4 +46,24 @@ public abstract class ExposedModule {
@Binds
abstract ExposedInjectsMembers bindExposedInjectsMembers(
NotExposedInjectsMembers notExposedInjectsMembers);
+
+ @Provides
+ static Collection<NotExposed> provideNotExposedCollection(NotExposed notExposed) {
+ return Arrays.<NotExposed>asList(notExposed);
+ }
+
+ @Provides
+ @IntoSet // This is needed to ensure a provider field gets created for providing the Collection.
+ static NotExposed provideNotExposed(Provider<Collection<NotExposed>> collectionProvider) {
+ return collectionProvider.get().iterator().next();
+ }
+
+ @Binds
+ @ElementsIntoSet
+ abstract Set<NotExposed> bindCollectionOfNotExposeds(Collection<NotExposed> collection);
+
+ @Provides
+ static String provideString(Set<NotExposed> setOfFoo) {
+ return "not exposed";
+ }
}
diff --git a/javatests/dagger/functional/guava/BUILD b/javatests/dagger/functional/guava/BUILD
index ed8efd37e..157fd55a4 100644
--- a/javatests/dagger/functional/guava/BUILD
+++ b/javatests/dagger/functional/guava/BUILD
@@ -26,12 +26,12 @@ GenJavaTests(
javacopts = DOCLINT_HTML_AND_SYNTAX,
deps = [
"//:dagger_with_compiler",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/jsr305_annotations",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/jsr305_annotations",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/functional/jakarta/BUILD b/javatests/dagger/functional/jakarta/BUILD
new file mode 100644
index 000000000..7fc1ec23e
--- /dev/null
+++ b/javatests/dagger/functional/jakarta/BUILD
@@ -0,0 +1,34 @@
+# Copyright (C) 2022 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Description:
+# Functional tests for Dagger that depend on jakarta.inject.
+
+load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
+load("//:test_defs.bzl", "GenJavaTests")
+
+package(default_visibility = ["//:src"])
+
+# TODO(b/203233586): Replace with GenJavaTest
+GenJavaTests(
+ name = "SimpleJakartaTest",
+ srcs = ["SimpleJakartaTest.java"],
+ javacopts = DOCLINT_HTML_AND_SYNTAX,
+ deps = [
+ "//:dagger_with_compiler",
+ "@maven//:jakarta_inject_jakarta_inject_api",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ ],
+)
diff --git a/javatests/dagger/functional/jakarta/SimpleJakartaTest.java b/javatests/dagger/functional/jakarta/SimpleJakartaTest.java
new file mode 100644
index 000000000..e943eb0b8
--- /dev/null
+++ b/javatests/dagger/functional/jakarta/SimpleJakartaTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.functional.jakarta;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import dagger.Binds;
+import dagger.Component;
+import dagger.Module;
+import jakarta.inject.Inject;
+import jakarta.inject.Qualifier;
+import jakarta.inject.Scope;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class SimpleJakartaTest {
+
+ @Scope
+ public @interface TestScope {}
+
+ @Qualifier
+ public @interface TestQualifier {}
+
+ @TestScope
+ @Component(modules = TestModule.class)
+ interface TestComponent {
+ @TestQualifier Foo getQualifiedFoo();
+ }
+
+ public static final class Foo {
+ @Inject Foo() {}
+ }
+
+ @Module
+ interface TestModule {
+ // By binding this to itself, if the qualifier annotation isn't picked up, it will created a
+ // cycle.
+ @Binds
+ @TestScope
+ @TestQualifier
+ Foo bind(Foo impl);
+ }
+
+ @Test
+ public void testFooFactory() {
+ TestComponent testComponent = DaggerSimpleJakartaTest_TestComponent.create();
+ Foo foo = testComponent.getQualifiedFoo();
+
+ assertThat(foo).isSameInstanceAs(testComponent.getQualifiedFoo());
+ }
+}
diff --git a/javatests/dagger/functional/jdk8/BUILD b/javatests/dagger/functional/jdk8/BUILD
index 5e35c753f..cc0c722c8 100644
--- a/javatests/dagger/functional/jdk8/BUILD
+++ b/javatests/dagger/functional/jdk8/BUILD
@@ -20,19 +20,53 @@ load("//:test_defs.bzl", "GenJavaTests")
package(default_visibility = ["//:src"])
+java_library(
+ name = "optional_binding_components",
+ srcs = ["OptionalBindingComponents.java"],
+ javacopts = DOCLINT_HTML_AND_SYNTAX,
+ deps = [
+ "//third_party/java/auto:value",
+ "//:dagger_with_compiler",
+ "//third_party/java/jsr305_annotations",
+ ],
+)
+
+# TODO(b/203233586): Replace with GenJavaTest
+GenJavaTests(
+ name = "OptionalBindingComponentsEmptyTest",
+ srcs = ["OptionalBindingComponentsEmptyTest.java"],
+ javacopts = DOCLINT_HTML_AND_SYNTAX,
+ test_only_deps = [
+ ":optional_binding_components",
+
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ ],
+ deps = [
+ "//third_party/java/auto:value",
+ "//:dagger_with_compiler",
+ "//third_party/java/jsr305_annotations",
+ ],
+)
+
+# TODO(b/203233586): Replace with GenJavaTest
GenJavaTests(
- name = "jdk8_tests",
- srcs = glob(["**/*.java"]),
+ name = "OptionalBindingComponentsPresentTest",
+ srcs = ["OptionalBindingComponentsPresentTest.java"],
javacopts = DOCLINT_HTML_AND_SYNTAX,
test_only_deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ ":optional_binding_components",
+
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
deps = [
+ "//third_party/java/auto:value",
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/jsr305_annotations",
+ "//third_party/java/jsr305_annotations",
],
)
diff --git a/javatests/dagger/functional/jdk8/a/BUILD b/javatests/dagger/functional/jdk8/a/BUILD
new file mode 100644
index 000000000..f36417474
--- /dev/null
+++ b/javatests/dagger/functional/jdk8/a/BUILD
@@ -0,0 +1,41 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
+load("//:test_defs.bzl", "GenJavaTests")
+
+package(default_visibility = ["//:src"])
+
+# TODO(b/203233586): Replace with GenJavaTest
+GenJavaTests(
+ name = "OptionalBindingComponentsEmptyTest",
+ srcs = [
+ "OptionalBindingComponentsWithInaccessibleTypes.java",
+ "OptionalBindingComponentsWithInaccessibleTypesTest.java",
+ ],
+ javacopts = DOCLINT_HTML_AND_SYNTAX,
+ test_only_deps = [
+
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ ],
+ deps = [
+ "//third_party/java/auto:value",
+ "//:dagger_with_compiler",
+ "//third_party/java/jsr305_annotations",
+ "//javatests/dagger/functional/jdk8:optional_binding_components",
+ ],
+)
diff --git a/javatests/dagger/functional/kotlin/BUILD b/javatests/dagger/functional/kotlin/BUILD
index 529eb6992..2741c8e06 100644
--- a/javatests/dagger/functional/kotlin/BUILD
+++ b/javatests/dagger/functional/kotlin/BUILD
@@ -41,6 +41,7 @@ kt_jvm_library(
":java_qualifier",
"//:dagger_with_compiler",
"//javatests/dagger/functional/kotlin/processor:annotation",
+ "//third_party/java/auto:factory",
],
)
@@ -66,10 +67,10 @@ GenJavaTests(
srcs = glob(["*Test.java"]),
functional = True,
test_only_deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
deps = [
":foo_with_injected_qualifier",
diff --git a/javatests/dagger/functional/kotlin/DependsOnGeneratedCodeClasses.kt b/javatests/dagger/functional/kotlin/DependsOnGeneratedCodeClasses.kt
new file mode 100644
index 000000000..6fc8e24ae
--- /dev/null
+++ b/javatests/dagger/functional/kotlin/DependsOnGeneratedCodeClasses.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.functional.kotlin
+
+import com.google.auto.factory.AutoFactory
+import dagger.Component
+import javax.inject.Inject
+
+// TODO(bcorso): Merge this into the test once we support kt_jvm_test
+/** Defines kotlin classes for the associated test. */
+object DependsOnGeneratedCodeClasses {
+ @Component
+ abstract class TestComponent {
+ abstract fun bar(): Bar
+ }
+
+ class Bar @Inject constructor(
+ )
+
+ @AutoFactory class SomeClass
+}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleApplication.java b/javatests/dagger/functional/kotlin/DependsOnGeneratedCodeTest.java
index a163d8c5e..d85aee826 100644
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleApplication.java
+++ b/javatests/dagger/functional/kotlin/DependsOnGeneratedCodeTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Dagger Authors.
+ * Copyright (C) 2021 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,19 +14,21 @@
* limitations under the License.
*/
-package dagger.hilt.android.example.gradle.simple;
+package dagger.functional.kotlin;
-import android.app.Application;
-import dagger.hilt.android.HiltAndroidApp;
-import javax.inject.Inject;
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
/**
- * A simple, skeletal application that demonstrates a dependency-injected application using the
- * utilities in {@code Hilt} in Android.
+ * @see <a href="https://github.com/google/dagger/issues/3075">Issue #3075</a>
*/
-@HiltAndroidApp
-public class SimpleApplication extends Application {
-
- // Shows that we can inject SingletonComponent bindings into an application.
- @Inject @Model String model;
+@RunWith(JUnit4.class)
+public class DependsOnGeneratedCodeTest {
+ @Test
+ public void testComponentDependsOnGeneratedCode() {
+ assertThat(DaggerDependsOnGeneratedCodeClasses_TestComponent.create().bar()).isNotNull();
+ }
}
diff --git a/javatests/dagger/functional/kotlin/processor/BUILD b/javatests/dagger/functional/kotlin/processor/BUILD
index 31a45c75a..25273e226 100644
--- a/javatests/dagger/functional/kotlin/processor/BUILD
+++ b/javatests/dagger/functional/kotlin/processor/BUILD
@@ -26,8 +26,8 @@ kt_jvm_library(
name = "processor",
srcs = ["TestGeneratedTypeProcessor.kt"],
deps = [
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/javapoet",
+ "//third_party/java/auto:service",
+ "//third_party/java/javapoet",
],
)
diff --git a/javatests/dagger/functional/names/BUILD b/javatests/dagger/functional/names/BUILD
new file mode 100644
index 000000000..5de751009
--- /dev/null
+++ b/javatests/dagger/functional/names/BUILD
@@ -0,0 +1,33 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Description:
+# Functional tests for Dagger testing various name conflicts.
+
+load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
+load("//:test_defs.bzl", "GenJavaTests")
+
+package(default_visibility = ["//:src"])
+
+# TODO(b/203233586): Replace with GenJavaTest
+GenJavaTests(
+ name = "ComponentFactoryNameConflictsTest",
+ srcs = ["ComponentFactoryNameConflictsTest.java"],
+ javacopts = DOCLINT_HTML_AND_SYNTAX,
+ deps = [
+ "//:dagger_with_compiler",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ ],
+)
diff --git a/javatests/dagger/functional/names/ComponentFactoryNameConflictsTest.java b/javatests/dagger/functional/names/ComponentFactoryNameConflictsTest.java
new file mode 100644
index 000000000..14acd0e5a
--- /dev/null
+++ b/javatests/dagger/functional/names/ComponentFactoryNameConflictsTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.functional.names;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import dagger.Component;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** This is a regression test for https://github.com/google/dagger/issues/3069. */
+@RunWith(JUnit4.class)
+public final class ComponentFactoryNameConflictsTest {
+
+ // A class name "Create" so the private method name in fastInit mode conflicts with the create()
+ // factory method.
+ public static final class Create {
+ // Take a dependency so we don't just inline this directly.
+ @Inject Create(Provider<CreateUsage> provider) {}
+ }
+
+ // Use another class to make sure the create class is used but not a direct component entry point.
+ public static final class CreateUsage {
+ @Inject CreateUsage(Create create) {}
+ }
+
+ @Component
+ interface CreateComponent {
+ CreateUsage getCreateUsage();
+ }
+
+ @Test
+ public void testCreate() {
+ CreateComponent testComponent =
+ DaggerComponentFactoryNameConflictsTest_CreateComponent.create();
+ CreateUsage createUsage = testComponent.getCreateUsage();
+ assertThat(createUsage).isNotNull();
+ }
+
+ // A class name "Builder" so the private method name in fastInit mode conflicts with the builder()
+ // factory method.
+ public static final class Builder {
+ // Take a dependency so we don't just inline this directly.
+ @Inject Builder(Provider<BuilderUsage> provider) {}
+ }
+
+ public static final class BuilderUsage {
+ @Inject BuilderUsage(Builder create) {}
+ }
+
+ @Component
+ interface BuilderComponent {
+ BuilderUsage getBuilderUsage();
+
+ @Component.Builder
+ interface OtherBuilder {
+ BuilderComponent build();
+ }
+ }
+
+ // Technically this test passes without claiming the name "builder" when we add the method (even
+ // though we do anyway for safety) because KeyVariableNamer actually hardcodes a list of common
+ // names to avoid which includes "builder".
+ @Test
+ public void testBuilder() {
+ BuilderComponent testComponent =
+ DaggerComponentFactoryNameConflictsTest_BuilderComponent.builder().build();
+ BuilderUsage builderUsage = testComponent.getBuilderUsage();
+ assertThat(builderUsage).isNotNull();
+ }
+}
diff --git a/javatests/dagger/functional/producers/BUILD b/javatests/dagger/functional/producers/BUILD
index f69b3cb85..6f2551e34 100644
--- a/javatests/dagger/functional/producers/BUILD
+++ b/javatests/dagger/functional/producers/BUILD
@@ -32,15 +32,15 @@ GenJavaTests(
lib_javacopts = SOURCE_7_TARGET_7,
deps = [
"//:producers_with_compiler",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/jsr305_annotations",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/mockito",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/util/concurrent",
+ "//third_party/java/jsr305_annotations",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/junit",
+ "//third_party/java/mockito",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/functional/spi/BUILD b/javatests/dagger/functional/spi/BUILD
index 8119bdd7f..dad3de668 100644
--- a/javatests/dagger/functional/spi/BUILD
+++ b/javatests/dagger/functional/spi/BUILD
@@ -24,11 +24,11 @@ java_plugin(
name = "test_plugin",
srcs = ["TestPlugin.java"],
deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
"//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/javapoet",
+ "//third_party/java/auto:service",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
@@ -45,12 +45,12 @@ GenJavaTests(
),
functional = 0,
test_only_deps = [
- "@google_bazel_common//third_party/java/truth",
- "@google_bazel_common//third_party/java/junit",
+ "//third_party/java/truth",
+ "//third_party/java/junit",
],
deps = [
":test_lib",
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/guava",
+ "//third_party/java/guava",
],
)
diff --git a/javatests/dagger/functional/sub/NestedType.java b/javatests/dagger/functional/sub/NestedType.java
new file mode 100644
index 000000000..999017a7d
--- /dev/null
+++ b/javatests/dagger/functional/sub/NestedType.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.functional.sub;
+
+// Move this back to dagger.functional package once the javapoet clash bug gets fixed.
+// https://github.com/square/javapoet/issues/860
+public interface NestedType {}
diff --git a/javatests/dagger/functional/tck/BUILD b/javatests/dagger/functional/tck/BUILD
index 9cad2a017..ede975921 100644
--- a/javatests/dagger/functional/tck/BUILD
+++ b/javatests/dagger/functional/tck/BUILD
@@ -35,8 +35,8 @@ GenJavaTests(
],
deps = [
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/jsr330_inject:tck",
- "@google_bazel_common//third_party/java/junit",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/jsr330_inject:tck",
+ "//third_party/java/junit",
],
)
diff --git a/javatests/dagger/hilt/android/ActivityInjectedSavedStateViewModelTest.java b/javatests/dagger/hilt/android/ActivityInjectedSavedStateViewModelTest.java
index 03aa3248d..e8ba0463f 100644
--- a/javatests/dagger/hilt/android/ActivityInjectedSavedStateViewModelTest.java
+++ b/javatests/dagger/hilt/android/ActivityInjectedSavedStateViewModelTest.java
@@ -19,13 +19,13 @@ package dagger.hilt.android;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.google.common.truth.Truth.assertThat;
-import androidx.lifecycle.SavedStateHandle;
-import androidx.lifecycle.ViewModel;
-import androidx.lifecycle.ViewModelProvider;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import androidx.fragment.app.FragmentActivity;
+import androidx.lifecycle.SavedStateHandle;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import dagger.Module;
diff --git a/javatests/dagger/hilt/android/ActivityInjectedViewModelTest.java b/javatests/dagger/hilt/android/ActivityInjectedViewModelTest.java
index 0e75741c4..5f88ca6af 100644
--- a/javatests/dagger/hilt/android/ActivityInjectedViewModelTest.java
+++ b/javatests/dagger/hilt/android/ActivityInjectedViewModelTest.java
@@ -19,11 +19,11 @@ package dagger.hilt.android;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.google.common.truth.Truth.assertThat;
-import androidx.lifecycle.ViewModel;
-import androidx.lifecycle.ViewModelProvider;
import android.content.Intent;
import android.os.Build;
import androidx.fragment.app.FragmentActivity;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import dagger.Module;
diff --git a/javatests/dagger/hilt/android/ActivityRetainedClearedListenerTest.java b/javatests/dagger/hilt/android/ActivityRetainedClearedListenerTest.java
index 286998c19..4530a7249 100644
--- a/javatests/dagger/hilt/android/ActivityRetainedClearedListenerTest.java
+++ b/javatests/dagger/hilt/android/ActivityRetainedClearedListenerTest.java
@@ -19,9 +19,9 @@ package dagger.hilt.android;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
-import androidx.lifecycle.Lifecycle.State;
import android.os.Build;
import androidx.fragment.app.FragmentActivity;
+import androidx.lifecycle.Lifecycle.State;
import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import dagger.hilt.android.ActivityRetainedLifecycle.OnClearedListener;
diff --git a/javatests/dagger/hilt/android/AliasOfMultipleScopesTest.java b/javatests/dagger/hilt/android/AliasOfMultipleScopesTest.java
new file mode 100644
index 000000000..032d5464c
--- /dev/null
+++ b/javatests/dagger/hilt/android/AliasOfMultipleScopesTest.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android;
+
+import static com.google.common.truth.Truth.assertThat;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+import android.content.Context;
+import android.os.Build;
+import androidx.activity.ComponentActivity;
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import dagger.Module;
+import dagger.Provides;
+import dagger.hilt.DefineComponent;
+import dagger.hilt.EntryPoint;
+import dagger.hilt.EntryPoints;
+import dagger.hilt.InstallIn;
+import dagger.hilt.android.components.ActivityComponent;
+import dagger.hilt.android.qualifiers.ApplicationContext;
+import dagger.hilt.android.scopes.ActivityScoped;
+import dagger.hilt.android.testing.HiltAndroidRule;
+import dagger.hilt.android.testing.HiltAndroidTest;
+import dagger.hilt.android.testing.HiltTestApplication;
+import dagger.hilt.components.SingletonComponent;
+import dagger.hilt.migration.AliasOf;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Scope;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+@HiltAndroidTest
+@RunWith(AndroidJUnit4.class)
+@Config(sdk = Build.VERSION_CODES.P, application = HiltTestApplication.class)
+public final class AliasOfMultipleScopesTest {
+
+ @Rule public final HiltAndroidRule rule = new HiltAndroidRule(this);
+
+ @Inject @ApplicationContext Context context;
+ @Inject CustomComponent.Builder customComponentBuilder;
+
+ @Scope
+ @Retention(CLASS)
+ @Target({ElementType.METHOD, ElementType.TYPE})
+ public @interface CustomScoped {}
+
+ @DefineComponent(parent = SingletonComponent.class)
+ @CustomScoped
+ public interface CustomComponent {
+ @DefineComponent.Builder
+ public interface Builder {
+ CustomComponent build();
+ }
+ }
+
+ @Scope
+ @AliasOf({ActivityScoped.class, CustomScoped.class})
+ public @interface AliasScoped {}
+
+ public interface UnscopedDep {}
+
+ public interface ActivityScopedDep {}
+
+ public interface CustomScopedDep {}
+
+ public interface AliasScopedDep {}
+
+ @Module
+ @InstallIn(SingletonComponent.class)
+ interface SingletonTestModule {
+ @Provides
+ static UnscopedDep unscopedDep() {
+ return new UnscopedDep() {};
+ }
+ }
+
+ @Module
+ @InstallIn(ActivityComponent.class)
+ interface ActivityTestModule {
+ @Provides
+ @ActivityScoped
+ static ActivityScopedDep activityScopedDep() {
+ return new ActivityScopedDep() {};
+ }
+
+ @Provides
+ @AliasScoped
+ static AliasScopedDep aliasScopedDep() {
+ return new AliasScopedDep() {};
+ }
+ }
+
+ @Module
+ @InstallIn(CustomComponent.class)
+ interface CustomTestModule {
+ @Provides
+ @CustomScoped
+ static CustomScopedDep customScopedDep() {
+ return new CustomScopedDep() {};
+ }
+
+ @Provides
+ @AliasScoped
+ static AliasScopedDep aliasScopedDep() {
+ return new AliasScopedDep() {};
+ }
+ }
+
+ /** An activity to test injection. */
+ @AndroidEntryPoint(ComponentActivity.class)
+ public static final class TestActivity extends Hilt_AliasOfMultipleScopesTest_TestActivity {
+ @Inject Provider<UnscopedDep> unscopedDep;
+ @Inject Provider<ActivityScopedDep> activityScopedDep;
+ @Inject Provider<AliasScopedDep> aliasScopedDep;
+ }
+
+ @EntryPoint
+ @InstallIn(SingletonComponent.class)
+ interface CustomComponentBuilderEntryPoint {
+ CustomComponent.Builder customComponentBuilder();
+ }
+
+ @EntryPoint
+ @InstallIn(CustomComponent.class)
+ interface CustomComponentEntryPoint {
+ Provider<UnscopedDep> unscopedDep();
+
+ Provider<CustomScopedDep> customScopedDep();
+
+ Provider<AliasScopedDep> aliasScopedDep();
+ }
+
+ @Before
+ public void setUp() {
+ rule.inject();
+ }
+
+ @Test
+ public void testActivityScoped() {
+ try (ActivityScenario<TestActivity> scenario = ActivityScenario.launch(TestActivity.class)) {
+ scenario.onActivity(
+ activity -> {
+ assertThat(activity.unscopedDep.get()).isNotSameInstanceAs(activity.unscopedDep.get());
+ assertThat(activity.activityScopedDep.get())
+ .isSameInstanceAs(activity.activityScopedDep.get());
+ assertThat(activity.aliasScopedDep.get())
+ .isSameInstanceAs(activity.aliasScopedDep.get());
+ });
+ }
+ }
+
+ @Test
+ public void testCustomScoped() {
+ CustomComponent customComponent =
+ EntryPoints.get(context, CustomComponentBuilderEntryPoint.class)
+ .customComponentBuilder()
+ .build();
+ CustomComponentEntryPoint entryPoint =
+ EntryPoints.get(customComponent, CustomComponentEntryPoint.class);
+ assertThat(entryPoint.unscopedDep().get()).isNotSameInstanceAs(entryPoint.unscopedDep().get());
+ assertThat(entryPoint.customScopedDep().get())
+ .isSameInstanceAs(entryPoint.customScopedDep().get());
+ assertThat(entryPoint.aliasScopedDep().get())
+ .isSameInstanceAs(entryPoint.aliasScopedDep().get());
+ }
+}
diff --git a/javatests/dagger/hilt/android/AndroidManifest.xml b/javatests/dagger/hilt/android/AndroidManifest.xml
index 7f6ede633..5195ca61c 100644
--- a/javatests/dagger/hilt/android/AndroidManifest.xml
+++ b/javatests/dagger/hilt/android/AndroidManifest.xml
@@ -1,4 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
package="dagger.hilt.android">
<uses-sdk android:minSdkVersion="14" />
@@ -6,42 +7,71 @@
<application>
<activity
android:name=".ActivityInjectedSavedStateViewModelTest$TestActivity"
- android:exported="false"/>
+ android:exported="false"
+ tools:ignore="MissingClass"/>
<activity
android:name=".ActivityInjectedSavedStateViewModelTest$TestActivityWithSuperActivity"
- android:exported="false"/>
+ android:exported="false"
+ tools:ignore="MissingClass"/>
<activity
android:name=".ActivityInjectedViewModelTest$TestActivity"
- android:exported="false"/>
+ android:exported="false"
+ tools:ignore="MissingClass"/>
<activity
android:name=".ActivityRetainedClearedListenerTest$TestActivity"
- android:exported="false"/>
+ android:exported="false"
+ tools:ignore="MissingClass"/>
<activity
android:name=".ActivityScenarioRuleTest$TestActivity"
- android:exported="false"/>
+ android:exported="false"
+ tools:ignore="MissingClass"/>
+ <activity
+ android:name=".AliasOfMultipleScopesTest$TestActivity"
+ android:exported="false"
+ tools:ignore="MissingClass"/>
<activity
android:name=".DefaultViewModelFactoryTest$TestActivity"
- android:exported="false"/>
+ android:exported="false"
+ tools:ignore="MissingClass"/>
+ <activity
+ android:name=".OptionalInjectTestClasses$TestActivity"
+ android:exported="false"
+ tools:ignore="MissingClass"/>
+ <activity
+ android:name=".OptionalInjectTestClasses$NonOptionalSubclassActivity"
+ android:exported="false"
+ tools:ignore="MissingClass"/>
+ <activity
+ android:name=".OptionalInjectTestClasses$OptionalSubclassActivity"
+ android:exported="false"
+ tools:ignore="MissingClass"/>
<activity
android:name=".QualifierInKotlinFieldsTest$TestActivity"
- android:exported="false"/>
+ android:exported="false"
+ tools:ignore="MissingClass"/>
<activity
android:name=".UsesSharedComponent1Test$TestActivity"
- android:exported="false"/>
+ android:exported="false"
+ tools:ignore="MissingClass"/>
<activity
android:name=".UsesSharedComponent2Test$TestActivity"
- android:exported="false"/>
+ android:exported="false"
+ tools:ignore="MissingClass"/>
<activity
android:name=".UsesSharedComponentEnclosedTest$EnclosedTest$TestActivity"
- android:exported="false"/>
+ android:exported="false"
+ tools:ignore="MissingClass"/>
<activity
android:name=".ViewModelScopedTest$TestActivity"
- android:exported="false"/>
+ android:exported="false"
+ tools:ignore="MissingClass"/>
<activity
android:name=".ViewModelWithBaseTest$TestActivity"
- android:exported="false"/>
+ android:exported="false"
+ tools:ignore="MissingClass"/>
<activity
android:name="dagger.hilt.android.testsubpackage.UsesSharedComponent1Test$TestActivity"
- android:exported="false"/>
+ android:exported="false"
+ tools:ignore="MissingClass"/>
</application>
</manifest>
diff --git a/javatests/dagger/hilt/android/BUILD b/javatests/dagger/hilt/android/BUILD
index 1f9bd0809..2aadb7d47 100644
--- a/javatests/dagger/hilt/android/BUILD
+++ b/javatests/dagger/hilt/android/BUILD
@@ -30,6 +30,7 @@ android_library(
"MultiTestRootExternalModules.java",
],
exports_manifest = 1,
+ javacopts = ["-Adagger.hilt.shareTestComponents=true"],
manifest = "AndroidManifest.xml",
deps = [
"//:android_local_test_exports",
@@ -42,7 +43,7 @@ android_library(
"//java/dagger/hilt/android/testing:custom_test_application",
"//java/dagger/hilt/android/testing:hilt_android_test",
"//java/dagger/hilt/android/testing:uninstall_modules",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/truth",
"@maven//:androidx_test_core",
"@maven//:androidx_test_ext_junit",
"@maven//:junit_junit",
@@ -91,6 +92,57 @@ android_local_test(
)
android_local_test(
+ name = "AliasOfMultipleScopesTest",
+ srcs = ["AliasOfMultipleScopesTest.java"],
+ manifest = "AndroidManifest.xml",
+ manifest_values = {
+ "minSdkVersion": "14",
+ },
+ deps = [
+ "//:android_local_test_exports",
+ "//java/dagger/hilt:define_component",
+ "//java/dagger/hilt:entry_point",
+ "//java/dagger/hilt:install_in",
+ "//java/dagger/hilt/android:android_entry_point",
+ "//java/dagger/hilt/android:package_info",
+ "//java/dagger/hilt/android/qualifiers",
+ "//java/dagger/hilt/android/scopes",
+ "//java/dagger/hilt/android/testing:hilt_android_rule",
+ "//java/dagger/hilt/android/testing:hilt_android_test",
+ "//java/dagger/hilt/migration:alias_of",
+ "//third_party/java/truth",
+ ],
+)
+
+android_library(
+ name = "custom_inject_classes",
+ srcs = ["CustomInjectClasses.java"],
+ deps = [
+ "//:dagger_with_compiler",
+ "//java/dagger/hilt:install_in",
+ "//java/dagger/hilt/android:hilt_android_app",
+ "//java/dagger/hilt/android:package_info",
+ "//java/dagger/hilt/android/migration:custom_inject",
+ "//third_party/java/jsr330_inject",
+ ],
+)
+
+android_local_test(
+ name = "CustomInjectTest",
+ size = "small",
+ srcs = ["CustomInjectTest.java"],
+ manifest_values = {
+ "minSdkVersion": "14",
+ },
+ deps = [
+ ":custom_inject_classes",
+ "//:android_local_test_exports",
+ "//java/dagger/hilt/android:package_info",
+ "//third_party/java/truth",
+ ],
+)
+
+android_local_test(
name = "EarlyEntryPointHiltAndroidAppRuntimeTest",
size = "small",
srcs = ["EarlyEntryPointHiltAndroidAppRuntimeTest.java"],
@@ -103,7 +155,7 @@ android_local_test(
"//java/dagger/hilt:entry_point",
"//java/dagger/hilt/android:early_entry_point",
"//java/dagger/hilt/android:package_info",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/truth",
"@maven//:junit_junit",
],
)
@@ -138,7 +190,7 @@ android_local_test(
"//java/dagger/hilt/android:early_entry_point",
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/testing:hilt_android_test",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/truth",
],
)
@@ -161,7 +213,7 @@ android_local_test(
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/testing:custom_test_application",
"//java/dagger/hilt/android/testing:hilt_android_test",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/truth",
],
)
@@ -180,7 +232,27 @@ android_local_test(
"//java/dagger/hilt/android:early_entry_point",
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/testing:hilt_android_test",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/truth",
+ ],
+)
+
+android_local_test(
+ name = "FragmentContextOnAttachTest",
+ size = "small",
+ srcs = ["FragmentContextOnAttachTest.java"],
+ manifest_values = {
+ "minSdkVersion": "14",
+ },
+ deps = [
+ "//:android_local_test_exports",
+ "//:dagger_with_compiler",
+ "//java/dagger/hilt:install_in",
+ "//java/dagger/hilt/android:android_entry_point",
+ "//java/dagger/hilt/android:package_info",
+ "//java/dagger/hilt/android/flags:fragment_get_context_fix",
+ "//java/dagger/hilt/android/testing:bind_value",
+ "//java/dagger/hilt/android/testing:hilt_android_test",
+ "//third_party/java/truth",
],
)
@@ -203,11 +275,10 @@ android_local_test(
},
deps = [
"//:android_local_test_exports",
- "//:dagger_with_compiler",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android:package_info",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/truth",
],
)
@@ -223,8 +294,8 @@ android_local_test(
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/testing:hilt_android_test",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/truth",
],
)
@@ -242,8 +313,8 @@ android_local_test(
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/testing:hilt_android_test",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/truth",
],
)
@@ -261,8 +332,8 @@ android_local_test(
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/testing:hilt_android_test",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
@@ -288,12 +359,11 @@ android_local_test(
deps = [
"//:android_local_test_exports",
"//:dagger_with_compiler",
- "//java/dagger/hilt:entry_point",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/testing:hilt_android_test",
"//javatests/dagger/hilt/testmodules",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/truth",
],
)
@@ -307,15 +377,14 @@ android_local_test(
deps = [
"//:android_local_test_exports",
"//:dagger_with_compiler",
- "//java/dagger/hilt:entry_point",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/lifecycle",
"//java/dagger/hilt/android/testing:bind_value",
"//java/dagger/hilt/android/testing:hilt_android_test",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/truth",
"@maven//:androidx_activity_activity",
"@maven//:androidx_fragment_fragment",
"@maven//:androidx_lifecycle_lifecycle_common",
@@ -339,8 +408,8 @@ android_local_test(
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/testing:hilt_android_test",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/truth",
"@maven//:androidx_activity_activity",
"@maven//:androidx_fragment_fragment",
"@maven//:androidx_lifecycle_lifecycle_common",
@@ -361,6 +430,75 @@ kt_android_library(
)
android_local_test(
+ name = "OptionalInjectWithHiltTest",
+ size = "small",
+ srcs = [
+ "OptionalInjectWithHiltTest.java",
+ ],
+ manifest = "AndroidManifest.xml",
+ manifest_values = {
+ "minSdkVersion": "14",
+ },
+ deps = [
+ ":OptionalInjectTestClasses",
+ "//:android_local_test_exports",
+ "//java/dagger/hilt/android:android_entry_point",
+ "//java/dagger/hilt/android:package_info",
+ "//java/dagger/hilt/android/migration:optional_inject",
+ "//java/dagger/hilt/android/testing:hilt_android_test",
+ "//third_party/java/truth",
+ "@maven//:androidx_activity_activity",
+ "@maven//:androidx_fragment_fragment",
+ "@maven//:androidx_lifecycle_lifecycle_common",
+ "@maven//:androidx_lifecycle_lifecycle_viewmodel",
+ "@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
+ ],
+)
+
+android_local_test(
+ name = "OptionalInjectWithoutHiltTest",
+ size = "small",
+ srcs = [
+ "OptionalInjectWithoutHiltTest.java",
+ ],
+ manifest = "AndroidManifest.xml",
+ manifest_values = {
+ "minSdkVersion": "14",
+ },
+ deps = [
+ ":OptionalInjectTestClasses",
+ "//:android_local_test_exports",
+ "//java/dagger/hilt/android:package_info",
+ "//java/dagger/hilt/android/migration:optional_inject",
+ "//third_party/java/truth",
+ "@maven//:androidx_activity_activity",
+ "@maven//:androidx_fragment_fragment",
+ "@maven//:androidx_lifecycle_lifecycle_common",
+ "@maven//:androidx_lifecycle_lifecycle_viewmodel",
+ "@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
+ ],
+)
+
+android_library(
+ name = "OptionalInjectTestClasses",
+ srcs = ["OptionalInjectTestClasses.java"],
+ manifest = "AndroidManifest.xml",
+ deps = [
+ "//:dagger_with_compiler",
+ "//java/dagger/hilt:install_in",
+ "//java/dagger/hilt/android:android_entry_point",
+ "//java/dagger/hilt/android:package_info",
+ "//java/dagger/hilt/android/migration:optional_inject",
+ "//third_party/java/jsr330_inject",
+ "@maven//:androidx_activity_activity",
+ "@maven//:androidx_fragment_fragment",
+ "@maven//:androidx_lifecycle_lifecycle_common",
+ "@maven//:androidx_lifecycle_lifecycle_viewmodel",
+ "@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
+ ],
+)
+
+android_local_test(
name = "ActivityRetainedClearedListenerTest",
srcs = ["ActivityRetainedClearedListenerTest.java"],
manifest = "AndroidManifest.xml",
@@ -370,14 +508,13 @@ android_local_test(
deps = [
"//:android_local_test_exports",
"//:dagger_with_compiler",
- "//java/dagger/hilt:entry_point",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android:activity_retained_lifecycle",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/testing:hilt_android_test",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/truth",
"@maven//:androidx_activity_activity",
"@maven//:androidx_fragment_fragment",
"@maven//:androidx_lifecycle_lifecycle_common",
@@ -397,13 +534,12 @@ android_local_test(
deps = [
"//:android_local_test_exports",
"//:dagger_with_compiler",
- "//java/dagger/hilt:entry_point",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/testing:hilt_android_test",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/truth",
"@maven//:androidx_activity_activity",
"@maven//:androidx_fragment_fragment",
"@maven//:androidx_lifecycle_lifecycle_common",
@@ -423,15 +559,14 @@ android_local_test(
deps = [
"//:android_local_test_exports",
"//:dagger_with_compiler",
- "//java/dagger/hilt:entry_point",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/lifecycle",
"//java/dagger/hilt/android/scopes",
"//java/dagger/hilt/android/testing:hilt_android_test",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/truth",
"@maven//:androidx_activity_activity",
"@maven//:androidx_fragment_fragment",
"@maven//:androidx_lifecycle_lifecycle_common",
@@ -451,14 +586,13 @@ android_local_test(
deps = [
"//:android_local_test_exports",
"//:dagger_with_compiler",
- "//java/dagger/hilt:entry_point",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/lifecycle",
"//java/dagger/hilt/android/testing:hilt_android_test",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/truth",
"@maven//:androidx_activity_activity",
"@maven//:androidx_fragment_fragment",
"@maven//:androidx_lifecycle_lifecycle_common",
@@ -478,14 +612,12 @@ android_local_test(
deps = [
"//:android_local_test_exports",
"//:dagger_with_compiler",
- "//java/dagger/hilt:entry_point",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android:package_info",
"//java/dagger/hilt/android/testing:hilt_android_test",
- "//java/dagger/internal/guava:base-android",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/truth",
"@maven//:junit_junit",
],
)
@@ -502,7 +634,7 @@ android_library(
"//java/dagger/hilt:entry_point",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android/components",
- "@google_bazel_common//third_party/java/jsr330_inject",
+ "//third_party/java/jsr330_inject",
],
)
@@ -548,8 +680,8 @@ android_library(
"//java/dagger/hilt/android/testing:custom_test_application",
"//java/dagger/hilt/android/testing:hilt_android_test",
"//java/dagger/hilt/android/testing:uninstall_modules",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/truth",
"@maven//:androidx_test_core",
"@maven//:androidx_test_ext_junit",
"@maven//:junit_junit",
@@ -578,8 +710,8 @@ android_library(
"//java/dagger/hilt/android/testing:bind_value",
"//java/dagger/hilt/android/testing:hilt_android_test",
"//java/dagger/hilt/testing:test_install_in",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/truth",
"@maven//:androidx_test_core",
"@maven//:androidx_test_ext_junit",
"@maven//:junit_junit",
diff --git a/javatests/dagger/hilt/android/CustomInjectClasses.java b/javatests/dagger/hilt/android/CustomInjectClasses.java
new file mode 100644
index 000000000..482b70bc9
--- /dev/null
+++ b/javatests/dagger/hilt/android/CustomInjectClasses.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android;
+
+import android.app.Application;
+import dagger.Module;
+import dagger.Provides;
+import dagger.hilt.InstallIn;
+import dagger.hilt.android.migration.CustomInject;
+import dagger.hilt.android.migration.CustomInjection;
+import dagger.hilt.components.SingletonComponent;
+import javax.inject.Inject;
+
+/**
+ * Classes for CustomInjectTest. This is in a separate build target because otherwise
+ * robolectric does not recognize the application class as extending application due to order of
+ * class generation.
+ */
+final class CustomInjectClasses {
+
+ @Module
+ @InstallIn(SingletonComponent.class)
+ static final class TestModule {
+ @Provides
+ static Integer provideInt() {
+ return 9;
+ }
+ }
+
+ @CustomInject
+ @HiltAndroidApp(Application.class)
+ static final class TestApplication extends Hilt_CustomInjectClasses_TestApplication {
+
+ @Inject Integer intValue;
+
+ void inject() {
+ CustomInjection.inject(this);
+ }
+ }
+}
diff --git a/javatests/dagger/hilt/android/CustomInjectTest.java b/javatests/dagger/hilt/android/CustomInjectTest.java
new file mode 100644
index 000000000..38512a037
--- /dev/null
+++ b/javatests/dagger/hilt/android/CustomInjectTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Build;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import dagger.hilt.android.CustomInjectClasses.TestApplication;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+/** Tests for @CustomInject. */
+@RunWith(AndroidJUnit4.class)
+// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
+@Config(
+ sdk = Build.VERSION_CODES.P,
+ application = TestApplication.class)
+public class CustomInjectTest {
+
+ @Test
+ public void testInjection() {
+ TestApplication app = (TestApplication) ApplicationProvider.getApplicationContext();
+
+ assertThat(app.intValue).isNull();
+ app.inject();
+ assertThat(app.intValue).isEqualTo(9);
+ }
+}
diff --git a/javatests/dagger/hilt/android/DefaultViewModelFactoryTest.java b/javatests/dagger/hilt/android/DefaultViewModelFactoryTest.java
index 78cd5688a..0d59e24b7 100644
--- a/javatests/dagger/hilt/android/DefaultViewModelFactoryTest.java
+++ b/javatests/dagger/hilt/android/DefaultViewModelFactoryTest.java
@@ -18,11 +18,11 @@ package dagger.hilt.android;
import static com.google.common.truth.Truth.assertThat;
-import androidx.lifecycle.ViewModel;
-import androidx.lifecycle.ViewModelProvider;
import android.os.Build;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import dagger.hilt.android.lifecycle.HiltViewModel;
diff --git a/javatests/dagger/hilt/android/EntryPointAccessorsTest.kt b/javatests/dagger/hilt/android/EntryPointAccessorsTest.kt
new file mode 100644
index 000000000..fb4afc077
--- /dev/null
+++ b/javatests/dagger/hilt/android/EntryPointAccessorsTest.kt
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android
+
+import android.content.Context
+import android.os.Build
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentActivity
+import android.view.View
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.EntryPoint
+import dagger.hilt.InstallIn
+import dagger.hilt.android.components.ActivityComponent
+import dagger.hilt.android.components.FragmentComponent
+import dagger.hilt.android.components.ViewComponent
+import dagger.hilt.android.testing.HiltAndroidRule
+import dagger.hilt.android.testing.HiltAndroidTest
+import dagger.hilt.android.testing.HiltTestApplication
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Qualifier
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.Robolectric
+import org.robolectric.annotation.Config
+
+@HiltAndroidTest
+@RunWith(AndroidJUnit4::class)
+// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
+@Config(sdk = [Build.VERSION_CODES.P], application = HiltTestApplication::class)
+class EntryPointAccessorsTest {
+
+ companion object {
+ const val APPLICATION_STRING = "APPLICATION_STRING"
+ const val ACTIVITY_STRING = "ACTIVITY_STRING"
+ const val FRAGMENT_STRING = "FRAGMENT_STRING"
+ const val VIEW_STRING = "VIEW_STRING"
+ }
+
+ @get:Rule
+ var rule = HiltAndroidRule(this)
+
+ @Qualifier
+ @Retention(AnnotationRetention.BINARY)
+ annotation class ApplicationLevel
+
+ @Qualifier
+ @Retention(AnnotationRetention.BINARY)
+ annotation class ActivityLevel
+
+ @Qualifier
+ @Retention(AnnotationRetention.BINARY)
+ annotation class FragmentLevel
+
+ @Qualifier
+ @Retention(AnnotationRetention.BINARY)
+ annotation class ViewLevel
+
+ @Module
+ @InstallIn(SingletonComponent::class)
+ internal object ApplicationModule {
+ @ApplicationLevel
+ @Provides
+ fun provideString(): String {
+ return APPLICATION_STRING
+ }
+ }
+
+ @Module
+ @InstallIn(ActivityComponent::class)
+ internal object ActivityModule {
+ @ActivityLevel
+ @Provides
+ fun provideString(): String {
+ return ACTIVITY_STRING
+ }
+ }
+
+ @Module
+ @InstallIn(FragmentComponent::class)
+ internal object FragmentModule {
+ @FragmentLevel
+ @Provides
+ fun provideString(): String {
+ return FRAGMENT_STRING
+ }
+ }
+
+ @Module
+ @InstallIn(ViewComponent::class)
+ internal object ViewModule {
+ @ViewLevel
+ @Provides
+ fun provideString(): String {
+ return VIEW_STRING
+ }
+ }
+
+ @EntryPoint
+ @InstallIn(SingletonComponent::class)
+ internal interface ApplicationEntryPoint {
+ @ApplicationLevel
+ fun getString(): String
+ }
+
+ @EntryPoint
+ @InstallIn(ActivityComponent::class)
+ internal interface ActivityEntryPoint {
+ @ActivityLevel
+ fun getString(): String
+ }
+
+ @EntryPoint
+ @InstallIn(FragmentComponent::class)
+ internal interface FragmentEntryPoint {
+ @FragmentLevel
+ fun getString(): String
+ }
+
+ @EntryPoint
+ @InstallIn(ViewComponent::class)
+ internal interface ViewEntryPoint {
+ @ViewLevel
+ fun getString(): String
+ }
+
+ @Test
+ fun testApplicationEntryPoint() {
+ val app = getApplicationContext<HiltTestApplication>()
+ val entryPoint = EntryPointAccessors.fromApplication<ApplicationEntryPoint>(app)
+ Truth.assertThat(entryPoint.getString())
+ .isEqualTo(APPLICATION_STRING)
+
+ val activity = Robolectric.buildActivity(TestActivity::class.java).setup().get()
+ val applicationEntryPoint = EntryPointAccessors.fromApplication<ApplicationEntryPoint>(activity)
+ Truth.assertThat(applicationEntryPoint.getString())
+ .isEqualTo(APPLICATION_STRING)
+ }
+
+ @Test
+ fun testActivityEntryPoint() {
+ val activity = Robolectric.buildActivity(TestActivity::class.java).setup().get()
+ val entryPoint = EntryPointAccessors.fromActivity<ActivityEntryPoint>(activity)
+ Truth.assertThat(entryPoint.getString())
+ .isEqualTo(ACTIVITY_STRING)
+ }
+
+ @Test
+ fun testFragmentEntryPoint() {
+ val activity = Robolectric.buildActivity(TestActivity::class.java).setup().get()
+ val fragment = TestFragment()
+ activity.supportFragmentManager.beginTransaction().add(fragment, "").commitNow()
+ val entryPoint = EntryPointAccessors.fromFragment<FragmentEntryPoint>(fragment)
+ Truth.assertThat(entryPoint.getString())
+ .isEqualTo(FRAGMENT_STRING)
+ }
+
+ @Test
+ fun testViewEntryPoint() {
+ val activity = Robolectric.buildActivity(TestActivity::class.java).setup().get()
+ val view = TestView(activity)
+ val entryPoint = EntryPointAccessors.fromView<ViewEntryPoint>(view)
+ Truth.assertThat(entryPoint.getString())
+ .isEqualTo(VIEW_STRING)
+ }
+
+ @AndroidEntryPoint(FragmentActivity::class)
+ class TestActivity : Hilt_EntryPointAccessorsTest_TestActivity()
+
+ @AndroidEntryPoint(Fragment::class)
+ class TestFragment : Hilt_EntryPointAccessorsTest_TestFragment()
+
+ @AndroidEntryPoint(View::class)
+ class TestView(context: Context) : Hilt_EntryPointAccessorsTest_TestView(context)
+}
diff --git a/javatests/dagger/hilt/android/FragmentContextOnAttachTest.java b/javatests/dagger/hilt/android/FragmentContextOnAttachTest.java
new file mode 100644
index 000000000..19b3d05aa
--- /dev/null
+++ b/javatests/dagger/hilt/android/FragmentContextOnAttachTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Build;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import dagger.hilt.android.flags.FragmentGetContextFix;
+import dagger.hilt.android.testing.BindValueIntoSet;
+import dagger.hilt.android.testing.HiltAndroidRule;
+import dagger.hilt.android.testing.HiltAndroidTest;
+import dagger.hilt.android.testing.HiltTestApplication;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.annotation.Config;
+
+@HiltAndroidTest
+@RunWith(AndroidJUnit4.class)
+// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
+@Config(sdk = Build.VERSION_CODES.P, application = HiltTestApplication.class)
+public final class FragmentContextOnAttachTest {
+
+ @Rule public final HiltAndroidRule rule = new HiltAndroidRule(this);
+
+ @BindValueIntoSet
+ @FragmentGetContextFix.DisableFragmentGetContextFix
+ boolean disableGetContextFix = false;
+
+ /** Hilt Activity */
+ @AndroidEntryPoint(FragmentActivity.class)
+ public static final class TestActivity extends Hilt_FragmentContextOnAttachTest_TestActivity {}
+
+ /** Hilt Fragment */
+ @AndroidEntryPoint(Fragment.class)
+ public static final class TestFragment extends Hilt_FragmentContextOnAttachTest_TestFragment {
+ Context onAttachContextContext = null;
+ Context onAttachActivityContext = null;
+
+ @Override
+ public void onAttach(Context context) {
+ // Test that getContext() can be called at this point
+ onAttachContextContext = getContext();
+ super.onAttach(context);
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ // Test that getContext() can be called at this point
+ onAttachActivityContext = getContext();
+ super.onAttach(activity);
+ }
+ }
+
+ @Test
+ public void testGetContextAvailableBeforeSuperOnAttach() throws Exception {
+ FragmentActivity activity = Robolectric.setupActivity(TestActivity.class);
+ TestFragment fragment = new TestFragment();
+ activity.getSupportFragmentManager().beginTransaction().add(fragment, "").commitNow();
+ assertThat(fragment.onAttachContextContext).isNotNull();
+ assertThat(fragment.onAttachActivityContext).isNotNull();
+ }
+
+ // Tests the behavior when using the useFragmentGetContextFix flag.
+ @Test
+ public void testGetContextReturnsNullAfterRemoval() throws Exception {
+ FragmentActivity activity = Robolectric.setupActivity(TestActivity.class);
+ TestFragment fragment = new TestFragment();
+ activity.getSupportFragmentManager().beginTransaction().add(fragment, "").commitNow();
+ assertThat(fragment.getContext()).isNotNull();
+ activity.getSupportFragmentManager().beginTransaction().remove(fragment).commitNow();
+ // This should be null since the fix was enabled by the compiler flag and runtime flag
+ assertThat(fragment.getContext()).isNull();
+
+ // Flip the flag so that we now disable the fix
+ disableGetContextFix = true;
+ TestFragment fragment2 = new TestFragment();
+ activity.getSupportFragmentManager().beginTransaction().add(fragment2, "").commitNow();
+ assertThat(fragment2.getContext()).isNotNull();
+ activity.getSupportFragmentManager().beginTransaction().remove(fragment2).commitNow();
+ // This should not be null since the fix was disabled by the runtime flag
+ assertThat(fragment2.getContext()).isNotNull();
+ }
+}
diff --git a/javatests/dagger/hilt/android/ModuleTest.java b/javatests/dagger/hilt/android/ModuleTest.java
index 0dadfe0ec..2a2462384 100644
--- a/javatests/dagger/hilt/android/ModuleTest.java
+++ b/javatests/dagger/hilt/android/ModuleTest.java
@@ -79,7 +79,7 @@ public final class ModuleTest {
// constructor exists.
@Module
@InstallIn(SingletonComponent.class)
- static final class TestModule3 {
+ public static final class TestModule3 {
TestModule3() {
this("");
}
diff --git a/javatests/dagger/hilt/android/MultiTestRoot1Test.java b/javatests/dagger/hilt/android/MultiTestRoot1Test.java
index 49c03bc75..36719b45e 100644
--- a/javatests/dagger/hilt/android/MultiTestRoot1Test.java
+++ b/javatests/dagger/hilt/android/MultiTestRoot1Test.java
@@ -150,7 +150,8 @@ public final class MultiTestRoot1Test {
}
}
- static class Bar {
+ // Must be public due to b/183636779
+ public static class Bar {
final String value;
Bar(String value) {
@@ -166,7 +167,8 @@ public final class MultiTestRoot1Test {
}
}
- static class Qux {}
+ // Must be public due to b/183636779
+ public static class Qux {}
@Module
@InstallIn(SingletonComponent.class)
@@ -277,10 +279,11 @@ public final class MultiTestRoot1Test {
ClassCastException.class,
() -> EntryPoints.get(getApplicationContext(), MultiTestRoot2Test.BarEntryPoint.class));
assertThat(exception)
- .hasMessageThat()
- .isEqualTo(
- "Cannot cast dagger.hilt.android.DaggerMultiTestRoot1Test_HiltComponents_SingletonC"
- + " to dagger.hilt.android.MultiTestRoot2Test$BarEntryPoint");
+ .hasMessageThat()
+ .isEqualTo(
+ "Cannot cast dagger.hilt.android.internal.testing.root."
+ + "DaggerMultiTestRoot1Test_HiltComponents_SingletonC"
+ + " to dagger.hilt.android.MultiTestRoot2Test$BarEntryPoint");
}
@Test
diff --git a/javatests/dagger/hilt/android/MultiTestRoot2Test.java b/javatests/dagger/hilt/android/MultiTestRoot2Test.java
index 39aecfa2e..ec660c429 100644
--- a/javatests/dagger/hilt/android/MultiTestRoot2Test.java
+++ b/javatests/dagger/hilt/android/MultiTestRoot2Test.java
@@ -121,7 +121,8 @@ public final class MultiTestRoot2Test {
}
}
- static class Bar {
+ // Must be public due to b/183636779
+ public static class Bar {
final String value;
Bar(String value) {
@@ -137,7 +138,8 @@ public final class MultiTestRoot2Test {
}
}
- static class Qux {}
+ // Must be public due to b/183636779
+ public static class Qux {}
@Module
@InstallIn(SingletonComponent.class)
@@ -255,10 +257,11 @@ public final class MultiTestRoot2Test {
ClassCastException.class,
() -> EntryPoints.get(getApplicationContext(), MultiTestRoot1Test.BarEntryPoint.class));
assertThat(exception)
- .hasMessageThat()
- .isEqualTo(
- "Cannot cast dagger.hilt.android.DaggerMultiTestRoot2Test_HiltComponents_SingletonC"
- + " to dagger.hilt.android.MultiTestRoot1Test$BarEntryPoint");
+ .hasMessageThat()
+ .isEqualTo(
+ "Cannot cast dagger.hilt.android.internal.testing.root."
+ + "DaggerMultiTestRoot2Test_HiltComponents_SingletonC"
+ + " to dagger.hilt.android.MultiTestRoot1Test$BarEntryPoint");
}
@Test
diff --git a/javatests/dagger/hilt/android/OptionalInjectTestClasses.java b/javatests/dagger/hilt/android/OptionalInjectTestClasses.java
new file mode 100644
index 000000000..78b52daa8
--- /dev/null
+++ b/javatests/dagger/hilt/android/OptionalInjectTestClasses.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android;
+
+import android.app.IntentService;
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import android.widget.LinearLayout;
+import androidx.lifecycle.ViewModel;
+import dagger.Module;
+import dagger.Provides;
+import dagger.hilt.InstallIn;
+import dagger.hilt.android.lifecycle.HiltViewModel;
+import dagger.hilt.android.migration.OptionalInject;
+import dagger.hilt.components.SingletonComponent;
+import javax.inject.Inject;
+import javax.inject.Qualifier;
+
+/** Test classes for optional injection. */
+public final class OptionalInjectTestClasses {
+ public static final String APP_BINDING = "app binding";
+ public static final String ACTIVITY_BINDING = "activity binding";
+ public static final String FRAGMENT_BINDING = "fragment binding";
+ public static final String VIEW_BINDING = "view binding";
+
+ @Qualifier
+ @interface ActivityLevel {}
+
+ @Qualifier
+ @interface FragmentLevel {}
+
+ @Qualifier
+ @interface ViewLevel {}
+
+ @AndroidEntryPoint(FragmentActivity.class)
+ @OptionalInject
+ public static class TestActivity extends Hilt_OptionalInjectTestClasses_TestActivity {
+ @Inject @ActivityLevel String testActivityBinding;
+ }
+
+ @AndroidEntryPoint(TestActivity.class)
+ public static final class NonOptionalSubclassActivity
+ extends Hilt_OptionalInjectTestClasses_NonOptionalSubclassActivity {
+ @Inject @ActivityLevel String testActivitySubclassBinding;
+ }
+
+ @AndroidEntryPoint(TestActivity.class)
+ @OptionalInject
+ public static final class OptionalSubclassActivity
+ extends Hilt_OptionalInjectTestClasses_OptionalSubclassActivity {
+ @Inject @ActivityLevel String testActivitySubclassBinding;
+ }
+
+ @AndroidEntryPoint(Fragment.class)
+ @OptionalInject
+ public static final class TestFragment extends Hilt_OptionalInjectTestClasses_TestFragment {
+ @Inject @FragmentLevel String testFragmentBinding;
+ }
+
+ @AndroidEntryPoint(LinearLayout.class)
+ @OptionalInject
+ public static final class TestView extends Hilt_OptionalInjectTestClasses_TestView {
+ @Inject @ViewLevel String testViewBinding;
+
+ TestView(Context context) {
+ super(context);
+ }
+ }
+
+ @WithFragmentBindings
+ @AndroidEntryPoint(LinearLayout.class)
+ @OptionalInject
+ public static final class TestWithFragmentBindingsView
+ extends Hilt_OptionalInjectTestClasses_TestWithFragmentBindingsView {
+ @Inject @ViewLevel String testViewBinding;
+
+ TestWithFragmentBindingsView(Context context) {
+ super(context);
+ }
+ }
+
+ @HiltViewModel
+ public static final class TestViewModel extends ViewModel {
+ final String appBinding;
+
+ @Inject TestViewModel(String appBinding) {
+ this.appBinding = appBinding;
+ }
+ }
+
+ public static final class NonHiltViewModel extends ViewModel {}
+
+ @AndroidEntryPoint(Service.class)
+ @OptionalInject
+ public static final class TestService extends Hilt_OptionalInjectTestClasses_TestService {
+ @Inject String testAppBinding;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+ }
+
+ @AndroidEntryPoint(IntentService.class)
+ @OptionalInject
+ public static final class TestIntentService
+ extends Hilt_OptionalInjectTestClasses_TestIntentService {
+ TestIntentService() {
+ super("TestIntentService");
+ }
+
+ @Inject String testAppBinding;
+
+ @Override
+ public void onHandleIntent(Intent intent) {}
+ }
+
+ @AndroidEntryPoint(BroadcastReceiver.class)
+ @OptionalInject
+ public static final class TestBroadcastReceiver
+ extends Hilt_OptionalInjectTestClasses_TestBroadcastReceiver {
+ @Inject String testAppBinding;
+ }
+
+ @Module
+ @InstallIn(SingletonComponent.class)
+ static final class AppModule {
+ @Provides
+ static String provideAppString() {
+ return APP_BINDING;
+ }
+
+ @Provides
+ @ActivityLevel
+ static String provideActivityString() {
+ return ACTIVITY_BINDING;
+ }
+
+ @Provides
+ @FragmentLevel
+ static String provideFragmentString() {
+ return FRAGMENT_BINDING;
+ }
+
+ @Provides
+ @ViewLevel
+ static String provideViewString() {
+ return VIEW_BINDING;
+ }
+ }
+}
diff --git a/javatests/dagger/hilt/android/OptionalInjectWithHiltTest.java b/javatests/dagger/hilt/android/OptionalInjectWithHiltTest.java
new file mode 100644
index 000000000..a8fedf6d3
--- /dev/null
+++ b/javatests/dagger/hilt/android/OptionalInjectWithHiltTest.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android;
+
+import static com.google.common.truth.Truth.assertThat;
+import static dagger.hilt.android.OptionalInjectTestClasses.ACTIVITY_BINDING;
+import static dagger.hilt.android.OptionalInjectTestClasses.APP_BINDING;
+import static dagger.hilt.android.OptionalInjectTestClasses.FRAGMENT_BINDING;
+import static dagger.hilt.android.OptionalInjectTestClasses.VIEW_BINDING;
+import static dagger.hilt.android.migration.OptionalInjectCheck.wasInjectedByHilt;
+import static org.junit.Assert.assertThrows;
+
+import android.content.Intent;
+import android.os.Build;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import dagger.hilt.android.OptionalInjectTestClasses.NonHiltViewModel;
+import dagger.hilt.android.OptionalInjectTestClasses.NonOptionalSubclassActivity;
+import dagger.hilt.android.OptionalInjectTestClasses.OptionalSubclassActivity;
+import dagger.hilt.android.OptionalInjectTestClasses.TestActivity;
+import dagger.hilt.android.OptionalInjectTestClasses.TestBroadcastReceiver;
+import dagger.hilt.android.OptionalInjectTestClasses.TestFragment;
+import dagger.hilt.android.OptionalInjectTestClasses.TestIntentService;
+import dagger.hilt.android.OptionalInjectTestClasses.TestService;
+import dagger.hilt.android.OptionalInjectTestClasses.TestView;
+import dagger.hilt.android.OptionalInjectTestClasses.TestViewModel;
+import dagger.hilt.android.OptionalInjectTestClasses.TestWithFragmentBindingsView;
+import dagger.hilt.android.testing.HiltAndroidRule;
+import dagger.hilt.android.testing.HiltAndroidTest;
+import dagger.hilt.android.testing.HiltTestApplication;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.annotation.Config;
+
+/** Tests that optional inject works with a Hilt root. */
+@HiltAndroidTest
+@RunWith(AndroidJUnit4.class)
+// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
+@Config(sdk = Build.VERSION_CODES.P, application = HiltTestApplication.class)
+public final class OptionalInjectWithHiltTest {
+ @Rule public final HiltAndroidRule rules = new HiltAndroidRule(this);
+
+ @Test
+ public void testActivityInjection() throws Exception {
+ TestActivity testActivity = Robolectric.setupActivity(TestActivity.class);
+ assertThat(testActivity.testActivityBinding).isEqualTo(ACTIVITY_BINDING);
+ assertThat(testActivity.wasInjectedByHilt()).isTrue();
+ assertThat(wasInjectedByHilt(testActivity)).isTrue();
+ }
+
+ @Test
+ public void testNonOptionalSubclassActivityInjection() throws Exception {
+ NonOptionalSubclassActivity testActivity = Robolectric.setupActivity(
+ NonOptionalSubclassActivity.class);
+ assertThat(testActivity.testActivityBinding).isEqualTo(ACTIVITY_BINDING);
+ assertThat(testActivity.testActivitySubclassBinding).isEqualTo(ACTIVITY_BINDING);
+ assertThat(testActivity.wasInjectedByHilt()).isTrue();
+ assertThat(wasInjectedByHilt(testActivity)).isTrue();
+ }
+
+ @Test
+ public void testOptionalSubclassActivityInjection() throws Exception {
+ OptionalSubclassActivity testActivity = Robolectric.setupActivity(
+ OptionalSubclassActivity.class);
+ assertThat(testActivity.testActivityBinding).isEqualTo(ACTIVITY_BINDING);
+ assertThat(testActivity.testActivitySubclassBinding).isEqualTo(ACTIVITY_BINDING);
+ assertThat(testActivity.wasInjectedByHilt()).isTrue();
+ assertThat(wasInjectedByHilt(testActivity)).isTrue();
+ }
+
+ @Test
+ public void testFragmentInjection() throws Exception {
+ TestActivity testActivity = Robolectric.setupActivity(TestActivity.class);
+ TestFragment testFragment = new TestFragment();
+ testActivity.getSupportFragmentManager()
+ .beginTransaction()
+ .add(testFragment, null)
+ .commitNow();
+ assertThat(testFragment.testFragmentBinding).isEqualTo(FRAGMENT_BINDING);
+ assertThat(testFragment.wasInjectedByHilt()).isTrue();
+ assertThat(wasInjectedByHilt(testFragment)).isTrue();
+ }
+
+ @Test
+ public void testFragmentInjectionWithNonHiltActivityWithHiltRoot() throws Exception {
+ FragmentActivity testActivity = Robolectric.setupActivity(FragmentActivity.class);
+ TestFragment testFragment = new TestFragment();
+ testActivity.getSupportFragmentManager()
+ .beginTransaction()
+ .add(testFragment, null)
+ .commitNow();
+ assertThat(testFragment.testFragmentBinding).isNull();
+ assertThat(testFragment.wasInjectedByHilt()).isFalse();
+ assertThat(wasInjectedByHilt(testFragment)).isFalse();
+ }
+
+ @Test
+ public void testViewInjection() throws Exception {
+ TestActivity testActivity = Robolectric.setupActivity(TestActivity.class);
+ TestView testView = new TestView(testActivity);
+ assertThat(testView.testViewBinding).isEqualTo(VIEW_BINDING);
+ assertThat(testView.wasInjectedByHilt()).isTrue();
+ assertThat(wasInjectedByHilt(testView)).isTrue();
+ }
+
+ @Test
+ public void testViewInjectionWithNonHiltActivityWithHiltRoot() throws Exception {
+ FragmentActivity testActivity = Robolectric.setupActivity(FragmentActivity.class);
+ TestView testView = new TestView(testActivity);
+ assertThat(testView.testViewBinding).isNull();
+ assertThat(testView.wasInjectedByHilt()).isFalse();
+ assertThat(wasInjectedByHilt(testView)).isFalse();
+ }
+
+ @Test
+ public void testViewWithFragmentBindingsInjection() throws Exception {
+ TestActivity testActivity = Robolectric.setupActivity(TestActivity.class);
+ TestFragment testFragment = new TestFragment();
+ testActivity.getSupportFragmentManager()
+ .beginTransaction()
+ .add(testFragment, null)
+ .commitNow();
+
+ TestWithFragmentBindingsView testView = new TestWithFragmentBindingsView(
+ testFragment.getLayoutInflater().getContext());
+ assertThat(testView.testViewBinding).isEqualTo(VIEW_BINDING);
+ assertThat(testView.wasInjectedByHilt()).isTrue();
+ assertThat(wasInjectedByHilt(testView)).isTrue();
+ }
+
+ @Test
+ public void testViewWithFragmentBindingsInjectionWithNonHiltFragmentWithHiltRoot()
+ throws Exception {
+ TestActivity testActivity = Robolectric.setupActivity(TestActivity.class);
+ Fragment testFragment = new Fragment();
+ testActivity.getSupportFragmentManager()
+ .beginTransaction()
+ .add(testFragment, null)
+ .commitNow();
+
+ TestWithFragmentBindingsView testView = new TestWithFragmentBindingsView(
+ testFragment.getLayoutInflater().getContext());
+ assertThat(testView.testViewBinding).isNull();
+ assertThat(testView.wasInjectedByHilt()).isFalse();
+ assertThat(wasInjectedByHilt(testView)).isFalse();
+ }
+
+ @Test
+ public void testHiltViewModels() {
+ TestActivity testActivity = Robolectric.setupActivity(TestActivity.class);
+ TestFragment testFragment = new TestFragment();
+ testActivity.getSupportFragmentManager()
+ .beginTransaction()
+ .add(testFragment, null)
+ .commitNow();
+ assertThat(new ViewModelProvider(testActivity).get(TestViewModel.class).appBinding)
+ .isEqualTo(APP_BINDING);
+ assertThat(new ViewModelProvider(testActivity).get(NonHiltViewModel.class)).isNotNull();
+ assertThat(new ViewModelProvider(testFragment).get(TestViewModel.class).appBinding)
+ .isEqualTo(APP_BINDING);
+ assertThat(new ViewModelProvider(testFragment).get(NonHiltViewModel.class)).isNotNull();
+ }
+
+ @Test
+ public void testHiltViewModelsWithNonHiltActivityWithHiltRoot() throws Exception {
+ FragmentActivity testActivity = Robolectric.setupActivity(FragmentActivity.class);
+ TestFragment testFragment = new TestFragment();
+ testActivity.getSupportFragmentManager()
+ .beginTransaction()
+ .add(testFragment, null)
+ .commitNow();
+ assertThat(new ViewModelProvider(testActivity).get(NonHiltViewModel.class)).isNotNull();
+ assertThat(new ViewModelProvider(testFragment).get(NonHiltViewModel.class)).isNotNull();
+
+ // Hilt View Models aren't usable in this case, so check that it throws. We only test with the
+ // owner as the fragment since the activity is just a plain FragmentActivity.
+ RuntimeException exception =
+ assertThrows(
+ RuntimeException.class,
+ () -> new ViewModelProvider(testFragment).get(TestViewModel.class));
+ assertThat(exception)
+ .hasMessageThat()
+ .contains("TestViewModel");
+ }
+
+ @Test
+ public void testServiceInjection() throws Exception {
+ TestService testService = Robolectric.setupService(TestService.class);
+ assertThat(testService.testAppBinding).isEqualTo(APP_BINDING);
+ assertThat(testService.wasInjectedByHilt()).isTrue();
+ assertThat(wasInjectedByHilt(testService)).isTrue();
+ }
+
+ @Test
+ public void testIntentServiceInjection() throws Exception {
+ TestIntentService testIntentService = Robolectric.setupService(TestIntentService.class);
+ assertThat(testIntentService.testAppBinding).isEqualTo(APP_BINDING);
+ assertThat(testIntentService.wasInjectedByHilt()).isTrue();
+ assertThat(wasInjectedByHilt(testIntentService)).isTrue();
+ }
+
+ @Test
+ public void testBroadcastReceiverInjection() throws Exception {
+ TestBroadcastReceiver testBroadcastReceiver = new TestBroadcastReceiver();
+ Intent intent = new Intent();
+ testBroadcastReceiver.onReceive(ApplicationProvider.getApplicationContext(), intent);
+ assertThat(testBroadcastReceiver.testAppBinding).isEqualTo(APP_BINDING);
+ assertThat(testBroadcastReceiver.wasInjectedByHilt()).isTrue();
+ assertThat(wasInjectedByHilt(testBroadcastReceiver)).isTrue();
+ }
+}
diff --git a/javatests/dagger/hilt/android/OptionalInjectWithoutHiltTest.java b/javatests/dagger/hilt/android/OptionalInjectWithoutHiltTest.java
new file mode 100644
index 000000000..fb516486d
--- /dev/null
+++ b/javatests/dagger/hilt/android/OptionalInjectWithoutHiltTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android;
+
+import static com.google.common.truth.Truth.assertThat;
+import static dagger.hilt.android.migration.OptionalInjectCheck.wasInjectedByHilt;
+import static org.junit.Assert.assertThrows;
+
+import android.content.Intent;
+import android.os.Build;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import dagger.hilt.android.OptionalInjectTestClasses.NonHiltViewModel;
+import dagger.hilt.android.OptionalInjectTestClasses.OptionalSubclassActivity;
+import dagger.hilt.android.OptionalInjectTestClasses.TestActivity;
+import dagger.hilt.android.OptionalInjectTestClasses.TestBroadcastReceiver;
+import dagger.hilt.android.OptionalInjectTestClasses.TestFragment;
+import dagger.hilt.android.OptionalInjectTestClasses.TestIntentService;
+import dagger.hilt.android.OptionalInjectTestClasses.TestService;
+import dagger.hilt.android.OptionalInjectTestClasses.TestView;
+import dagger.hilt.android.OptionalInjectTestClasses.TestViewModel;
+import dagger.hilt.android.OptionalInjectTestClasses.TestWithFragmentBindingsView;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.annotation.Config;
+
+/** Tests that optional inject work without a Hilt root. */
+@RunWith(AndroidJUnit4.class)
+// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
+@Config(sdk = Build.VERSION_CODES.P)
+public final class OptionalInjectWithoutHiltTest {
+ @Test
+ public void testActivityInjection() throws Exception {
+ TestActivity testActivity = Robolectric.setupActivity(TestActivity.class);
+ assertThat(testActivity.testActivityBinding).isNull();
+ assertThat(testActivity.wasInjectedByHilt()).isFalse();
+ assertThat(wasInjectedByHilt(testActivity)).isFalse();
+ }
+
+ @Test
+ public void testOptionalSubclassActivityInjection() throws Exception {
+ OptionalSubclassActivity testActivity = Robolectric.setupActivity(
+ OptionalSubclassActivity.class);
+ assertThat(testActivity.testActivityBinding).isNull();
+ assertThat(testActivity.testActivitySubclassBinding).isNull();
+ assertThat(testActivity.wasInjectedByHilt()).isFalse();
+ assertThat(wasInjectedByHilt(testActivity)).isFalse();
+ }
+
+ @Test
+ public void testFragmentInjection() throws Exception {
+ TestActivity testActivity = Robolectric.setupActivity(TestActivity.class);
+ TestFragment testFragment = new TestFragment();
+ testActivity.getSupportFragmentManager()
+ .beginTransaction()
+ .add(testFragment, null)
+ .commitNow();
+ assertThat(testFragment.testFragmentBinding).isNull();
+ assertThat(testFragment.wasInjectedByHilt()).isFalse();
+ assertThat(wasInjectedByHilt(testFragment)).isFalse();
+ }
+
+ @Test
+ public void testViewInjection() throws Exception {
+ TestActivity testActivity = Robolectric.setupActivity(TestActivity.class);
+ TestView testView = new TestView(testActivity);
+ assertThat(testView.testViewBinding).isNull();
+ assertThat(testView.wasInjectedByHilt()).isFalse();
+ assertThat(wasInjectedByHilt(testView)).isFalse();
+ }
+
+ @Test
+ public void testViewWithFragmentBindingsInjection() throws Exception {
+ TestActivity testActivity = Robolectric.setupActivity(TestActivity.class);
+ TestFragment testFragment = new TestFragment();
+ testActivity.getSupportFragmentManager()
+ .beginTransaction()
+ .add(testFragment, null)
+ .commitNow();
+
+ TestWithFragmentBindingsView testView = new TestWithFragmentBindingsView(
+ testFragment.getLayoutInflater().getContext());
+ assertThat(testView.testViewBinding).isNull();
+ assertThat(testView.wasInjectedByHilt()).isFalse();
+ assertThat(wasInjectedByHilt(testView)).isFalse();
+ }
+
+ @Test
+ public void testViewModels() {
+ TestActivity testActivity = Robolectric.setupActivity(TestActivity.class);
+ TestFragment testFragment = new TestFragment();
+ testActivity.getSupportFragmentManager()
+ .beginTransaction()
+ .add(testFragment, null)
+ .commitNow();
+ assertThat(new ViewModelProvider(testActivity).get(NonHiltViewModel.class)).isNotNull();
+ assertThat(new ViewModelProvider(testFragment).get(NonHiltViewModel.class)).isNotNull();
+
+ // Hilt View Models aren't usable in this case, so check that it throws.
+ RuntimeException activityException =
+ assertThrows(
+ RuntimeException.class,
+ () -> new ViewModelProvider(testFragment).get(TestViewModel.class));
+ assertThat(activityException)
+ .hasMessageThat()
+ .contains("TestViewModel");
+ RuntimeException fragmentException =
+ assertThrows(
+ RuntimeException.class,
+ () -> new ViewModelProvider(testFragment).get(TestViewModel.class));
+ assertThat(fragmentException)
+ .hasMessageThat()
+ .contains("TestViewModel");
+ }
+
+ @Test
+ public void testServiceInjection() throws Exception {
+ TestService testService = Robolectric.setupService(TestService.class);
+ assertThat(testService.testAppBinding).isNull();
+ assertThat(testService.wasInjectedByHilt()).isFalse();
+ assertThat(wasInjectedByHilt(testService)).isFalse();
+ }
+
+ @Test
+ public void testIntentServiceInjection() throws Exception {
+ TestIntentService testIntentService = Robolectric.setupService(TestIntentService.class);
+ assertThat(testIntentService.testAppBinding).isNull();
+ assertThat(testIntentService.wasInjectedByHilt()).isFalse();
+ assertThat(wasInjectedByHilt(testIntentService)).isFalse();
+ }
+
+ @Test
+ public void testBroadcastReceiverInjection() throws Exception {
+ TestBroadcastReceiver testBroadcastReceiver = new TestBroadcastReceiver();
+ Intent intent = new Intent();
+ testBroadcastReceiver.onReceive(ApplicationProvider.getApplicationContext(), intent);
+ assertThat(testBroadcastReceiver.testAppBinding).isNull();
+ assertThat(testBroadcastReceiver.wasInjectedByHilt()).isFalse();
+ assertThat(wasInjectedByHilt(testBroadcastReceiver)).isFalse();
+ }
+}
diff --git a/javatests/dagger/hilt/android/ViewModelScopedTest.java b/javatests/dagger/hilt/android/ViewModelScopedTest.java
index e37e42ac7..bc8212650 100644
--- a/javatests/dagger/hilt/android/ViewModelScopedTest.java
+++ b/javatests/dagger/hilt/android/ViewModelScopedTest.java
@@ -18,13 +18,13 @@ package dagger.hilt.android;
import static com.google.common.truth.Truth.assertThat;
-import androidx.lifecycle.ViewModel;
-import androidx.lifecycle.ViewModelProvider;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import dagger.hilt.android.lifecycle.HiltViewModel;
diff --git a/javatests/dagger/hilt/android/ViewModelWithBaseTest.java b/javatests/dagger/hilt/android/ViewModelWithBaseTest.java
index 4e4a47c0b..292fd1605 100644
--- a/javatests/dagger/hilt/android/ViewModelWithBaseTest.java
+++ b/javatests/dagger/hilt/android/ViewModelWithBaseTest.java
@@ -18,13 +18,13 @@ package dagger.hilt.android;
import static com.google.common.truth.Truth.assertThat;
-import androidx.lifecycle.SavedStateHandle;
-import androidx.lifecycle.ViewModel;
-import androidx.lifecycle.ViewModelProvider;
import android.os.Build;
import android.os.Bundle;
import androidx.fragment.app.FragmentActivity;
import androidx.annotation.Nullable;
+import androidx.lifecycle.SavedStateHandle;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import dagger.hilt.android.lifecycle.HiltViewModel;
diff --git a/javatests/dagger/hilt/android/internal/managers/BUILD b/javatests/dagger/hilt/android/internal/managers/BUILD
index ff4f432f7..b7fe47c83 100644
--- a/javatests/dagger/hilt/android/internal/managers/BUILD
+++ b/javatests/dagger/hilt/android/internal/managers/BUILD
@@ -27,10 +27,8 @@ android_local_test(
deps = [
"//:android_local_test_exports",
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/jsr330_inject",
"@maven//:junit_junit",
- "@google_bazel_common//third_party/java/truth",
- "//java/dagger/hilt:entry_point",
+ "//third_party/java/truth",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android/lifecycle",
diff --git a/javatests/dagger/hilt/android/internal/managers/FragmentContextWrapperLeakTest.java b/javatests/dagger/hilt/android/internal/managers/FragmentContextWrapperLeakTest.java
index 38086c6aa..116d2d943 100644
--- a/javatests/dagger/hilt/android/internal/managers/FragmentContextWrapperLeakTest.java
+++ b/javatests/dagger/hilt/android/internal/managers/FragmentContextWrapperLeakTest.java
@@ -19,10 +19,10 @@ package dagger.hilt.android.internal.managers;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
-import androidx.lifecycle.Lifecycle;
import android.os.Build;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
+import androidx.lifecycle.Lifecycle;
import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import dagger.hilt.android.AndroidEntryPoint;
diff --git a/javatests/dagger/hilt/android/processor/internal/BUILD b/javatests/dagger/hilt/android/processor/internal/BUILD
index 9a0a8f2a0..513173f15 100644
--- a/javatests/dagger/hilt/android/processor/internal/BUILD
+++ b/javatests/dagger/hilt/android/processor/internal/BUILD
@@ -28,9 +28,9 @@ compiler_test(
"@maven//:androidx_annotation_annotation",
],
deps = [
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "//javatests/dagger/hilt/android/processor:android_compilers",
+ "//third_party/java/compile_testing",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ "//java/dagger/hilt/android/testing/compile",
],
)
diff --git a/javatests/dagger/hilt/android/processor/internal/GeneratorsTest.java b/javatests/dagger/hilt/android/processor/internal/GeneratorsTest.java
index ecfd1f6aa..4dfa87c5d 100644
--- a/javatests/dagger/hilt/android/processor/internal/GeneratorsTest.java
+++ b/javatests/dagger/hilt/android/processor/internal/GeneratorsTest.java
@@ -17,7 +17,7 @@
package dagger.hilt.android.processor.internal;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.processor.AndroidCompilers.compiler;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
@@ -174,7 +174,6 @@ public final class GeneratorsTest {
" public MyView(Context context, AttributeSet attributeSet){",
" super(context, attributeSet);",
" }",
- "",
"}");
Compilation compilation = compiler().compile(myView);
assertThat(compilation).succeeded();
@@ -247,7 +246,6 @@ public final class GeneratorsTest {
"",
"@Generated(\"dagger.hilt.android.processor.internal.androidentrypoint.FragmentGenerator\")",
"@TargetApi(24)",
- "@SuppressWarnings(\"deprecation\")",
"abstract class Hilt_MyFragment extends Fragment implements"
+ " GeneratedComponentManagerHolder {}"));
}
@@ -315,4 +313,193 @@ public final class GeneratorsTest {
"abstract class Hilt_MyService extends Service implements"
+ " GeneratedComponentManagerHolder{}"));
}
+
+ @Test
+ public void copySuppressWarningsAnnotationActivity_annotationCopied() {
+ JavaFileObject myActivity =
+ JavaFileObjects.forSourceLines(
+ "test.MyActivity",
+ "package test;",
+ "",
+ "import android.annotation.TargetApi;",
+ "import androidx.fragment.app.FragmentActivity;",
+ "import dagger.hilt.android.AndroidEntryPoint;",
+ "",
+ "@SuppressWarnings(\"deprecation\")",
+ "@AndroidEntryPoint(FragmentActivity.class)",
+ "public class MyActivity extends Hilt_MyActivity {}");
+ Compilation compilation = compiler().compile(myActivity);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test/Hilt_MyActivity")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.Hilt_MyActivity",
+ " package test;",
+ "",
+ "@Generated(\"dagger.hilt.android.processor.internal.androidentrypoint.ActivityGenerator\")",
+ "@SuppressWarnings(\"deprecation\")",
+ "abstract class Hilt_MyActivity extends FragmentActivity ",
+ "implements GeneratedComponentManagerHolder {",
+ "}"));
+ }
+
+ @Test
+ public void copySuppressWarningsAnnotation_onView_annotationCopied() {
+ JavaFileObject myView =
+ JavaFileObjects.forSourceLines(
+ "test.MyView",
+ "package test;",
+ "",
+ "import android.annotation.TargetApi;",
+ "import android.widget.LinearLayout;",
+ "import android.content.Context;",
+ "import android.util.AttributeSet;",
+ "import dagger.hilt.android.AndroidEntryPoint;",
+ "",
+ "@SuppressWarnings(\"deprecation\")",
+ "@AndroidEntryPoint(LinearLayout.class)",
+ "public class MyView extends Hilt_MyView {",
+ " public MyView(Context context, AttributeSet attributeSet){",
+ " super(context, attributeSet);",
+ " }",
+ "}");
+ Compilation compilation = compiler().compile(myView);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test/Hilt_MyView")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.Hilt_MyView",
+ "",
+ "package test;",
+ "",
+ "@Generated(\"dagger.hilt.android.processor.internal.androidentrypoint.ViewGenerator\")",
+ "@SuppressWarnings(\"deprecation\")",
+ "abstract class Hilt_MyView extends LinearLayout implements"
+ + " GeneratedComponentManagerHolder {",
+ "}"));
+ }
+
+ @Test
+ public void copySuppressWarningsAnnotation_onApplication_annotationCopied() {
+ JavaFileObject myApplication =
+ JavaFileObjects.forSourceLines(
+ "test.MyApplication",
+ "package test;",
+ "",
+ "import android.annotation.TargetApi;",
+ "import android.app.Application;",
+ "import dagger.hilt.android.HiltAndroidApp;",
+ "",
+ "@SuppressWarnings(\"deprecation\")",
+ "@HiltAndroidApp(Application.class)",
+ "public class MyApplication extends Hilt_MyApplication {}");
+ Compilation compilation = compiler().compile(myApplication);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test/Hilt_MyApplication")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.Hilt_MyApplication",
+ " package test;",
+ "",
+ "@Generated(\"dagger.hilt.android.processor.internal.androidentrypoint.ApplicationGenerator\")",
+ "@SuppressWarnings(\"deprecation\")",
+ "abstract class Hilt_MyApplication extends Application implements"
+ + " GeneratedComponentManagerHolder {}"));
+ }
+
+ @Test
+ public void copySuppressWarningsAnnotation_onFragment_annotationCopied() {
+ JavaFileObject myApplication =
+ JavaFileObjects.forSourceLines(
+ "test.MyFragment",
+ "package test;",
+ "",
+ "import android.annotation.TargetApi;",
+ "import androidx.fragment.app.Fragment;",
+ "import dagger.hilt.android.AndroidEntryPoint;",
+ "",
+ "@SuppressWarnings(\"rawtypes\")",
+ "@AndroidEntryPoint(Fragment.class)",
+ "public class MyFragment extends Hilt_MyFragment {}");
+ Compilation compilation = compiler().compile(myApplication);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test/Hilt_MyFragment")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.Hilt_MyFragment",
+ "package test;",
+ "",
+ "@Generated(\"dagger.hilt.android.processor.internal.androidentrypoint.FragmentGenerator\")",
+ "@SuppressWarnings(\"rawtypes\")",
+ "abstract class Hilt_MyFragment extends Fragment implements"
+ + " GeneratedComponentManagerHolder {}"));
+ }
+
+ @Test
+ public void copySuppressWarnings_onBroadcastRecieverGenerator_annotationCopied() {
+ JavaFileObject myBroadcastReceiver =
+ JavaFileObjects.forSourceLines(
+ "test.MyBroadcastReceiver",
+ "package test;",
+ "",
+ "import android.content.BroadcastReceiver;",
+ "import android.annotation.TargetApi;",
+ "import dagger.hilt.android.AndroidEntryPoint;",
+ "",
+ "@SuppressWarnings(\"deprecation\")",
+ "@AndroidEntryPoint(BroadcastReceiver.class)",
+ "public class MyBroadcastReceiver extends Hilt_MyBroadcastReceiver {}");
+ Compilation compilation = compiler().compile(myBroadcastReceiver);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test/Hilt_MyBroadcastReceiver")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.Hilt_MyBroadcastReceiver",
+ "package test;",
+ "",
+ "@Generated(\"dagger.hilt.android.processor.internal.androidentrypoint.BroadcastReceiverGenerator\")",
+ "@SuppressWarnings(\"deprecation\")",
+ "abstract class Hilt_MyBroadcastReceiver extends BroadcastReceiver {}"));
+ }
+
+ @Test
+ public void copySuppressWarnings_onServiceGenerator_annotationCopied() {
+ JavaFileObject myService =
+ JavaFileObjects.forSourceLines(
+ "test.MyService",
+ "package test;",
+ "",
+ "import android.annotation.TargetApi;",
+ "import android.content.Intent;",
+ "import android.app.Service;",
+ "import android.os.IBinder;",
+ "import dagger.hilt.android.AndroidEntryPoint;",
+ "",
+ "@SuppressWarnings(\"deprecation\")",
+ "@AndroidEntryPoint(Service.class)",
+ "public class MyService extends Hilt_MyService {",
+ " @Override",
+ " public IBinder onBind(Intent intent){",
+ " return null;",
+ " }",
+ "}");
+ Compilation compilation = compiler().compile(myService);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test/Hilt_MyService")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.Hilt_MyService",
+ "package test;",
+ "",
+ "@Generated(\"dagger.hilt.android.processor.internal.androidentrypoint.ServiceGenerator\")",
+ "@SuppressWarnings(\"deprecation\")",
+ "abstract class Hilt_MyService extends Service implements"
+ + " GeneratedComponentManagerHolder{}"));
+ }
}
diff --git a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD
index 654b573a0..79a45c4e5 100644
--- a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD
+++ b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD
@@ -33,10 +33,10 @@ compiler_test(
"@androidsdk//:platforms/android-30/android.jar",
],
deps = [
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "//javatests/dagger/hilt/android/processor:android_compilers",
+ "//third_party/java/compile_testing",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ "//java/dagger/hilt/android/testing/compile",
],
)
@@ -52,10 +52,10 @@ compiler_test(
"@androidsdk//:platforms/android-30/android.jar",
],
deps = [
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "//javatests/dagger/hilt/android/processor:android_compilers",
+ "//third_party/java/compile_testing",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ "//java/dagger/hilt/android/testing/compile",
],
)
diff --git a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/EarlyEntryPointProcessorTest.java b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/EarlyEntryPointProcessorTest.java
index 3bf3a31de..b39cd6b52 100644
--- a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/EarlyEntryPointProcessorTest.java
+++ b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/EarlyEntryPointProcessorTest.java
@@ -17,7 +17,7 @@
package dagger.hilt.android.processor.internal.aggregateddeps;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.processor.AndroidCompilers.compiler;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
diff --git a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/TestInstallInTest.java b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/TestInstallInTest.java
index 3af5be6fd..e4e9f674f 100644
--- a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/TestInstallInTest.java
+++ b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/TestInstallInTest.java
@@ -17,7 +17,7 @@
package dagger.hilt.android.processor.internal.aggregateddeps;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.processor.AndroidCompilers.compiler;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
diff --git a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGeneratorTest.java b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGeneratorTest.java
index 25a1abdeb..b6674d4a7 100644
--- a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGeneratorTest.java
+++ b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGeneratorTest.java
@@ -17,7 +17,7 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.processor.AndroidCompilers.compiler;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
diff --git a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessorTest.java b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessorTest.java
index c024a9c18..a5f85a252 100644
--- a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessorTest.java
+++ b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessorTest.java
@@ -17,7 +17,7 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.processor.AndroidCompilers.compiler;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
diff --git a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
index e53d9e26f..c1f9fd2f2 100644
--- a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
+++ b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
@@ -26,10 +26,10 @@ compiler_test(
"@androidsdk//:platforms/android-30/android.jar",
],
deps = [
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "//javatests/dagger/hilt/android/processor:android_compilers",
+ "//third_party/java/compile_testing",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ "//java/dagger/hilt/android/testing/compile",
],
)
@@ -42,10 +42,10 @@ compiler_test(
"@androidsdk//:platforms/android-30/android.jar",
],
deps = [
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "//javatests/dagger/hilt/android/processor:android_compilers",
+ "//third_party/java/compile_testing",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ "//java/dagger/hilt/android/testing/compile",
],
)
@@ -58,10 +58,10 @@ compiler_test(
"@androidsdk//:platforms/android-30/android.jar",
],
deps = [
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "//javatests/dagger/hilt/android/processor:android_compilers",
+ "//third_party/java/guava/collect",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ "//java/dagger/hilt/android/testing/compile",
"@maven//:com_github_tschuchortdev_kotlin_compile_testing",
],
)
diff --git a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/KotlinAndroidEntryPointProcessorTest.java b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/KotlinAndroidEntryPointProcessorTest.java
index 739c87c73..42875b197 100644
--- a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/KotlinAndroidEntryPointProcessorTest.java
+++ b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/KotlinAndroidEntryPointProcessorTest.java
@@ -16,7 +16,7 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
-import static dagger.hilt.android.processor.AndroidCompilers.kotlinCompiler;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.kotlinCompiler;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
diff --git a/javatests/dagger/hilt/android/processor/internal/customtestapplication/BUILD b/javatests/dagger/hilt/android/processor/internal/customtestapplication/BUILD
index 6fc39e435..2e564ec78 100644
--- a/javatests/dagger/hilt/android/processor/internal/customtestapplication/BUILD
+++ b/javatests/dagger/hilt/android/processor/internal/customtestapplication/BUILD
@@ -28,9 +28,9 @@ compiler_test(
"@androidsdk//:platforms/android-30/android.jar",
],
deps = [
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "//javatests/dagger/hilt/android/processor:android_compilers",
+ "//third_party/java/compile_testing",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ "//java/dagger/hilt/android/testing/compile",
],
)
diff --git a/javatests/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessorTest.java b/javatests/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessorTest.java
index f0372ab5b..beadecf9a 100644
--- a/javatests/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessorTest.java
+++ b/javatests/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessorTest.java
@@ -17,7 +17,7 @@
package dagger.hilt.android.processor.internal.customtestapplication;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.processor.AndroidCompilers.compiler;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
diff --git a/javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD b/javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD
index 030efd918..86342bd19 100644
--- a/javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD
+++ b/javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD
@@ -25,9 +25,9 @@ java_test(
runtime_deps = [
":ViewModelProcessorTestLib",
"//java/dagger/hilt/android/lifecycle",
+ "//third_party/java/compile_testing",
+ "//third_party/java/truth",
"@androidsdk//:platforms/android-30/android.jar",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/truth",
"@maven//:androidx_lifecycle_lifecycle_viewmodel",
"@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
],
@@ -41,9 +41,9 @@ kt_jvm_library(
deps = [
":test_utils",
"//java/dagger/hilt/android/processor/internal/viewmodel:processor_lib",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/compile_testing",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
@@ -52,9 +52,9 @@ java_test(
runtime_deps = [
":ViewModelGeneratorTestLib",
"//java/dagger/hilt/android/lifecycle",
+ "//third_party/java/compile_testing",
+ "//third_party/java/truth",
"@androidsdk//:platforms/android-30/android.jar",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/truth",
"@maven//:androidx_lifecycle_lifecycle_viewmodel",
"@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
],
@@ -68,9 +68,9 @@ kt_jvm_library(
deps = [
":test_utils",
"//java/dagger/hilt/android/processor/internal/viewmodel:processor_lib",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/compile_testing",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
@@ -83,8 +83,8 @@ kt_compiler_test(
"@androidsdk//:platforms/android-30/android.jar",
"@maven//:androidx_lifecycle_lifecycle_viewmodel",
"@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/compile_testing",
+ "//third_party/java/truth",
"//java/dagger/hilt/android/lifecycle",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android:hilt_android_app",
@@ -94,10 +94,10 @@ kt_compiler_test(
"//:compiler_internals",
"//java/dagger/hilt/android/processor/internal/viewmodel:processor_lib",
"//java/dagger/hilt/android/processor/internal/viewmodel:validation_plugin_lib",
- "//javatests/dagger/hilt/android/processor:android_compilers",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//java/dagger/hilt/android/testing/compile",
+ "//third_party/java/compile_testing",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
@@ -107,6 +107,6 @@ kt_jvm_library(
"TestUtils.kt",
],
deps = [
- "@google_bazel_common//third_party/java/compile_testing",
+ "//third_party/java/compile_testing",
],
)
diff --git a/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelGeneratorTest.kt b/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelGeneratorTest.kt
index df020ffa9..c2378e030 100644
--- a/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelGeneratorTest.kt
+++ b/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelGeneratorTest.kt
@@ -46,21 +46,6 @@ class ViewModelGeneratorTest {
val expected = """
package dagger.hilt.android.test;
- import androidx.lifecycle.ViewModel;
- import dagger.Binds;
- import dagger.Module;
- import dagger.Provides;
- import dagger.hilt.InstallIn;
- import dagger.hilt.android.components.ActivityRetainedComponent;
- import dagger.hilt.android.components.ViewModelComponent;
- import dagger.hilt.android.internal.lifecycle.HiltViewModelMap;
- import dagger.hilt.codegen.OriginatingElement;
- import dagger.multibindings.IntoMap;
- import dagger.multibindings.IntoSet;
- import dagger.multibindings.StringKey;
- import java.lang.String;
- import $GENERATED_TYPE
-
$GENERATED_ANNOTATION
@OriginatingElement(
topLevelClass = MyViewModel.class
@@ -102,7 +87,7 @@ class ViewModelGeneratorTest {
assertThat(compilation).apply {
succeeded()
generatedSourceFile("dagger.hilt.android.test.MyViewModel_HiltModules")
- .hasSourceEquivalentTo(expected)
+ .containsElementsIn(expected)
}
}
@@ -126,21 +111,6 @@ class ViewModelGeneratorTest {
val expected = """
package dagger.hilt.android.test;
- import androidx.lifecycle.ViewModel;
- import dagger.Binds;
- import dagger.Module;
- import dagger.Provides;
- import dagger.hilt.InstallIn;
- import dagger.hilt.android.components.ActivityRetainedComponent;
- import dagger.hilt.android.components.ViewModelComponent;
- import dagger.hilt.android.internal.lifecycle.HiltViewModelMap;
- import dagger.hilt.codegen.OriginatingElement;
- import dagger.multibindings.IntoMap;
- import dagger.multibindings.IntoSet;
- import dagger.multibindings.StringKey;
- import java.lang.String;
- import $GENERATED_TYPE
-
$GENERATED_ANNOTATION
@OriginatingElement(
topLevelClass = MyViewModel.class
@@ -182,7 +152,7 @@ class ViewModelGeneratorTest {
assertThat(compilation).apply {
succeeded()
generatedSourceFile("dagger.hilt.android.test.MyViewModel_HiltModules")
- .hasSourceEquivalentTo(expected)
+ .containsElementsIn(expected)
}
}
@@ -213,21 +183,6 @@ class ViewModelGeneratorTest {
val expected = """
package dagger.hilt.android.test;
- import androidx.lifecycle.ViewModel;
- import dagger.Binds;
- import dagger.Module;
- import dagger.Provides;
- import dagger.hilt.InstallIn;
- import dagger.hilt.android.components.ActivityRetainedComponent;
- import dagger.hilt.android.components.ViewModelComponent;
- import dagger.hilt.android.internal.lifecycle.HiltViewModelMap;
- import dagger.hilt.codegen.OriginatingElement;
- import dagger.multibindings.IntoMap;
- import dagger.multibindings.IntoSet;
- import dagger.multibindings.StringKey;
- import java.lang.String;
- import $GENERATED_TYPE
-
$GENERATED_ANNOTATION
@OriginatingElement(
topLevelClass = MyViewModel.class
@@ -269,7 +224,7 @@ class ViewModelGeneratorTest {
assertThat(compilation).apply {
succeeded()
generatedSourceFile("dagger.hilt.android.test.MyViewModel_HiltModules")
- .hasSourceEquivalentTo(expected)
+ .containsElementsIn(expected)
}
}
@@ -301,21 +256,6 @@ class ViewModelGeneratorTest {
val expected = """
package dagger.hilt.android.test;
- import androidx.lifecycle.ViewModel;
- import dagger.Binds;
- import dagger.Module;
- import dagger.Provides;
- import dagger.hilt.InstallIn;
- import dagger.hilt.android.components.ActivityRetainedComponent;
- import dagger.hilt.android.components.ViewModelComponent;
- import dagger.hilt.android.internal.lifecycle.HiltViewModelMap;
- import dagger.hilt.codegen.OriginatingElement;
- import dagger.multibindings.IntoMap;
- import dagger.multibindings.IntoSet;
- import dagger.multibindings.StringKey;
- import java.lang.String;
- import $GENERATED_TYPE;
-
$GENERATED_ANNOTATION
@OriginatingElement(
topLevelClass = MyViewModel.class
@@ -357,7 +297,7 @@ class ViewModelGeneratorTest {
assertThat(compilation).apply {
succeeded()
generatedSourceFile("dagger.hilt.android.test.MyViewModel_HiltModules")
- .hasSourceEquivalentTo(expected)
+ .containsElementsIn(expected)
}
}
@@ -396,21 +336,6 @@ class ViewModelGeneratorTest {
val expected = """
package dagger.hilt.android.test;
- import androidx.lifecycle.ViewModel;
- import dagger.Binds;
- import dagger.Module;
- import dagger.Provides;
- import dagger.hilt.InstallIn;
- import dagger.hilt.android.components.ActivityRetainedComponent;
- import dagger.hilt.android.components.ViewModelComponent;
- import dagger.hilt.android.internal.lifecycle.HiltViewModelMap;
- import dagger.hilt.codegen.OriginatingElement;
- import dagger.multibindings.IntoMap;
- import dagger.multibindings.IntoSet;
- import dagger.multibindings.StringKey;
- import java.lang.String;
- import $GENERATED_TYPE;
-
$GENERATED_ANNOTATION
@OriginatingElement(
topLevelClass = MyViewModel.class
@@ -452,7 +377,7 @@ class ViewModelGeneratorTest {
assertThat(compilation).apply {
succeeded()
generatedSourceFile("dagger.hilt.android.test.MyViewModel_HiltModules")
- .hasSourceEquivalentTo(expected)
+ .containsElementsIn(expected)
}
}
@@ -477,21 +402,6 @@ class ViewModelGeneratorTest {
val expectedModule = """
package dagger.hilt.android.test;
- import androidx.lifecycle.ViewModel;
- import dagger.Binds;
- import dagger.Module;
- import dagger.Provides;
- import dagger.hilt.InstallIn;
- import dagger.hilt.android.components.ActivityRetainedComponent;
- import dagger.hilt.android.components.ViewModelComponent;
- import dagger.hilt.android.internal.lifecycle.HiltViewModelMap;
- import dagger.hilt.codegen.OriginatingElement;
- import dagger.multibindings.IntoMap;
- import dagger.multibindings.IntoSet;
- import dagger.multibindings.StringKey;
- import java.lang.String;
- import $GENERATED_TYPE
-
$GENERATED_ANNOTATION
@OriginatingElement(
topLevelClass = Outer.class
@@ -533,7 +443,7 @@ class ViewModelGeneratorTest {
assertThat(compilation).apply {
succeeded()
generatedSourceFile("dagger.hilt.android.test.Outer_InnerViewModel_HiltModules")
- .hasSourceEquivalentTo(expectedModule)
+ .containsElementsIn(expectedModule)
}
}
}
diff --git a/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPluginTest.kt b/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPluginTest.kt
index b5c22c1a3..5fe40ddb9 100644
--- a/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPluginTest.kt
+++ b/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPluginTest.kt
@@ -18,7 +18,7 @@ package dagger.hilt.android.processor.internal.viewmodel
import com.google.testing.compile.CompilationSubject.assertThat
import com.google.testing.compile.Compiler
-import dagger.hilt.android.processor.AndroidCompilers.compiler
+import dagger.hilt.android.testing.compile.HiltCompilerTests.compiler
import dagger.internal.codegen.ComponentProcessor
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/javatests/dagger/hilt/android/testing/BUILD b/javatests/dagger/hilt/android/testing/BUILD
index e3367778d..4b3cac97b 100644
--- a/javatests/dagger/hilt/android/testing/BUILD
+++ b/javatests/dagger/hilt/android/testing/BUILD
@@ -25,8 +25,8 @@ android_local_test(
},
deps = [
"//:android_local_test_exports",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/truth",
"//java/dagger/hilt:entry_point",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android/testing:bind_value",
@@ -44,10 +44,10 @@ android_local_test(
},
deps = [
"//:android_local_test_exports",
- "@google_bazel_common//third_party/java/auto:value",
+ "//third_party/java/auto:value",
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/truth",
"//java/dagger/hilt:entry_point",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android/testing:bind_value",
@@ -66,8 +66,8 @@ android_local_test(
deps = [
"//:android_local_test_exports",
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/truth",
"//java/dagger/hilt:entry_point",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android/testing:bind_value",
@@ -85,10 +85,10 @@ android_local_test(
},
deps = [
"//:android_local_test_exports",
- "//java/dagger/internal/guava:collect",
+ "//third_party/java/guava/collect",
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/truth",
"//java/dagger/hilt:entry_point",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android/testing:bind_value",
@@ -107,7 +107,7 @@ android_local_test(
deps = [
"//:android_local_test_exports",
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/jsr330_inject",
+ "//third_party/java/jsr330_inject",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android/testing:hilt_android_test",
@@ -125,11 +125,9 @@ android_local_test(
deps = [
":HiltAndroidRuleTestApp",
"//:android_local_test_exports",
- "//java/dagger/internal/guava:collect",
+ "//third_party/java/guava/collect",
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
- "//java/dagger/hilt/android/qualifiers",
+ "//third_party/java/truth",
"//java/dagger/hilt/android/testing:hilt_android_rule",
"//java/dagger/hilt/android/testing:hilt_android_test",
],
@@ -152,8 +150,7 @@ android_local_test(
},
deps = [
"//:android_local_test_exports",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/truth",
"//java/dagger/hilt:entry_point",
"//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android/testing:bind_value",
diff --git a/javatests/dagger/hilt/android/testing/HiltAndroidRuleTestApp.java b/javatests/dagger/hilt/android/testing/HiltAndroidRuleTestApp.java
index 9ec7d0869..9ec5d751a 100644
--- a/javatests/dagger/hilt/android/testing/HiltAndroidRuleTestApp.java
+++ b/javatests/dagger/hilt/android/testing/HiltAndroidRuleTestApp.java
@@ -21,4 +21,4 @@ import dagger.hilt.android.HiltAndroidApp;
/** A Hilt application used to test errors in {@link HiltAndroidRuleTest}. */
@HiltAndroidApp(Application.class)
-final class HiltAndroidRuleTestApp extends Hilt_HiltAndroidRuleTestApp {}
+public final class HiltAndroidRuleTestApp extends Hilt_HiltAndroidRuleTestApp {}
diff --git a/javatests/dagger/hilt/android/testing/testinstallin/BUILD b/javatests/dagger/hilt/android/testing/testinstallin/BUILD
index 63d0bca95..67f3c3512 100644
--- a/javatests/dagger/hilt/android/testing/testinstallin/BUILD
+++ b/javatests/dagger/hilt/android/testing/testinstallin/BUILD
@@ -33,7 +33,7 @@ android_local_test(
"@maven//:androidx_test_ext_junit",
"@maven//:androidx_test_core",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/truth",
"//java/dagger/hilt/android/testing:hilt_android_test",
],
)
@@ -55,7 +55,7 @@ android_local_test(
"@maven//:androidx_test_ext_junit",
"@maven//:androidx_test_core",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/truth",
"//java/dagger/hilt/android/testing:hilt_android_test",
"//java/dagger/hilt/android/testing:uninstall_modules",
"//java/dagger/hilt/testing:test_install_in",
@@ -79,7 +79,7 @@ android_local_test(
"@maven//:androidx_test_ext_junit",
"@maven//:androidx_test_core",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/processor/internal/BUILD b/javatests/dagger/hilt/processor/internal/BUILD
index e6e1cfb4e..3dfe1ea73 100644
--- a/javatests/dagger/hilt/processor/internal/BUILD
+++ b/javatests/dagger/hilt/processor/internal/BUILD
@@ -23,9 +23,9 @@ java_test(
srcs = ["ProcessorsTest.java"],
deps = [
"//java/dagger/hilt/processor/internal:processors",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/javapoet",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD b/javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD
index f52b051d7..180bba1b8 100644
--- a/javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD
+++ b/javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD
@@ -27,7 +27,7 @@ compiler_test(
"//java/dagger/hilt/internal:component_entry_point",
"//java/dagger/hilt/internal:generated_entry_point",
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/jsr250_annotations",
+ "//third_party/java/jsr250_annotations",
"//java/dagger/hilt:entry_point",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android/testing:hilt_android_test",
@@ -35,11 +35,11 @@ compiler_test(
],
deps = [
"//java/dagger/hilt/processor/internal/aggregateddeps:processor_lib",
- "//java/dagger/internal/guava:base",
"//javatests/dagger/hilt/processor/internal:generated_import",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/compile_testing",
+ "//third_party/java/guava/base",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/processor/internal/aliasof/AliasOfProcessorTest.java b/javatests/dagger/hilt/processor/internal/aliasof/AliasOfProcessorTest.java
new file mode 100644
index 000000000..f04dc7649
--- /dev/null
+++ b/javatests/dagger/hilt/processor/internal/aliasof/AliasOfProcessorTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal.aliasof;
+
+import static com.google.testing.compile.CompilationSubject.assertThat;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
+
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for failure on alias scope used on DefineComponent. */
+@RunWith(JUnit4.class)
+public final class AliasOfProcessorTest {
+ @Test
+ public void fails_componentScopedWithAliasScope() {
+ JavaFileObject scope =
+ JavaFileObjects.forSourceLines(
+ "test.AliasScope",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "import javax.inject.Singleton;",
+ "import dagger.hilt.migration.AliasOf;",
+ "",
+ "@Scope",
+ "@AliasOf(Singleton.class)",
+ "public @interface AliasScope{}");
+
+ JavaFileObject root =
+ JavaFileObjects.forSourceLines(
+ "test.MyApp",
+ "package test;",
+ "",
+ "import android.app.Application;",
+ "import dagger.hilt.android.HiltAndroidApp;",
+ "",
+ "@HiltAndroidApp(Application.class)",
+ "public final class MyApp extends Hilt_MyApp {}");
+
+ JavaFileObject defineComponent =
+ JavaFileObjects.forSourceLines(
+ "test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.hilt.DefineComponent;",
+ "import dagger.hilt.components.SingletonComponent;",
+ "",
+ "@DefineComponent(parent = SingletonComponent.class)",
+ "@AliasScope",
+ "public interface ChildComponent {}");
+
+ Compilation compilation =
+ compiler()
+ .withOptions("-Xlint:-processing") // Suppresses unclaimed annotation warning
+ .compile(root, defineComponent, scope);
+
+ assertThat(compilation).failed();
+ // One extra error for the missing Hilt_MyApp reference
+ assertThat(compilation).hadErrorCount(2);
+ assertThat(compilation)
+ .hadErrorContaining(
+ "@DefineComponent test.ChildComponent, references invalid scope(s) annotated with"
+ + " @AliasOf. @DefineComponent scopes cannot be aliases of other scopes:"
+ + " [@test.AliasScope]");
+ }
+
+ @Test
+ public void fails_conflictingAliasScope() {
+ JavaFileObject scope =
+ JavaFileObjects.forSourceLines(
+ "test.AliasScope",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "import javax.inject.Singleton;",
+ "import dagger.hilt.android.scopes.ActivityScoped;",
+ "import dagger.hilt.migration.AliasOf;",
+ "",
+ "@Scope",
+ "@AliasOf({Singleton.class, ActivityScoped.class})",
+ "public @interface AliasScope{}");
+
+ JavaFileObject root =
+ JavaFileObjects.forSourceLines(
+ "test.MyApp",
+ "package test;",
+ "",
+ "import android.app.Application;",
+ "import dagger.hilt.android.HiltAndroidApp;",
+ "",
+ "@HiltAndroidApp(Application.class)",
+ "public final class MyApp extends Hilt_MyApp {}");
+
+ Compilation compilation =
+ compiler()
+ .withOptions("-Xlint:-processing") // Suppresses unclaimed annotation warning
+ .compile(root, scope);
+
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(1);
+ assertThat(compilation).hadErrorContaining("has conflicting scopes");
+ }
+}
diff --git a/javatests/dagger/hilt/processor/internal/aliasof/BUILD b/javatests/dagger/hilt/processor/internal/aliasof/BUILD
new file mode 100644
index 000000000..3a7b4af68
--- /dev/null
+++ b/javatests/dagger/hilt/processor/internal/aliasof/BUILD
@@ -0,0 +1,40 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Description:
+# Builds and run tests related to AliasOfProcessor.
+
+load("//java/dagger/testing/compile:macros.bzl", "compiler_test")
+
+package(default_visibility = ["//:src"])
+
+compiler_test(
+ name = "AliasOfProcessorTest",
+ size = "small",
+ srcs = ["AliasOfProcessorTest.java"],
+ compiler_deps = [
+ "@androidsdk//:platforms/android-30/android.jar",
+ "//third_party/java/jsr330_inject",
+ "//java/dagger/hilt/android:hilt_android_app",
+ "//java/dagger/hilt/android/components",
+ "//java/dagger/hilt:define_component",
+ "//java/dagger/hilt/migration:alias_of",
+ ],
+ deps = [
+ "//third_party/java/compile_testing",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ "//java/dagger/hilt/android/testing/compile",
+ ],
+)
diff --git a/javatests/dagger/hilt/processor/internal/definecomponent/BUILD b/javatests/dagger/hilt/processor/internal/definecomponent/BUILD
index ce5cc0aef..9de94bad3 100644
--- a/javatests/dagger/hilt/processor/internal/definecomponent/BUILD
+++ b/javatests/dagger/hilt/processor/internal/definecomponent/BUILD
@@ -34,9 +34,9 @@ GenJavaTests(
"//java/dagger/hilt/processor/internal/definecomponent:define_components",
"//java/dagger/hilt/processor/internal/definecomponent:processor_lib",
"//javatests/dagger/hilt/processor/internal:generated_import",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/compile_testing",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessorTest.java b/javatests/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessorTest.java
index a8c5fbe9c..373061c5f 100644
--- a/javatests/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessorTest.java
+++ b/javatests/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessorTest.java
@@ -22,7 +22,6 @@ import static com.google.testing.compile.Compiler.javac;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.Compiler;
import com.google.testing.compile.JavaFileObjects;
-import dagger.hilt.processor.internal.GeneratedImport;
import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -67,9 +66,6 @@ public final class DefineComponentProcessorTest {
"dagger.hilt.processor.internal.definecomponent.codegen._test_FooComponent",
"package dagger.hilt.processor.internal.definecomponent.codegen;",
"",
- "import dagger.hilt.internal.definecomponent.DefineComponentClasses;",
- GeneratedImport.IMPORT_GENERATED_ANNOTATION,
- "",
"@DefineComponentClasses(component = \"test.FooComponent\")",
"@Generated(\"" + DefineComponentProcessor.class.getName() + "\")",
"public class _test_FooComponent {}");
@@ -79,9 +75,6 @@ public final class DefineComponentProcessorTest {
"dagger.hilt.processor.internal.definecomponent.codegen._test_FooComponentBuilder",
"package dagger.hilt.processor.internal.definecomponent.codegen;",
"",
- "import dagger.hilt.internal.definecomponent.DefineComponentClasses;",
- GeneratedImport.IMPORT_GENERATED_ANNOTATION,
- "",
"@DefineComponentClasses(builder = \"test.FooComponentBuilder\")",
"@Generated(\"" + DefineComponentProcessor.class.getName() + "\")",
"public class _test_FooComponentBuilder {}");
@@ -90,10 +83,10 @@ public final class DefineComponentProcessorTest {
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile(sourceName(componentOutput))
- .hasSourceEquivalentTo(componentOutput);
+ .containsElementsIn(componentOutput);
assertThat(compilation)
.generatedSourceFile(sourceName(builderOutput))
- .hasSourceEquivalentTo(builderOutput);
+ .containsElementsIn(builderOutput);
}
private static String sourceName(JavaFileObject fileObject) {
diff --git a/javatests/dagger/hilt/processor/internal/disableinstallincheck/BUILD b/javatests/dagger/hilt/processor/internal/disableinstallincheck/BUILD
index 90b0596b6..11252a6f9 100644
--- a/javatests/dagger/hilt/processor/internal/disableinstallincheck/BUILD
+++ b/javatests/dagger/hilt/processor/internal/disableinstallincheck/BUILD
@@ -26,14 +26,14 @@ compiler_test(
compiler_deps = [
"//java/dagger/hilt/migration:disable_install_in_check",
"//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/jsr250_annotations",
+ "//third_party/java/jsr250_annotations",
"//java/dagger/hilt:entry_point",
],
deps = [
"//java/dagger/hilt/processor/internal/disableinstallincheck:processor_lib",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/compile_testing",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD b/javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD
index c5dacd9f8..a815ecd54 100644
--- a/javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD
+++ b/javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD
@@ -31,11 +31,11 @@ GenJavaTests(
"//java/dagger/hilt/processor/internal:base_processor",
"//java/dagger/hilt/processor/internal/generatesrootinput:generates_root_inputs",
"//java/dagger/hilt/processor/internal/generatesrootinput:processor_lib",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/compile_testing",
+ "//third_party/java/javapoet",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessorTest.java b/javatests/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessorTest.java
index fb62c3d12..48818d4d6 100644
--- a/javatests/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessorTest.java
+++ b/javatests/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessorTest.java
@@ -74,7 +74,7 @@ public final class GeneratesRootInputProcessorTest {
}
@Test
- public void succeeds_ComponentProcessorWaitsForAnnotationsWithgeneratesstinginput() {
+ public void succeeds_ComponentProcessorWaitsForAnnotationsWithGeneratesRootInput() {
JavaFileObject testAnnotation =
JavaFileObjects.forSourceLines(
"test.TestAnnotation",
diff --git a/javatests/dagger/hilt/processor/internal/originatingelement/BUILD b/javatests/dagger/hilt/processor/internal/originatingelement/BUILD
index 3135159ce..c45cfb6e9 100644
--- a/javatests/dagger/hilt/processor/internal/originatingelement/BUILD
+++ b/javatests/dagger/hilt/processor/internal/originatingelement/BUILD
@@ -28,10 +28,10 @@ compiler_test(
"@maven//:androidx_annotation_annotation",
],
deps = [
- "//javatests/dagger/hilt/android/processor:android_compilers",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//java/dagger/hilt/android/testing/compile",
+ "//third_party/java/compile_testing",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessorTest.java b/javatests/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessorTest.java
index 444fb1d67..5dc7a11f4 100644
--- a/javatests/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessorTest.java
+++ b/javatests/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessorTest.java
@@ -17,7 +17,7 @@
package dagger.hilt.processor.internal.originatingelement;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.processor.AndroidCompilers.compiler;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
diff --git a/javatests/dagger/hilt/processor/internal/root/BUILD b/javatests/dagger/hilt/processor/internal/root/BUILD
index 0dba875c7..ef2344c1d 100644
--- a/javatests/dagger/hilt/processor/internal/root/BUILD
+++ b/javatests/dagger/hilt/processor/internal/root/BUILD
@@ -40,11 +40,11 @@ compiler_test(
"@maven//:androidx_test_core",
],
deps = [
- "//java/dagger/internal/guava:collect",
- "//javatests/dagger/hilt/android/processor:android_compilers",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//java/dagger/hilt/android/testing/compile",
+ "//third_party/java/compile_testing",
+ "//third_party/java/guava/collect",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
@@ -71,11 +71,11 @@ compiler_test(
"@maven//:androidx_test_core",
],
deps = [
- "//java/dagger/internal/guava:collect",
- "//javatests/dagger/hilt/android/processor:android_compilers",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//java/dagger/hilt/android/testing/compile",
+ "//third_party/java/compile_testing",
+ "//third_party/java/guava/collect",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
@@ -92,11 +92,11 @@ compiler_test(
"@maven//:androidx_test_core",
],
deps = [
- "//java/dagger/internal/guava:collect",
- "//javatests/dagger/hilt/android/processor:android_compilers",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//java/dagger/hilt/android/testing/compile",
+ "//third_party/java/compile_testing",
+ "//third_party/java/guava/collect",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
@@ -113,11 +113,11 @@ compiler_test(
"@maven//:androidx_test_core",
],
deps = [
- "//java/dagger/internal/guava:base",
- "//javatests/dagger/hilt/android/processor:android_compilers",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//java/dagger/hilt/android/testing/compile",
+ "//third_party/java/compile_testing",
+ "//third_party/java/guava/base",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/processor/internal/root/MyAppPreviousCompilationTest.java b/javatests/dagger/hilt/processor/internal/root/MyAppPreviousCompilationTest.java
index adf6d9b2d..e4aa5abe7 100644
--- a/javatests/dagger/hilt/processor/internal/root/MyAppPreviousCompilationTest.java
+++ b/javatests/dagger/hilt/processor/internal/root/MyAppPreviousCompilationTest.java
@@ -23,7 +23,7 @@ import com.google.common.collect.ImmutableList;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.Compiler;
import com.google.testing.compile.JavaFileObjects;
-import dagger.hilt.android.processor.AndroidCompilers;
+import dagger.hilt.android.testing.compile.HiltCompilerTests;
import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,7 +45,7 @@ public final class MyAppPreviousCompilationTest {
}
private Compiler compiler() {
- return AndroidCompilers.compiler()
+ return HiltCompilerTests.compiler()
.withOptions(
String.format(
"-Adagger.hilt.disableCrossCompilationRootValidation=%s",
@@ -90,11 +90,11 @@ public final class MyAppPreviousCompilationTest {
assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
- "Cannot process app roots in this compilation unit since there are app roots in a "
+ "Cannot process new app roots when there are app roots from a "
+ "previous compilation unit:"
- + "\n \tApp roots in previous compilation unit: ["
- + "dagger.hilt.processor.internal.root.MyAppPreviousCompilation.MyApp]"
- + "\n \tApp roots in this compilation unit: [test.AppRoot]");
+ + "\n App roots in previous compilation unit: "
+ + "dagger.hilt.processor.internal.root.MyAppPreviousCompilation.MyApp"
+ + "\n App roots in this compilation unit: test.AppRoot");
}
}
}
diff --git a/javatests/dagger/hilt/processor/internal/root/MyTestPreviousCompilationTest.java b/javatests/dagger/hilt/processor/internal/root/MyTestPreviousCompilationTest.java
index 9e9fae57e..82251bd70 100644
--- a/javatests/dagger/hilt/processor/internal/root/MyTestPreviousCompilationTest.java
+++ b/javatests/dagger/hilt/processor/internal/root/MyTestPreviousCompilationTest.java
@@ -23,7 +23,7 @@ import com.google.common.collect.ImmutableList;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.Compiler;
import com.google.testing.compile.JavaFileObjects;
-import dagger.hilt.android.processor.AndroidCompilers;
+import dagger.hilt.android.testing.compile.HiltCompilerTests;
import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,7 +45,7 @@ public final class MyTestPreviousCompilationTest {
}
private Compiler compiler() {
- return AndroidCompilers.compiler()
+ return HiltCompilerTests.compiler()
.withOptions(
String.format(
"-Adagger.hilt.disableCrossCompilationRootValidation=%s",
@@ -73,9 +73,9 @@ public final class MyTestPreviousCompilationTest {
assertThat(compilation)
.hadErrorContaining(
"Cannot process new roots when there are test roots from a previous compilation unit:"
- + "\n \tTest roots from previous compilation unit: "
- + "[dagger.hilt.processor.internal.root.MyTestPreviousCompilation.MyTest]"
- + "\n \tAll roots from this compilation unit: [test.TestRoot]");
+ + "\n Test roots from previous compilation unit: "
+ + "dagger.hilt.processor.internal.root.MyTestPreviousCompilation.MyTest"
+ + "\n All roots from this compilation unit: test.TestRoot");
}
}
@@ -101,9 +101,9 @@ public final class MyTestPreviousCompilationTest {
assertThat(compilation)
.hadErrorContaining(
"Cannot process new roots when there are test roots from a previous compilation unit:"
- + "\n \tTest roots from previous compilation unit: "
- + "[dagger.hilt.processor.internal.root.MyTestPreviousCompilation.MyTest]"
- + "\n \tAll roots from this compilation unit: [test.AppRoot]");
+ + "\n Test roots from previous compilation unit: "
+ + "dagger.hilt.processor.internal.root.MyTestPreviousCompilation.MyTest"
+ + "\n All roots from this compilation unit: test.AppRoot");
}
}
}
diff --git a/javatests/dagger/hilt/processor/internal/root/RootFileFormatterTest.java b/javatests/dagger/hilt/processor/internal/root/RootFileFormatterTest.java
index 6d598c83f..53ef42c9c 100644
--- a/javatests/dagger/hilt/processor/internal/root/RootFileFormatterTest.java
+++ b/javatests/dagger/hilt/processor/internal/root/RootFileFormatterTest.java
@@ -17,7 +17,7 @@
package dagger.hilt.processor.internal.root;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.processor.AndroidCompilers.compiler;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
import com.google.common.base.Joiner;
import com.google.testing.compile.Compilation;
@@ -83,6 +83,7 @@ public final class RootFileFormatterTest {
public void testTestComponents() {
Compilation compilation =
compiler()
+ .withOptions("-Adagger.hilt.shareTestComponents=false")
.compile(
JavaFileObjects.forSourceLines(
"test.MyTest",
diff --git a/javatests/dagger/hilt/processor/internal/root/RootProcessorErrorsTest.java b/javatests/dagger/hilt/processor/internal/root/RootProcessorErrorsTest.java
index e9ed8c418..c07ee5347 100644
--- a/javatests/dagger/hilt/processor/internal/root/RootProcessorErrorsTest.java
+++ b/javatests/dagger/hilt/processor/internal/root/RootProcessorErrorsTest.java
@@ -23,7 +23,7 @@ import com.google.common.collect.ImmutableList;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.Compiler;
import com.google.testing.compile.JavaFileObjects;
-import dagger.hilt.android.processor.AndroidCompilers;
+import dagger.hilt.android.testing.compile.HiltCompilerTests;
import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,7 +45,7 @@ public final class RootProcessorErrorsTest {
}
private Compiler compiler() {
- return AndroidCompilers.compiler()
+ return HiltCompilerTests.compiler()
.withOptions(
String.format(
"-Adagger.hilt.disableCrossCompilationRootValidation=%s",
@@ -83,7 +83,7 @@ public final class RootProcessorErrorsTest {
assertThat(compilation)
.hadErrorContaining(
"Cannot process multiple app roots in the same compilation unit: "
- + "[test.AppRoot1, test.AppRoot2]");
+ + "test.AppRoot1, test.AppRoot2");
}
@Test
@@ -116,7 +116,7 @@ public final class RootProcessorErrorsTest {
assertThat(compilation)
.hadErrorContaining(
"Cannot process test roots and app roots in the same compilation unit:"
- + "\n \tApp root in this compilation unit: [test.AppRoot]"
- + "\n \tTest roots in this compilation unit: [test.TestRoot]");
+ + "\n App root in this compilation unit: test.AppRoot"
+ + "\n Test roots in this compilation unit: test.TestRoot");
}
}
diff --git a/javatests/dagger/hilt/processor/internal/uninstallmodules/BUILD b/javatests/dagger/hilt/processor/internal/uninstallmodules/BUILD
index caceb7ce5..e407193b4 100644
--- a/javatests/dagger/hilt/processor/internal/uninstallmodules/BUILD
+++ b/javatests/dagger/hilt/processor/internal/uninstallmodules/BUILD
@@ -31,10 +31,10 @@ compiler_test(
"@maven//:androidx_annotation_annotation",
],
deps = [
- "//javatests/dagger/hilt/android/processor:android_compilers",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//java/dagger/hilt/android/testing/compile",
+ "//third_party/java/compile_testing",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessorTest.java b/javatests/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessorTest.java
index 2be9ab670..04b5a2461 100644
--- a/javatests/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessorTest.java
+++ b/javatests/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessorTest.java
@@ -17,7 +17,7 @@
package dagger.hilt.processor.internal.uninstallmodules;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.processor.AndroidCompilers.compiler;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
diff --git a/javatests/dagger/hilt/testmodules/BUILD b/javatests/dagger/hilt/testmodules/BUILD
index 7acd3d1ae..f7aef8024 100644
--- a/javatests/dagger/hilt/testmodules/BUILD
+++ b/javatests/dagger/hilt/testmodules/BUILD
@@ -27,7 +27,7 @@ kt_android_library(
"//:dagger_with_compiler",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/components",
- "@google_bazel_common//third_party/java/jsr330_inject",
+ "//third_party/java/jsr330_inject",
],
)
diff --git a/javatests/dagger/internal/codegen/AssistedFactoryErrorsTest.java b/javatests/dagger/internal/codegen/AssistedFactoryErrorsTest.java
index 42b8f8a99..09f9fab75 100644
--- a/javatests/dagger/internal/codegen/AssistedFactoryErrorsTest.java
+++ b/javatests/dagger/internal/codegen/AssistedFactoryErrorsTest.java
@@ -620,7 +620,7 @@ public class AssistedFactoryErrorsTest {
}
@Test
- public void testInjectsProviderOfAssistedFactory() {
+ public void testInjectsLazyOfAssistedFactory() {
JavaFileObject foo =
JavaFileObjects.forSourceLines(
"test.Foo",
@@ -644,12 +644,12 @@ public class AssistedFactoryErrorsTest {
"test.Bar",
"package test;",
"",
+ "import dagger.Lazy;",
"import javax.inject.Inject;",
- "import javax.inject.Provider;",
"",
"class Bar {",
" @Inject",
- " Bar(Foo.Factory fooFactory, Provider<Foo.Factory> fooFactoryProvider) {}",
+ " Bar(Foo.Factory fooFactory, Lazy<Foo.Factory> fooFactoryLazy) {}",
"}");
Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo, bar);
@@ -657,7 +657,7 @@ public class AssistedFactoryErrorsTest {
assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
- "Dagger does not support injecting Provider<T>, Lazy<T>, Producer<T>, or Produced<T> "
+ "Dagger does not support injecting Lazy<T>, Producer<T>, or Produced<T> "
+ "when T is an @AssistedFactory-annotated type such as test.Foo.Factory")
.inFile(bar)
.onLine(8);
diff --git a/javatests/dagger/internal/codegen/AssistedFactoryTest.java b/javatests/dagger/internal/codegen/AssistedFactoryTest.java
index cffd42eba..7691e1e26 100644
--- a/javatests/dagger/internal/codegen/AssistedFactoryTest.java
+++ b/javatests/dagger/internal/codegen/AssistedFactoryTest.java
@@ -99,19 +99,39 @@ public class AssistedFactoryTest {
.addLinesIn(
FAST_INIT_MODE,
"final class DaggerTestComponent implements TestComponent {",
+ " private final DaggerTestComponent testComponent = this;",
+ " private Provider<FooFactory> fooFactoryProvider;",
"",
- " private Foo foo(String str) {",
- " return new Foo(str, new Bar());",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.fooFactoryProvider = SingleCheck.provider(new"
+ + " SwitchingProvider<FooFactory>(testComponent, 0));",
" }",
"",
" @Override",
" public FooFactory fooFactory() {",
- " return new FooFactory() {",
- " @Override",
- " public Foo create(String str) {",
- " return DaggerTestComponent.this.foo(str);",
+ " return fooFactoryProvider.get();",
+ " }",
+ "",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " private final DaggerTestComponent testComponent;",
+ " private final int id;",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0:",
+ " return (T) new FooFactory() {",
+ " @Override",
+ " public Foo create(String str) {",
+ " return new Foo(str, new Bar());",
+ " }",
+ " };",
+ "",
+ " default: throw new AssertionError(id);",
" }",
- " };",
+ " }",
" }",
"}")
.addLinesIn(
@@ -195,23 +215,43 @@ public class AssistedFactoryTest {
.addLinesIn(
FAST_INIT_MODE,
"final class DaggerTestComponent implements TestComponent {",
+ " private final DaggerTestComponent testComponent = this;",
+ " private Provider<FooFactory> fooFactoryProvider;",
"",
" private Bar bar() {",
- " return new Bar(fooFactory());",
+ " return new Bar(fooFactoryProvider.get());",
" }",
"",
- " private Foo foo(String str) {",
- " return new Foo(str, bar());",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.fooFactoryProvider = SingleCheck.provider(new"
+ + " SwitchingProvider<FooFactory>(testComponent, 0));",
" }",
"",
" @Override",
" public FooFactory fooFactory() {",
- " return new FooFactory() {",
- " @Override",
- " public Foo create(String str) {",
- " return DaggerTestComponent.this.foo(str);",
+ " return fooFactoryProvider.get();",
+ " }",
+ "",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " private final DaggerTestComponent testComponent;",
+ " private final int id;",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0:",
+ " return (T) new FooFactory() {",
+ " @Override",
+ " public Foo create(String str) {",
+ " return new Foo(str, testComponent.bar())",
+ " }",
+ " };",
+ "",
+ " default: throw new AssertionError(id);",
" }",
- " };",
+ " }",
" }",
"}")
.addLinesIn(
@@ -243,4 +283,344 @@ public class AssistedFactoryTest {
.generatedSourceFile("test.DaggerTestComponent")
.containsElementsIn(generatedComponent);
}
+
+ @Test
+ public void assistedParamConflictsWithComponentFieldName_successfulyDeduped() {
+ JavaFileObject foo =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "import dagger.assisted.Assisted;",
+ "import dagger.assisted.AssistedInject;",
+ "import javax.inject.Provider;",
+ "",
+ "class Foo {",
+ " @AssistedInject",
+ " Foo(@Assisted String testComponent, Provider<Bar> bar) {}",
+ "}");
+ JavaFileObject fooFactory =
+ JavaFileObjects.forSourceLines(
+ "test.FooFactory",
+ "package test;",
+ "",
+ "import dagger.assisted.AssistedFactory;",
+ "",
+ "@AssistedFactory",
+ "interface FooFactory {",
+ " Foo create(String factoryStr);",
+ "}");
+ JavaFileObject bar =
+ JavaFileObjects.forSourceLines(
+ "test.Bar",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Bar {",
+ " @Inject Bar() {}",
+ "}");
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " FooFactory fooFactory();",
+ "}");
+ JavaFileObject generatedComponent =
+ compilerMode
+ .javaFileBuilder("test.DaggerTestComponent")
+ .addLines("package test;", "", GeneratedLines.generatedAnnotations())
+ .addLinesIn(
+ FAST_INIT_MODE,
+ "final class DaggerTestComponent implements TestComponent {",
+ " private final DaggerTestComponent testComponent = this;",
+ " private Provider<FooFactory> fooFactoryProvider;",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.barProvider = new SwitchingProvider<>(testComponent, 1);",
+ " this.fooFactoryProvider = SingleCheck.provider(",
+ " new SwitchingProvider<FooFactory>(testComponent, 0));",
+ " }",
+ "",
+ " @Override",
+ " public FooFactory fooFactory() {",
+ " return fooFactoryProvider.get();",
+ " }",
+ "",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " private final DaggerTestComponent testComponent;",
+ " private final int id;",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0:",
+ " return (T) new FooFactory() {",
+ " @Override",
+ " public Foo create(String testComponent2) {",
+ " return new Foo(testComponent2, testComponent.barProvider);",
+ " }",
+ " };",
+ " case 1: return (T) new Bar();",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
+ " }",
+ "}")
+ .addLinesIn(
+ DEFAULT_MODE,
+ "final class DaggerTestComponent implements TestComponent {",
+ "",
+ " private Foo_Factory fooProvider;",
+ "",
+ " private Provider<FooFactory> fooFactoryProvider;",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.fooProvider = Foo_Factory.create(Bar_Factory.create());",
+ " this.fooFactoryProvider = FooFactory_Impl.create(fooProvider);",
+ " }",
+ "",
+ " @Override",
+ " public FooFactory fooFactory() {",
+ " return fooFactoryProvider.get();",
+ " }",
+ "}")
+ .build();
+
+ Compilation compilation =
+ compilerWithOptions(compilerMode.javacopts()).compile(foo, bar, fooFactory, component);
+
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerTestComponent")
+ .containsElementsIn(generatedComponent);
+ }
+
+ @Test
+ public void testFactoryGeneratorDuplicatedParamNames() {
+ JavaFileObject componentSrc =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.BindsInstance;",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " @Component.Factory",
+ " interface Factory {",
+ " TestComponent create(@BindsInstance Bar arg);",
+ "}",
+ " FooFactory getFooFactory();",
+ "}");
+ JavaFileObject factorySrc =
+ JavaFileObjects.forSourceLines(
+ "test.FooFactory",
+ "package test;",
+ "",
+ "import dagger.assisted.AssistedFactory;",
+ "",
+ "@AssistedFactory",
+ "public interface FooFactory {",
+ " Foo create(Integer arg);",
+ "}");
+ JavaFileObject barSrc =
+ JavaFileObjects.forSourceLines("test.Bar", "package test;", "", "interface Bar {}");
+ JavaFileObject injectSrc =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "import dagger.assisted.Assisted;",
+ "import dagger.assisted.AssistedInject;",
+ "",
+ "class Foo {",
+ " @AssistedInject",
+ " Foo(Bar arg, @Assisted Integer argProvider) {}",
+ "}");
+ JavaFileObject generatedSrc =
+ compilerMode
+ .javaFileBuilder("test.DaggerTestComponent")
+ .addLines(
+ "package test;",
+ "",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
+ GeneratedLines.generatedAnnotations())
+ .addLinesIn(
+ FAST_INIT_MODE,
+ "public final class Foo_Factory {",
+ " private final Provider<Bar> argProvider;",
+ "",
+ " public Foo_Factory(Provider<Bar> argProvider) {",
+ " this.argProvider = argProvider;",
+ " }",
+ "",
+ " public Foo get(Integer argProvider2) {",
+ " return newInstance(argProvider.get(), argProvider2);",
+ " }",
+ "",
+ " public static Foo_Factory create(Provider<Bar> argProvider) {",
+ " return new Foo_Factory(argProvider);",
+ " }",
+ "",
+ " public static Foo newInstance(Object arg, Integer argProvider) {",
+ " return new Foo((Bar) arg, argProvider);",
+ " }",
+ "}")
+ .addLinesIn(
+ DEFAULT_MODE,
+ "public final class Foo_Factory {",
+ " private final Provider<Bar> argProvider;",
+ "",
+ " public Foo_Factory(Provider<Bar> argProvider) {",
+ " this.argProvider = argProvider;",
+ " }",
+ "",
+ " public Foo get(Integer argProvider2) {",
+ " return newInstance(argProvider.get(), argProvider2);",
+ " }",
+ "",
+ " public static Foo_Factory create(Provider<Bar> argProvider) {",
+ " return new Foo_Factory(argProvider);",
+ " }",
+ "",
+ " public static Foo newInstance(Object arg, Integer argProvider) {",
+ " return new Foo((Bar) arg, argProvider);",
+ " }",
+ "}")
+ .build();
+ Compilation compilation =
+ compilerWithOptions(compilerMode.javacopts())
+ .compile(componentSrc, factorySrc, barSrc, injectSrc);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test.Foo_Factory")
+ .containsElementsIn(generatedSrc);
+ }
+
+ @Test
+ public void testParameterizedAssistParam() {
+ JavaFileObject componentSrc =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " FooFactory<String> getFooFactory();",
+ "}");
+ JavaFileObject factorySrc =
+ JavaFileObjects.forSourceLines(
+ "test.FooFactory",
+ "package test;",
+ "",
+ "import dagger.assisted.AssistedFactory;",
+ "",
+ "@AssistedFactory",
+ "public interface FooFactory<T> {",
+ " Foo<T> create(T arg);",
+ "}");
+ JavaFileObject injectSrc =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "import dagger.assisted.Assisted;",
+ "import dagger.assisted.AssistedInject;",
+ "",
+ "class Foo<T> {",
+ " @AssistedInject",
+ " Foo(@Assisted T arg) {}",
+ "}");
+ JavaFileObject generatedSrc =
+ compilerMode
+ .javaFileBuilder("test.DaggerTestComponent")
+ .addLines("package test;", "", GeneratedLines.generatedAnnotations())
+ .addLinesIn(
+ FAST_INIT_MODE,
+ "final class DaggerTestComponent implements TestComponent {",
+ " private final DaggerTestComponent testComponent = this;",
+ " private Provider<FooFactory<String>> fooFactoryProvider;",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.fooFactoryProvider = SingleCheck.provider(new"
+ + " SwitchingProvider<FooFactory<String>>(testComponent, 0));",
+ " }",
+ "",
+ " @Override",
+ " public FooFactory<String> getFooFactory() {",
+ " return fooFactoryProvider.get();",
+ " }",
+ " ",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " private final DaggerTestComponent testComponent;",
+ " private final int id;",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0: return (T) new FooFactory<String>() {",
+ " @Override",
+ " public Foo<String> create(String arg) {",
+ " return new Foo<String>(arg)",
+ " }",
+ " };",
+ "",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
+ " }",
+ "}")
+ .addLinesIn(
+ DEFAULT_MODE,
+ "final class DaggerTestComponent implements TestComponent {",
+ " private final DaggerTestComponent testComponent = this;",
+ " private Foo_Factory<String> fooProvider;",
+ " private Provider<FooFactory<String>> fooFactoryProvider;",
+ "",
+ " private DaggerTestComponent() {",
+ " initialize();",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.fooProvider = Foo_Factory.create();",
+ " this.fooFactoryProvider = FooFactory_Impl.create(fooProvider);",
+ " }",
+ "",
+ " @Override",
+ " public FooFactory<String> getFooFactory() {",
+ " return fooFactoryProvider.get();",
+ " }",
+ "}")
+ .build();
+ Compilation compilation =
+ compilerWithOptions(compilerMode.javacopts()).compile(componentSrc, factorySrc, injectSrc);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerTestComponent")
+ .containsElementsIn(generatedSrc);
+ }
}
diff --git a/javatests/dagger/internal/codegen/BUILD b/javatests/dagger/internal/codegen/BUILD
index 979ae71ef..f0a65bf0d 100644
--- a/javatests/dagger/internal/codegen/BUILD
+++ b/javatests/dagger/internal/codegen/BUILD
@@ -18,6 +18,7 @@
load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
load("//:test_defs.bzl", "GenJavaTests")
+load("//java/dagger/testing/compile:macros.bzl", "compiler_test")
package(default_visibility = ["//:src"])
@@ -43,10 +44,19 @@ java_library(
deps = [
"//java/dagger/internal/codegen:package_info",
"//java/dagger/internal/codegen:processor",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
+ "//third_party/java/compile_testing",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
"@com_google_auto_value_auto_value//jar",
- "@google_bazel_common//third_party/java/compile_testing",
+ ],
+)
+
+java_library(
+ name = "InvalidInjectConstructor",
+ srcs = ["InvalidInjectConstructor.java"],
+ # Note: We purposely leave off the dagger processor here.
+ deps = [
+ "//third_party/java/jsr330_inject",
],
)
@@ -58,12 +68,15 @@ GenJavaTests(
"CompilerMode.java",
"Compilers.java",
"JavaFileBuilder.java",
+ "ComponentValidationKtTest.java",
+ "InvalidInjectConstructor.java",
],
),
functional = False,
javacopts = DOCLINT_HTML_AND_SYNTAX,
plugins = ["//java/dagger/internal/codegen/bootstrap"],
deps = [
+ ":InvalidInjectConstructor",
":compilers",
":kotlin_sources",
"//java/dagger:core",
@@ -73,26 +86,54 @@ GenJavaTests(
"//java/dagger/internal/codegen/binding",
"//java/dagger/internal/codegen/bindinggraphvalidation",
"//java/dagger/internal/codegen/compileroption",
+ "//java/dagger/internal/codegen/javac",
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/kotlin",
"//java/dagger/internal/codegen/langmodel",
"//java/dagger/internal/codegen/validation",
"//java/dagger/internal/codegen/writing",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
+ "//java/dagger/internal/codegen/xprocessing",
"//java/dagger/model/testing",
"//java/dagger/producers",
"//java/dagger/spi",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:value",
+ "//third_party/java/compile_testing",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/util/concurrent",
+ "//third_party/java/javapoet",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/junit",
+ "//third_party/java/mockito",
+ "//third_party/java/truth",
"@com_google_auto_value_auto_value//jar",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr250_annotations",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/mockito",
- "@google_bazel_common//third_party/java/truth",
- "@maven//:com_google_auto_auto_common",
+ ],
+)
+
+compiler_test(
+ name = "ComponentValidationKtTest",
+ srcs = ["ComponentValidationKtTest.java"],
+ compiler_deps = [
+ "//java/dagger:core",
+ "//java/dagger/internal/codegen:package_info",
+ "//java/dagger/internal/codegen:processor",
+ "//java/dagger/internal/codegen/base",
+ "//java/dagger/internal/codegen/binding",
+ "//java/dagger/internal/codegen/bindinggraphvalidation",
+ "//java/dagger/internal/codegen/compileroption",
+ "//java/dagger/internal/codegen/javapoet",
+ "//java/dagger/internal/codegen/langmodel",
+ "//java/dagger/internal/codegen/validation",
+ "//java/dagger/internal/codegen/writing",
+ "//java/dagger/model/testing",
+ "//java/dagger/producers",
+ "//java/dagger/spi",
+ ],
+ deps = [
+ "//third_party/java/guava/collect",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ "@maven//:com_github_tschuchortdev_kotlin_compile_testing",
],
)
diff --git a/javatests/dagger/internal/codegen/BindsMethodValidationTest.java b/javatests/dagger/internal/codegen/BindsMethodValidationTest.java
index ab2601091..8974e0617 100644
--- a/javatests/dagger/internal/codegen/BindsMethodValidationTest.java
+++ b/javatests/dagger/internal/codegen/BindsMethodValidationTest.java
@@ -16,11 +16,15 @@
package dagger.internal.codegen;
+import static com.google.testing.compile.CompilationSubject.assertThat;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatMethodInUnannotatedClass;
import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatModuleMethod;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.JavaFileObjects;
import dagger.Module;
import dagger.multibindings.IntKey;
import dagger.multibindings.LongKey;
@@ -29,6 +33,7 @@ import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.util.Collection;
import javax.inject.Qualifier;
+import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -41,10 +46,12 @@ public class BindsMethodValidationTest {
return ImmutableList.copyOf(new Object[][] {{Module.class}, {ProducerModule.class}});
}
+ private final String moduleAnnotation;
private final String moduleDeclaration;
public BindsMethodValidationTest(Class<? extends Annotation> moduleAnnotation) {
- moduleDeclaration = "@" + moduleAnnotation.getCanonicalName() + " abstract class %s { %s }";
+ this.moduleAnnotation = "@" + moduleAnnotation.getCanonicalName();
+ moduleDeclaration = this.moduleAnnotation + " abstract class %s { %s }";
}
@Test
@@ -141,6 +148,113 @@ public class BindsMethodValidationTest {
.hasError("may not have more than one map key");
}
+ @Test
+ public void bindsMissingTypeInParameterHierarchy() {
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Binds;",
+ "",
+ moduleAnnotation,
+ "interface TestModule {",
+ " @Binds String bindObject(Child<String> child);",
+ "}");
+
+ JavaFileObject child =
+ JavaFileObjects.forSourceLines(
+ "test.Child",
+ "package test;",
+ "",
+ "class Child<T> extends Parent<T> {}");
+
+ JavaFileObject parent =
+ JavaFileObjects.forSourceLines(
+ "test.Parent",
+ "package test;",
+ "",
+ "class Parent<T> extends MissingType {}");
+
+ Compilation compilation = daggerCompiler().compile(module, child, parent);
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(3);
+ assertThat(compilation)
+ .hadErrorContaining(
+ "cannot find symbol"
+ + "\n symbol: class MissingType");
+ assertThat(compilation)
+ .hadErrorContaining(
+ "ModuleProcessingStep was unable to process 'test.TestModule' because 'MissingType' "
+ + "could not be resolved.");
+ assertThat(compilation)
+ .hadErrorContaining(
+ "BindingMethodProcessingStep was unable to process"
+ + " 'bindObject(test.Child<java.lang.String>)' because 'MissingType' could not be"
+ + " resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (INTERFACE): test.TestModule"
+ + "\n => element (METHOD): bindObject(test.Child<java.lang.String>)"
+ + "\n => element (PARAMETER): child"
+ + "\n => type (DECLARED parameter): test.Child<java.lang.String>"
+ + "\n => type (DECLARED supertype): test.Parent<java.lang.String>"
+ + "\n => type (ERROR supertype): MissingType");
+ }
+
+
+ @Test
+ public void bindsMissingTypeInReturnTypeHierarchy() {
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Binds;",
+ "",
+ moduleAnnotation,
+ "interface TestModule {",
+ " @Binds Child<String> bindChild(String str);",
+ "}");
+
+ JavaFileObject child =
+ JavaFileObjects.forSourceLines(
+ "test.Child",
+ "package test;",
+ "",
+ "class Child<T> extends Parent<T> {}");
+
+ JavaFileObject parent =
+ JavaFileObjects.forSourceLines(
+ "test.Parent",
+ "package test;",
+ "",
+ "class Parent<T> extends MissingType {}");
+
+ Compilation compilation = daggerCompiler().compile(module, child, parent);
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(3);
+ assertThat(compilation)
+ .hadErrorContaining(
+ "cannot find symbol"
+ + "\n symbol: class MissingType");
+ assertThat(compilation)
+ .hadErrorContaining(
+ "ModuleProcessingStep was unable to process 'test.TestModule' because 'MissingType' "
+ + "could not be resolved.");
+ assertThat(compilation)
+ .hadErrorContaining(
+ "BindingMethodProcessingStep was unable to process 'bindChild(java.lang.String)'"
+ + " because 'MissingType' could not be resolved."
+ + "\n "
+ + "\n Dependency trace:"
+ + "\n => element (INTERFACE): test.TestModule"
+ + "\n => element (METHOD): bindChild(java.lang.String)"
+ + "\n => type (DECLARED return type): test.Child<java.lang.String>"
+ + "\n => type (DECLARED supertype): test.Parent<java.lang.String>"
+ + "\n => type (ERROR supertype): MissingType");
+ }
+
private DaggerModuleMethodSubject assertThatMethod(String method) {
return assertThatModuleMethod(method).withDeclaration(moduleDeclaration);
}
diff --git a/javatests/dagger/internal/codegen/Compilers.java b/javatests/dagger/internal/codegen/Compilers.java
index 26796bfd2..af45f2c25 100644
--- a/javatests/dagger/internal/codegen/Compilers.java
+++ b/javatests/dagger/internal/codegen/Compilers.java
@@ -44,7 +44,8 @@ public final class Compilers {
.collect(collectingAndThen(toList(), ImmutableList::copyOf));
static final ImmutableList<String> DEFAULT_JAVACOPTS =
- ImmutableList.of("-Adagger.experimentalDaggerErrorMessages=enabled");
+ ImmutableList.of(
+ "-Adagger.experimentalDaggerErrorMessages=enabled");
/**
* Returns a compiler that runs the Dagger and {@code @AutoAnnotation} processors, along with
diff --git a/javatests/dagger/internal/codegen/ComponentBuilderTest.java b/javatests/dagger/internal/codegen/ComponentBuilderTest.java
index c4e0e07f1..17c49002d 100644
--- a/javatests/dagger/internal/codegen/ComponentBuilderTest.java
+++ b/javatests/dagger/internal/codegen/ComponentBuilderTest.java
@@ -18,7 +18,7 @@ package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.COMPONENT_BUILDER;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.COMPONENT_BUILDER;
import static dagger.internal.codegen.binding.ErrorMessages.creatorMessagesFor;
import com.google.testing.compile.Compilation;
diff --git a/javatests/dagger/internal/codegen/ComponentCreatorTest.java b/javatests/dagger/internal/codegen/ComponentCreatorTest.java
index 3cf05ac9c..be8066f35 100644
--- a/javatests/dagger/internal/codegen/ComponentCreatorTest.java
+++ b/javatests/dagger/internal/codegen/ComponentCreatorTest.java
@@ -23,17 +23,17 @@ import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
import static dagger.internal.codegen.ComponentCreatorTest.CompilerType.JAVAC;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.COMPONENT_BUILDER;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.COMPONENT_FACTORY;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.BUILDER;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.FACTORY;
-import static dagger.internal.codegen.binding.ComponentKind.COMPONENT;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.COMPONENT_BUILDER;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.COMPONENT_FACTORY;
+import static dagger.internal.codegen.base.ComponentCreatorKind.BUILDER;
+import static dagger.internal.codegen.base.ComponentCreatorKind.FACTORY;
+import static dagger.internal.codegen.base.ComponentKind.COMPONENT;
import static dagger.internal.codegen.binding.ErrorMessages.componentMessagesFor;
import com.google.common.collect.ImmutableList;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
-import dagger.internal.codegen.binding.ComponentCreatorAnnotation;
+import dagger.internal.codegen.base.ComponentCreatorAnnotation;
import java.util.Collection;
import javax.tools.JavaFileObject;
import org.junit.Test;
@@ -163,6 +163,8 @@ public class ComponentCreatorTest extends ComponentCreatorTestHelper {
"final class DaggerTestComponent implements TestComponent {",
" private final TestModule testModule;",
"",
+ " private final DaggerTestComponent testComponent = this;",
+ "",
" private DaggerTestComponent(TestModule testModuleParam) {",
" this.testModule = testModuleParam;",
" }",
@@ -361,6 +363,8 @@ public class ComponentCreatorTest extends ComponentCreatorTestHelper {
"final class DaggerSimpleComponent implements SimpleComponent {",
" private final Object object;",
"",
+ " private final DaggerSimpleComponent simpleComponent = this;",
+ "",
" private DaggerSimpleComponent(Object objectParam) {",
" this.object = objectParam;",
" }",
diff --git a/javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java b/javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java
index 8ad43227f..aaab5c3b4 100644
--- a/javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java
+++ b/javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java
@@ -17,14 +17,14 @@
package dagger.internal.codegen;
import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.FACTORY;
+import static dagger.internal.codegen.base.ComponentCreatorKind.FACTORY;
import static dagger.internal.codegen.binding.ErrorMessages.creatorMessagesFor;
import static java.util.stream.Collectors.joining;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
-import dagger.internal.codegen.binding.ComponentCreatorAnnotation;
-import dagger.internal.codegen.binding.ComponentCreatorKind;
+import dagger.internal.codegen.base.ComponentCreatorAnnotation;
+import dagger.internal.codegen.base.ComponentCreatorKind;
import dagger.internal.codegen.binding.ErrorMessages;
import java.util.Arrays;
import java.util.stream.Stream;
@@ -67,7 +67,7 @@ abstract class ComponentCreatorTestHelper {
line ->
line.replace("Builder", "Factory")
.replace("builder", "factory")
- .replace("build", "create"));
+ .replace("build", "createComponent"));
}
return stream.collect(joining("\n"));
}
diff --git a/javatests/dagger/internal/codegen/ComponentFactoryTest.java b/javatests/dagger/internal/codegen/ComponentFactoryTest.java
index 35cbb6a67..a910f7222 100644
--- a/javatests/dagger/internal/codegen/ComponentFactoryTest.java
+++ b/javatests/dagger/internal/codegen/ComponentFactoryTest.java
@@ -18,7 +18,7 @@ package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.COMPONENT_FACTORY;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.COMPONENT_FACTORY;
import static dagger.internal.codegen.binding.ErrorMessages.creatorMessagesFor;
import com.google.testing.compile.Compilation;
diff --git a/javatests/dagger/internal/codegen/ComponentProcessorTest.java b/javatests/dagger/internal/codegen/ComponentProcessorTest.java
index 3e514c829..480a449ad 100644
--- a/javatests/dagger/internal/codegen/ComponentProcessorTest.java
+++ b/javatests/dagger/internal/codegen/ComponentProcessorTest.java
@@ -175,74 +175,34 @@ public class ComponentProcessorTest {
.addLines(
"package test;",
"",
- GeneratedLines.generatedImports(
- "import dagger.Lazy;",
- "import dagger.internal.DoubleCheck;",
- "import javax.inject.Provider;"),
- "",
GeneratedLines.generatedAnnotations(),
- "final class DaggerSimpleComponent implements SimpleComponent {")
+ "final class DaggerSimpleComponent implements SimpleComponent {",
+ " private final DaggerSimpleComponent simpleComponent = this;")
.addLinesIn(
FAST_INIT_MODE,
- " private volatile Provider<SomeInjectableType> someInjectableTypeProvider;")
- .addLines(
- " private DaggerSimpleComponent() {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static SimpleComponent create() {",
- " return new Builder().build();",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.someInjectableTypeProvider =",
+ " new SwitchingProvider<>(simpleComponent, 0);",
" }",
"",
" @Override",
" public SomeInjectableType someInjectableType() {",
- " return new SomeInjectableType();",
+ " return someInjectableTypeProvider.get();",
" }",
"",
" @Override",
- " public Lazy<SomeInjectableType> lazySomeInjectableType() {")
- .addLinesIn(
- DEFAULT_MODE, //
- " return DoubleCheck.lazy(SomeInjectableType_Factory.create());")
- .addLinesIn(
- FAST_INIT_MODE,
- " return DoubleCheck.lazy(someInjectableTypeProvider());")
- .addLines(
+ " public Lazy<SomeInjectableType> lazySomeInjectableType() {",
+ " return DoubleCheck.lazy(someInjectableTypeProvider);",
" }",
"",
" @Override",
- " public Provider<SomeInjectableType> someInjectableTypeProvider() {")
- .addLinesIn(
- DEFAULT_MODE, //
- " return SomeInjectableType_Factory.create();")
- .addLinesIn(
- FAST_INIT_MODE, //
- " Object local = someInjectableTypeProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " someInjectableTypeProvider = (Provider<SomeInjectableType>) local;",
- " }",
- " return (Provider<SomeInjectableType>) local;")
- .addLines(
+ " public Provider<SomeInjectableType> someInjectableTypeProvider() {",
+ " return someInjectableTypeProvider",
" }",
"",
- " static final class Builder {",
- " private Builder() {}",
- "",
- " public SimpleComponent build() {",
- " return new DaggerSimpleComponent();",
- " }",
- " }")
- .addLinesIn(
- FAST_INIT_MODE,
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " private final DaggerSimpleComponent simpleComponent;",
"",
" @SuppressWarnings(\"unchecked\")",
" @Override",
@@ -251,8 +211,24 @@ public class ComponentProcessorTest {
" case 0: return (T) new SomeInjectableType();",
" default: throw new AssertionError(id);",
" }",
- " }",
- " }")
+ " }")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return new SomeInjectableType();",
+ " }",
+ "",
+ " @Override",
+ " public Lazy<SomeInjectableType> lazySomeInjectableType() {",
+ " return DoubleCheck.lazy(SomeInjectableType_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public Provider<SomeInjectableType> someInjectableTypeProvider() {",
+ " return SomeInjectableType_Factory.create();",
+ " }",
+ "}")
.build();
Compilation compilation =
@@ -261,7 +237,7 @@ public class ComponentProcessorTest {
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerSimpleComponent")
- .hasSourceEquivalentTo(generatedComponent);
+ .containsElementsIn(generatedComponent);
}
@Test public void componentWithScope() {
@@ -297,84 +273,46 @@ public class ComponentProcessorTest {
"package test;",
"",
GeneratedLines.generatedAnnotations(),
- "final class DaggerSimpleComponent implements SimpleComponent {")
+ "final class DaggerSimpleComponent implements SimpleComponent {",
+ " private Provider<SomeInjectableType> someInjectableTypeProvider;")
.addLinesIn(
FAST_INIT_MODE,
- " private volatile Object someInjectableType = new MemoizedSentinel();",
- " private volatile Provider<SomeInjectableType> someInjectableTypeProvider;")
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.someInjectableTypeProvider =",
+ " DoubleCheck.provider(",
+ " new SwitchingProvider<SomeInjectableType>(simpleComponent, 0));",
+ " }")
.addLinesIn(
DEFAULT_MODE,
- " private Provider<SomeInjectableType> someInjectableTypeProvider;",
- "",
" @SuppressWarnings(\"unchecked\")",
" private void initialize() {",
" this.someInjectableTypeProvider =",
" DoubleCheck.provider(SomeInjectableType_Factory.create());",
- " }",
- "")
- .addLines(
- " @Override", //
- " public SomeInjectableType someInjectableType() {")
- .addLinesIn(
- FAST_INIT_MODE,
- " Object local = someInjectableType;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = someInjectableType;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new SomeInjectableType();",
- " someInjectableType =",
- " DoubleCheck.reentrantCheck(someInjectableType, local);",
- " }",
- " }",
- " }",
- " return (SomeInjectableType) local;")
- .addLinesIn(
- DEFAULT_MODE, //
- " return someInjectableTypeProvider.get();")
+ " }")
.addLines(
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return someInjectableTypeProvider.get();",
" }",
"",
" @Override",
- " public Lazy<SomeInjectableType> lazySomeInjectableType() {")
- .addLinesIn(
- DEFAULT_MODE, //
- " return DoubleCheck.lazy(someInjectableTypeProvider);")
- .addLinesIn(
- FAST_INIT_MODE,
- " return DoubleCheck.lazy(someInjectableTypeProvider());")
- .addLines(
+ " public Lazy<SomeInjectableType> lazySomeInjectableType() {",
+ " return DoubleCheck.lazy(someInjectableTypeProvider);",
" }",
"",
" @Override",
- " public Provider<SomeInjectableType> someInjectableTypeProvider() {")
- .addLinesIn(
- FAST_INIT_MODE, //
- " Object local = someInjectableTypeProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " someInjectableTypeProvider = (Provider<SomeInjectableType>) local;",
- " }",
- " return (Provider<SomeInjectableType>) local;")
- .addLinesIn(
- DEFAULT_MODE, //
- " return someInjectableTypeProvider;")
- .addLines( //
+ " public Provider<SomeInjectableType> someInjectableTypeProvider() {",
+ " return someInjectableTypeProvider;",
" }")
.addLinesIn(
FAST_INIT_MODE,
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
" switch (id) {",
- " case 0: return (T) DaggerSimpleComponent.this.someInjectableType();",
+ " case 0: return (T) new SomeInjectableType();",
" default: throw new AssertionError(id);",
" }",
" }",
@@ -882,6 +820,7 @@ public class ComponentProcessorTest {
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerParent implements Parent {",
+ " private final DaggerParent parent = this;",
"",
" private DaggerParent() {}",
"",
@@ -1044,29 +983,42 @@ public class ComponentProcessorTest {
" Provider<SimpleComponent> selfProvider();",
"}");
JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerSimpleComponent",
- "package test;",
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " private Provider<SimpleComponent> simpleComponentProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.simpleComponentProvider = InstanceFactory.create((SimpleComponent) this);",
- " }",
- "",
- " @Override",
- " public SomeInjectableType someInjectableType() {",
- " return new SomeInjectableType(this)",
- " }",
- "",
- " @Override",
- " public Provider<SimpleComponent> selfProvider() {",
- " return simpleComponentProvider;",
- " }",
- "}");
+ compilerMode
+ .javaFileBuilder("test.DaggerSimpleComponent")
+ .addLines(
+ "package test;",
+ "",
+ GeneratedLines.generatedAnnotations(),
+ "final class DaggerSimpleComponent implements SimpleComponent {",
+ " private final DaggerSimpleComponent simpleComponent = this;",
+ "",
+ " private Provider<SimpleComponent> simpleComponentProvider;",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.simpleComponentProvider =",
+ " InstanceFactory.create((SimpleComponent) simpleComponent);",
+ " }",
+ "")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return new SomeInjectableType(this)",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return new SomeInjectableType(simpleComponentProvider.get());",
+ " }")
+ .addLines(
+ " @Override",
+ " public Provider<SimpleComponent> selfProvider() {",
+ " return simpleComponentProvider;",
+ " }",
+ "}")
+ .build();
Compilation compilation =
compilerWithOptions(compilerMode.javacopts())
.compile(injectableTypeFile, componentFile);
@@ -1182,34 +1134,37 @@ public class ComponentProcessorTest {
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerBComponent implements BComponent {")
- .addLinesIn(DEFAULT_MODE, " private Provider<A> aProvider;")
.addLinesIn(
FAST_INIT_MODE,
" private final AComponent aComponent;",
- " private volatile Provider<A> aProvider;",
+ " private final DaggerBComponent bComponent = this;",
+ " private Provider<A> aProvider;",
"",
" private DaggerBComponent(AComponent aComponentParam) {",
" this.aComponent = aComponentParam;",
+ " initialize(aComponentParam);",
" }",
"",
- " private Provider<A> aProvider() {",
- " Object local = aProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " aProvider = (Provider<A>) local;",
- " }",
- " return (Provider<A>) local;",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final AComponent aComponentParam) {",
+ " this.aProvider = new SwitchingProvider<>(bComponent, 0);",
" }")
.addLinesIn(
DEFAULT_MODE,
+ " private Provider<A> aProvider;",
+ "",
+ " private DaggerBComponent(AComponent aComponentParam) {",
+ " initialize(aComponentParam);",
+ " }",
+ "",
" @SuppressWarnings(\"unchecked\")",
" private void initialize(final AComponent aComponentParam) {",
" this.aProvider = new test_AComponent_a(aComponentParam);",
" }")
- .addLines("", " @Override", " public B b() {")
- .addLinesIn(DEFAULT_MODE, " return new B(aProvider);")
- .addLinesIn(FAST_INIT_MODE, " return new B(aProvider());")
.addLines(
+ " @Override",
+ " public B b() {",
+ " return new B(aProvider);",
" }",
"",
" static final class Builder {",
@@ -1242,15 +1197,14 @@ public class ComponentProcessorTest {
"}")
.addLinesIn(
FAST_INIT_MODE,
- " private final class SwitchingProvider<T> implements Provider<T> {",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
" switch (id) {",
" case 0:",
" return (T)",
- " Preconditions.checkNotNullFromComponent(",
- " DaggerBComponent.this.aComponent.a());",
+ " Preconditions.checkNotNullFromComponent(bComponent.aComponent.a());",
" default:",
" throw new AssertionError(id);",
" }",
@@ -1320,9 +1274,9 @@ public class ComponentProcessorTest {
"",
" private DaggerTestComponent(",
" TestModule testModuleParam,",
- " other.test.TestModule testModule2Param) {",
+ " other.test.TestModule testModuleParam2) {",
" this.testModule = testModuleParam;",
- " this.testModule2 = testModule2Param;",
+ " this.testModule2 = testModuleParam2;",
" }",
"",
" @Override",
@@ -1601,6 +1555,8 @@ public class ComponentProcessorTest {
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerSimpleComponent implements SimpleComponent {",
+ " private final DaggerSimpleComponent simpleComponent = this;",
+ "",
" private DaggerSimpleComponent() {}",
"",
" public static Builder builder() {",
@@ -2042,8 +1998,9 @@ public class ComponentProcessorTest {
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerParent implements Parent {",
- " private DaggerParent() {",
- " }",
+ " private final DaggerParent parent = this;",
+ "",
+ " private DaggerParent() {}",
"",
" public static Builder builder() {",
" return new Builder();",
@@ -2181,6 +2138,8 @@ public class ComponentProcessorTest {
"test.TestModule_NonNullableStringFactory",
"package test;",
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class TestModule_NonNullableStringFactory",
" implements Factory<String> {",
@@ -2271,6 +2230,8 @@ public class ComponentProcessorTest {
"test.TestModule_PrimitiveIntegerFactory",
"package test;",
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class TestModule_PrimitiveIntegerFactory",
" implements Factory<Integer> {",
@@ -2439,10 +2400,10 @@ public class ComponentProcessorTest {
"package test;",
GeneratedLines.generatedAnnotations(),
"final class DaggerParent implements Parent {",
- " private final class ChildImpl implements Child {",
+ " private static final class ChildImpl implements Child {",
" @Override",
" public String string() {",
- " return DaggerParent.this.string();",
+ " return parent.string();",
" }",
" }",
"}");
@@ -2633,6 +2594,8 @@ public class ComponentProcessorTest {
"",
GeneratedLines.generatedAnnotations(),
"public final class DaggerPublicComponent implements PublicComponent {",
+ " private final DaggerPublicComponent publicComponent = this;",
+ "",
" private DaggerPublicComponent() {}",
"",
" public static Builder builder() {",
@@ -2653,6 +2616,219 @@ public class ComponentProcessorTest {
"}"));
}
+ @Test
+ public void componentFactoryInterfaceTest() {
+ JavaFileObject parentInterface =
+ JavaFileObjects.forSourceLines(
+ "test.ParentInterface",
+ "package test;",
+ "",
+ "interface ParentInterface extends ChildInterface.Factory {}");
+
+ JavaFileObject childInterface =
+ JavaFileObjects.forSourceLines(
+ "test.ChildInterface",
+ "package test;",
+ "",
+ "interface ChildInterface {",
+ " interface Factory {",
+ " ChildInterface child(ChildModule childModule);",
+ " }",
+ "}");
+
+ JavaFileObject parent =
+ JavaFileObjects.forSourceLines(
+ "test.Parent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface Parent extends ParentInterface, Child.Factory {}");
+
+ JavaFileObject child =
+ JavaFileObjects.forSourceLines(
+ "test.Child",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = ChildModule.class)",
+ "interface Child extends ChildInterface {",
+ " interface Factory extends ChildInterface.Factory {",
+ " @Override Child child(ChildModule childModule);",
+ " }",
+ "}");
+
+ JavaFileObject childModule =
+ JavaFileObjects.forSourceLines(
+ "test.ChildModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class ChildModule {",
+ " @Provides",
+ " int provideInt() {",
+ " return 0;",
+ " }",
+ "}");
+
+ Compilation compilation =
+ daggerCompiler().compile(parentInterface, childInterface, parent, child, childModule);
+ assertThat(compilation).succeeded();
+ }
+
+ @Test
+ public void providerComponentType() {
+ JavaFileObject entryPoint =
+ JavaFileObjects.forSourceLines(
+ "test.SomeEntryPoint",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "public class SomeEntryPoint {",
+ " @Inject SomeEntryPoint(Foo foo, Provider<Foo> fooProvider) {}",
+ "}");
+ JavaFileObject foo =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public class Foo {",
+ " @Inject Foo(Bar bar) {}",
+ "}");
+ JavaFileObject bar =
+ JavaFileObjects.forSourceLines(
+ "test.Bar",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public class Bar {",
+ " @Inject Bar() {}",
+ "}");
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "public interface TestComponent {",
+ " SomeEntryPoint someEntryPoint();",
+ "}");
+ Compilation compilation =
+ compilerWithOptions(compilerMode.javacopts()).compile(component, foo, bar, entryPoint);
+
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerTestComponent")
+ .containsElementsIn(
+ compilerMode
+ .javaFileBuilder("test.DaggerSimpleComponent")
+ .addLines(
+ "package test;",
+ "",
+ GeneratedLines.generatedAnnotations(),
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Foo> fooProvider;")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " private Foo foo() {",
+ " return new Foo(new Bar());",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.fooProvider = Foo_Factory.create(Bar_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public SomeEntryPoint someEntryPoint() {",
+ " return new SomeEntryPoint(foo(), fooProvider);",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.fooProvider = new SwitchingProvider<>(testComponent, 0);",
+ " }",
+ "",
+ " @Override",
+ " public SomeEntryPoint someEntryPoint() {",
+ " return new SomeEntryPoint(fooProvider.get(), fooProvider);",
+ " }",
+ "",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0: return (T) new Foo(new Bar());",
+ "",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
+ " }",
+ "}")
+ .build());
+ }
+
+ @Test
+ public void injectedTypeHasGeneratedParam() {
+ JavaFileObject foo =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public final class Foo {",
+ "",
+ " @Inject",
+ " public Foo(GeneratedParam param) {}",
+ "",
+ " @Inject",
+ " public void init() {}",
+ "}");
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " Foo foo();",
+ "}");
+
+ Compilation compilation =
+ daggerCompiler(
+ new GeneratingProcessor(
+ "test.GeneratedParam",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public final class GeneratedParam {",
+ "",
+ " @Inject",
+ " public GeneratedParam() {}",
+ "}"))
+ .compile(foo, component);
+ assertThat(compilation).succeededWithoutWarnings();
+ }
+
/**
* A {@link ComponentProcessor} that excludes elements using a {@link Predicate}.
*/
diff --git a/javatests/dagger/internal/codegen/ComponentProtectedTypeTest.java b/javatests/dagger/internal/codegen/ComponentProtectedTypeTest.java
new file mode 100644
index 000000000..c67cbec09
--- /dev/null
+++ b/javatests/dagger/internal/codegen/ComponentProtectedTypeTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.testing.compile.CompilationSubject.assertThat;
+import static dagger.internal.codegen.Compilers.compilerWithOptions;
+
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class ComponentProtectedTypeTest {
+ @Parameters(name = "{0}")
+ public static ImmutableList<Object[]> parameters() {
+ return CompilerMode.TEST_PARAMETERS;
+ }
+
+ private final CompilerMode compilerMode;
+
+ public ComponentProtectedTypeTest(CompilerMode compilerMode) {
+ this.compilerMode = compilerMode;
+ }
+
+ @Test
+ public void componentAccessesProtectedType_succeeds() {
+ JavaFileObject baseSrc =
+ JavaFileObjects.forSourceLines(
+ "test.sub.TestComponentBase",
+ "package test.sub;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Singleton;",
+ "",
+ "public abstract class TestComponentBase {",
+ " static class Dep {",
+ " @Inject",
+ " Dep() {}",
+ " }",
+ "",
+ " @Singleton",
+ " protected static final class ProtectedType {",
+ " @Inject",
+ " ProtectedType(Dep dep) {}",
+ " }",
+ "}");
+ JavaFileObject componentSrc =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Provider;",
+ "import javax.inject.Singleton;",
+ "import test.sub.TestComponentBase;",
+ "",
+ "@Singleton",
+ "@Component",
+ "public abstract class TestComponent extends TestComponentBase {",
+ // This component method will be implemented as:
+ // TestComponentBase.ProtectedType provideProtectedType() {
+ // return protectedTypeProvider.get();
+ // }
+ // The protectedTypeProvider can't be a raw provider, otherwise it will have a type cast
+ // error. So protected accessibility should be evaluated when checking accessibility of
+ // a type.
+ " abstract TestComponentBase.ProtectedType provideProtectedType();",
+ "}");
+ JavaFileObject generatedComponent =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ GeneratedLines.generatedAnnotations(),
+ "public final class DaggerTestComponent extends TestComponent {",
+ " private Provider<test.sub.TestComponentBase.ProtectedType> protectedTypeProvider;",
+ "",
+ " @Override",
+ " test.sub.TestComponentBase.ProtectedType provideProtectedType() {",
+ " return protectedTypeProvider.get();",
+ " }",
+ "}");
+
+ Compilation compilation =
+ compilerWithOptions(compilerMode.javacopts()).compile(baseSrc, componentSrc);
+
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerTestComponent")
+ .containsElementsIn(generatedComponent);
+ }
+}
diff --git a/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java b/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java
index 05164a6a3..b0e30e80b 100644
--- a/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java
+++ b/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java
@@ -17,6 +17,8 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
+import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
+import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
import static dagger.internal.codegen.Compilers.compilerWithOptions;
import com.google.testing.compile.Compilation;
@@ -272,15 +274,15 @@ public class ComponentRequirementFieldTest {
" return Preconditions.checkNotNullFromComponent(dep.object());",
" }",
"",
- " private final class TestSubcomponentImpl implements TestSubcomponent {",
+ " private static final class TestSubcomponentImpl implements TestSubcomponent {",
" @Override",
" public TestComponent parent() {",
- " return DaggerTestComponent.this;",
+ " return testComponent;",
" }",
"",
" @Override",
" public Dep depFromSubcomponent() {",
- " return DaggerTestComponent.this.dep;",
+ " return testComponent.dep;",
" }",
" }",
"}"));
@@ -348,83 +350,128 @@ public class ComponentRequirementFieldTest {
"interface TestSubcomponent {",
" Provider<Object> dependsOnMultibinding();",
"}");
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {",
- " private final ParentModule parentModule;",
- "",
- " private DaggerTestComponent(ParentModule parentModuleParam) {",
- " this.parentModule = parentModuleParam;",
- " }",
- "",
- " private final class TestSubcomponentImpl implements TestSubcomponent {",
- " private Set<Object> setOfObject() {",
- " return ImmutableSet.<Object>of(",
- " ParentModule_ContributionFactory.contribution(),",
- " ChildModule_ContributionFactory.contribution());",
- " }",
- "",
- " private Object object() {",
- " return ParentModule_ReliesOnMultibindingFactory.reliesOnMultibinding(",
- " DaggerTestComponent.this.parentModule, setOfObject());",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {",
- " private final ParentModule parentModule;",
- "",
- " private DaggerTestComponent(ParentModule parentModuleParam) {",
- " this.parentModule = parentModuleParam;",
- " initialize(parentModuleParam);",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(final ParentModule parentModuleParam) {",
- " this.setOfObjectProvider =",
- " SetFactory.<Object>builder(1, 0)",
- " .addProvider(ParentModule_ContributionFactory.create())",
- " .build();",
- " this.reliesOnMultibindingProvider =",
- " ParentModule_ReliesOnMultibindingFactory.create(",
- " parentModuleParam, setOfObjectProvider);",
- " }",
- "",
- " private final class TestSubcomponentImpl implements TestSubcomponent {",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.setOfObjectProvider =",
- " SetFactory.<Object>builder(2, 0)",
- " .addProvider(ParentModule_ContributionFactory.create())",
- " .addProvider(ChildModule_ContributionFactory.create())",
- " .build();",
- " this.reliesOnMultibindingProvider =",
- " ParentModule_ReliesOnMultibindingFactory.create(",
- " DaggerTestComponent.this.parentModule, setOfObjectProvider);",
- " }",
- " }",
- "}");
- }
+
Compilation compilation =
compilerWithOptions(compilerMode.javacopts())
.compile(parentModule, childModule, component, subcomponent);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
+ .containsElementsIn(
+ compilerMode
+ .javaFileBuilder("test.DaggerSimpleComponent")
+ .addLines(
+ "package test;",
+ "",
+ GeneratedLines.generatedAnnotations(),
+ "final class DaggerTestComponent implements TestComponent {",
+ " private final ParentModule parentModule;",
+ "",
+ " private DaggerTestComponent(ParentModule parentModuleParam) {",
+ " this.parentModule = parentModuleParam;",
+ " initialize(parentModuleParam);",
+ " }")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final ParentModule parentModuleParam) {",
+ " this.setOfObjectProvider =",
+ " SetFactory.<Object>builder(1, 0)",
+ " .addProvider(ParentModule_ContributionFactory.create())",
+ " .build();",
+ " this.reliesOnMultibindingProvider =",
+ " ParentModule_ReliesOnMultibindingFactory",
+ " .create(parentModuleParam, setOfObjectProvider);",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ "",
+ " private Set<Object> setOfObject() {",
+ " return ImmutableSet.<Object>of(",
+ " ParentModule_ContributionFactory.contribution());",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final ParentModule parentModuleParam) {",
+ " this.reliesOnMultibindingProvider =",
+ " new SwitchingProvider<>(testComponent, 0);",
+ " }")
+ .addLines(
+ " @Override",
+ " public Provider<Object> dependsOnMultibinding() {",
+ " return reliesOnMultibindingProvider;",
+ " }",
+ "",
+ " @Override",
+ " public TestSubcomponent subcomponent() {",
+ " return new TestSubcomponentImpl(testComponent);",
+ " }",
+ "",
+ " private static final class TestSubcomponentImpl",
+ " implements TestSubcomponent {")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.setOfObjectProvider =",
+ " SetFactory.<Object>builder(2, 0)",
+ " .addProvider(ParentModule_ContributionFactory.create())",
+ " .addProvider(ChildModule_ContributionFactory.create())",
+ " .build();",
+ " this.reliesOnMultibindingProvider =",
+ " ParentModule_ReliesOnMultibindingFactory",
+ " .create(testComponent.parentModule, setOfObjectProvider);",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " private Set<Object> setOfObject() {",
+ " return ImmutableSet.<Object>of(",
+ " ParentModule_ContributionFactory.contribution(),",
+ " ChildModule_ContributionFactory.contribution());",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.reliesOnMultibindingProvider =",
+ " new SwitchingProvider<>(testComponent, testSubcomponentImpl, 0);",
+ " }")
+ .addLines(
+ " @Override",
+ " public Provider<Object> dependsOnMultibinding() {",
+ " return reliesOnMultibindingProvider;",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0:",
+ " return (T) ParentModule_ReliesOnMultibindingFactory",
+ " .reliesOnMultibinding(",
+ " testComponent.parentModule,",
+ " testSubcomponentImpl.setOfObject());",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
+ " }",
+ " }",
+ "",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0:",
+ " return (T) ParentModule_ReliesOnMultibindingFactory",
+ " .reliesOnMultibinding(",
+ " testComponent.parentModule, testComponent.setOfObject());",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
+ " }",
+ "}")
+ .build());
}
}
diff --git a/javatests/dagger/internal/codegen/ComponentShardTest.java b/javatests/dagger/internal/codegen/ComponentShardTest.java
index ec7f4990c..015a8cf70 100644
--- a/javatests/dagger/internal/codegen/ComponentShardTest.java
+++ b/javatests/dagger/internal/codegen/ComponentShardTest.java
@@ -17,9 +17,12 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static com.google.testing.compile.Compiler.javac;
+import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
+import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
+import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static java.util.stream.Collectors.joining;
+import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.testing.compile.Compilation;
@@ -29,211 +32,268 @@ import java.util.Arrays;
import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
-@RunWith(JUnit4.class)
+@RunWith(Parameterized.class)
public class ComponentShardTest {
- private static final int BINDINGS_PER_SHARD = 10;
+ private static final int BINDINGS_PER_SHARD = 2;
+
+ @Parameters(name = "{0}")
+ public static ImmutableCollection<Object[]> parameters() {
+ return CompilerMode.TEST_PARAMETERS;
+ }
+
+ private final CompilerMode compilerMode;
+
+ public ComponentShardTest(CompilerMode compilerMode) {
+ this.compilerMode = compilerMode;
+ }
@Test
public void testNewShardCreated() {
- // Create 2N + 1 bindings: N in DaggerTestComponent, N in Shard1, and 1 in Shard2
- int numBindings = 2 * BINDINGS_PER_SHARD + 1;
+ // Add all bindings.
+ //
+ // 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7
+ // ^--------/
+ //
ImmutableList.Builder<JavaFileObject> javaFileObjects = ImmutableList.builder();
- ImmutableList.Builder<String> entryPoints = ImmutableList.builder();
- for (int i = 0; i < numBindings; i++) {
- String bindingName = "Binding" + i;
- entryPoints.add(String.format("%1$s get%1$s();", bindingName));
- entryPoints.add(String.format("Provider<%1$s> get%1$sProvider();", bindingName));
+ javaFileObjects
+ // Shard 2: Bindings (1)
+ .add(createBinding("Binding1", "Binding2 binding2"))
+ // Shard 1: Bindings (2, 3, 4, 5). Contains more than 2 bindings due to cycle.
+ .add(createBinding("Binding2", "Binding3 binding3"))
+ .add(createBinding("Binding3", "Binding4 binding4"))
+ .add(createBinding("Binding4", "Binding5 binding5, Provider<Binding2> binding2Provider"))
+ .add(createBinding("Binding5", "Binding6 binding6"))
+ // Component shard: Bindings (6, 7)
+ .add(createBinding("Binding6", "Binding7 binding7"))
+ .add(createBinding("Binding7"));
- // Add dependencies between main component and shard1: 9 -> 10 -> Provider<9>
- // Add dependencies between shard1 and shard2: 19 -> 20 -> Provider<19>
- switch (i) {
- case 9:
- javaFileObjects.add(createBinding(bindingName, "Binding10 dep"));
- break;
- case 10:
- javaFileObjects.add(createBinding(bindingName, "Provider<Binding9> dep"));
- break;
- case 19:
- javaFileObjects.add(createBinding(bindingName, "Binding20 dep"));
- break;
- case 20:
- javaFileObjects.add(createBinding(bindingName, "Provider<Binding19> dep"));
- break;
- default:
- javaFileObjects.add(createBinding(bindingName));
- break;
- }
- }
-
- javaFileObjects.add(createComponent(entryPoints.build()));
-
- // This generated component shows a couple things:
- // 1. Binding locations:
- // * Binding #9 belongs to DaggerTestComponent
- // * Binding #10 belongs to Shard1
- // * Binding #20 belongs to Shard2
- // 2. DaggerTestComponent entry point methods:
- // * Binding #9 implementation is inlined DaggerTestComponent.
- // * Binding #10 implementation is delegated to Shard1.
- // * Binding #20 implementation is delegated to Shard2.
- // 3. Dependencies between component and shard:
- // * Binding #9 in DaggerTestComponent depends on #10 in Shard1.
- // * Binding #10 in Shard1 depends on Provider<#9> in DaggerTestComponent.
- // 4. Dependencies between shard and shard:
- // * Binding #19 in Shard1 depends on #20 in Shard2.
- // * Binding #20 in Shard2 depends on Provider<#19> in Shard1.
- JavaFileObject generatedComponent =
+ // Add the component with entry points for each binding and its provider.
+ javaFileObjects.add(
JavaFileObjects.forSourceLines(
- "dagger.internal.codegen.DaggerTestComponent",
- "package dagger.internal.codegen;",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {",
- " private final Shard1 shard1 = new Shard1();",
- "",
- " private volatile Provider<Binding9> binding9Provider;",
- "",
- " private volatile Object binding9 = new MemoizedSentinel();",
- "",
- " @Override",
- " public Binding9 getBinding9() {",
- " Object local = binding9;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = binding9;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new Binding9(DaggerTestComponent.this.shard1.binding10());",
- " binding9 = DoubleCheck.reentrantCheck(binding9, local);",
- " }",
- " }",
- " }",
- " return (Binding9) local;",
- " }",
- "",
- " @Override",
- " public Provider<Binding9> getBinding9Provider() {",
- " Object local = binding9Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(9);",
- " binding9Provider = (Provider<Binding9>) local;",
- " }",
- " return (Provider<Binding9>) local;",
- " }",
- "",
- " @Override",
- " public Binding10 getBinding10() {",
- " return DaggerTestComponent.this.shard1.binding10();",
- " }",
- "",
- " @Override",
- " public Provider<Binding10> getBinding10Provider() {",
- " return DaggerTestComponent.this.shard1.binding10Provider();",
- " }",
- "",
- " @Override",
- " public Binding20 getBinding20() {",
- " return DaggerTestComponent.this.shard2.binding20();",
- " }",
- "",
- " @Override",
- " public Provider<Binding20> getBinding20Provider() {",
- " return DaggerTestComponent.this.shard2.binding20Provider();",
- " }",
- "",
- " private final class Shard1 {",
- " private volatile Object binding10 = new MemoizedSentinel();",
- "",
- " private volatile Provider<Binding10> binding10Provider;",
- "",
- " private volatile Provider<Binding19> binding19Provider;",
- "",
- " private volatile Object binding19 = new MemoizedSentinel();",
- "",
- " private Binding10 binding10() {",
- " Object local = binding10;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = binding10;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new Binding10(",
- " DaggerTestComponent.this.getBinding9Provider());",
- " binding10 = DoubleCheck.reentrantCheck(binding10, local);",
- " }",
- " }",
- " }",
- " return (Binding10) local;",
- " }",
- "",
- " private Provider<Binding10> binding10Provider() {",
- " Object local = binding10Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(10);",
- " binding10Provider = (Provider<Binding10>) local;",
- " }",
- " return (Provider<Binding10>) local;",
- " }",
- "",
- " private Provider<Binding19> binding19Provider() {",
- " Object local = binding19Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(19);",
- " binding19Provider = (Provider<Binding19>) local;",
- " }",
- " return (Provider<Binding19>) local;",
- " }",
- "",
- " private Binding19 binding19() {",
- " Object local = binding19;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = binding19;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new Binding19(DaggerTestComponent.this.shard2.binding20());",
- " binding19 = DoubleCheck.reentrantCheck(binding19, local);",
- " }",
- " }",
- " }",
- " return (Binding19) local;",
- " }",
- " }",
- "",
- " private final class Shard2 {",
- " private volatile Object binding20 = new MemoizedSentinel();",
- "",
- " private volatile Provider<Binding20> binding20Provider;",
- "",
- " private Binding20 binding20() {",
- " Object local = binding20;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = binding20;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new Binding20(",
- " DaggerTestComponent.this.shard1.binding19Provider());",
- " binding20 = DoubleCheck.reentrantCheck(binding20, local);",
- " }",
- " }",
- " }",
- " return (Binding20) local;",
- " }",
- "",
- " private Provider<Binding20> binding20Provider() {",
- " Object local = binding20Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(20);",
- " binding20Provider = (Provider<Binding20>) local;",
- " }",
- " return (Provider<Binding20>) local;",
- " }",
- " }",
- "}");
+ "dagger.internal.codegen.TestComponent",
+ "package dagger.internal.codegen;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Provider;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "@Component",
+ "interface TestComponent {",
+ " Binding1 binding1();",
+ " Binding2 binding2();",
+ " Binding3 binding3();",
+ " Binding4 binding4();",
+ " Binding5 binding5();",
+ " Binding6 binding6();",
+ " Binding7 binding7();",
+ " Provider<Binding1> providerBinding1();",
+ " Provider<Binding2> providerBinding2();",
+ " Provider<Binding3> providerBinding3();",
+ " Provider<Binding4> providerBinding4();",
+ " Provider<Binding5> providerBinding5();",
+ " Provider<Binding6> providerBinding6();",
+ " Provider<Binding7> providerBinding7();",
+ "}"));
- Compilation compilation = compilerWithAndroidMode().compile(javaFileObjects.build());
+ Compilation compilation = compiler().compile(javaFileObjects.build());
assertThat(compilation).succeededWithoutWarnings();
assertThat(compilation)
.generatedSourceFile("dagger.internal.codegen.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
+ .containsElementsIn(
+ compilerMode
+ .javaFileBuilder("dagger.internal.codegen.DaggerTestComponent")
+ .addLines(
+ "package dagger.internal.codegen;",
+ "",
+ GeneratedLines.generatedAnnotations(),
+ "final class DaggerTestComponent implements TestComponent {",
+ " private Shard1 shard1;",
+ " private Shard2 shard2;",
+ " private final DaggerTestComponent testComponent = this;",
+ " private Provider<Binding7> binding7Provider;",
+ " private Provider<Binding6> binding6Provider;",
+ "",
+ " private DaggerTestComponent() {",
+ " initialize();",
+ " shard1 = new Shard1();",
+ " shard2 = new Shard2();",
+ " }")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.binding7Provider =",
+ " DoubleCheck.provider(Binding7_Factory.create());",
+ " this.binding6Provider =",
+ " DoubleCheck.provider(Binding6_Factory.create(binding7Provider));",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.binding7Provider = DoubleCheck.provider(",
+ " new SwitchingProvider<Binding7>(testComponent, 6));",
+ " this.binding6Provider = DoubleCheck.provider(",
+ " new SwitchingProvider<Binding6>(testComponent, 5));",
+ " }")
+ .addLines(
+ " @Override",
+ " public Binding1 binding1() {",
+ " return testComponent.shard2.binding1Provider.get();",
+ " }",
+ "",
+ " @Override",
+ " public Binding2 binding2() {",
+ " return testComponent.shard1.binding2Provider.get();",
+ " }",
+ "",
+ " @Override",
+ " public Binding3 binding3() {",
+ " return testComponent.shard1.binding3Provider.get();",
+ " }",
+ "",
+ " @Override",
+ " public Binding4 binding4() {",
+ " return testComponent.shard1.binding4Provider.get();",
+ " }",
+ "",
+ " @Override",
+ " public Binding5 binding5() {",
+ " return testComponent.shard1.binding5Provider.get();",
+ " }",
+ "",
+ " @Override",
+ " public Binding6 binding6() {",
+ " return binding6Provider.get();",
+ " }",
+ "",
+ " @Override",
+ " public Binding7 binding7() {",
+ " return binding7Provider.get();",
+ " }",
+ "",
+ " @Override",
+ " public Provider<Binding1> providerBinding1() {",
+ " return testComponent.shard2.binding1Provider;",
+ " }",
+ "",
+ " @Override",
+ " public Provider<Binding2> providerBinding2() {",
+ " return testComponent.shard1.binding2Provider;",
+ " }",
+ "",
+ " @Override",
+ " public Provider<Binding3> providerBinding3() {",
+ " return testComponent.shard1.binding3Provider;",
+ " }",
+ "",
+ " @Override",
+ " public Provider<Binding4> providerBinding4() {",
+ " return testComponent.shard1.binding4Provider;",
+ " }",
+ "",
+ " @Override",
+ " public Provider<Binding5> providerBinding5() {",
+ " return testComponent.shard1.binding5Provider;",
+ " }",
+ "",
+ " @Override",
+ " public Provider<Binding6> providerBinding6() {",
+ " return binding6Provider;",
+ " }",
+ "",
+ " @Override",
+ " public Provider<Binding7> providerBinding7() {",
+ " return binding7Provider;",
+ " }",
+ "",
+ " private final class Shard1 {",
+ " private Provider<Binding5> binding5Provider;",
+ " private Provider<Binding2> binding2Provider;",
+ " private Provider<Binding4> binding4Provider;",
+ " private Provider<Binding3> binding3Provider;")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.binding5Provider =",
+ " DoubleCheck.provider(",
+ " Binding5_Factory.create(testComponent.binding6Provider));",
+ " this.binding2Provider = new DelegateFactory<>();",
+ " this.binding4Provider =",
+ " DoubleCheck.provider(",
+ " Binding4_Factory.create(binding5Provider, binding2Provider));",
+ " this.binding3Provider =",
+ " DoubleCheck.provider(Binding3_Factory.create(binding4Provider));",
+ " DelegateFactory.setDelegate(",
+ " binding2Provider,",
+ " DoubleCheck.provider(Binding2_Factory.create(binding3Provider)));",
+ " }",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.binding5Provider = DoubleCheck.provider(",
+ " new SwitchingProvider<Binding5>(testComponent, 4));",
+ " this.binding4Provider = DoubleCheck.provider(",
+ " new SwitchingProvider<Binding4>(testComponent, 3));",
+ " this.binding3Provider = DoubleCheck.provider(",
+ " new SwitchingProvider<Binding3>(testComponent, 2));",
+ " this.binding2Provider = DoubleCheck.provider(",
+ " new SwitchingProvider<Binding2>(testComponent, 1));",
+ " }",
+ " }")
+ .addLines(
+ " private final class Shard2 {",
+ " private Provider<Binding1> binding1Provider;")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.binding1Provider =",
+ " DoubleCheck.provider(",
+ " Binding1_Factory.create(",
+ " testComponent.shard1.binding2Provider));",
+ " }",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.binding1Provider = DoubleCheck.provider(",
+ " new SwitchingProvider<Binding1>(testComponent, 0));",
+ " }",
+ " }",
+ "",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0: return (T) new Binding1(",
+ " testComponent.shard1.binding2Provider.get());",
+ " case 1: return (T) new Binding2(",
+ " testComponent.shard1.binding3Provider.get());",
+ " case 2: return (T) new Binding3(",
+ " testComponent.shard1.binding4Provider.get());",
+ " case 3: return (T) new Binding4(",
+ " testComponent.shard1.binding5Provider.get(),",
+ " testComponent.shard1.binding2Provider);",
+ " case 4: return (T) new Binding5(",
+ " testComponent.binding6Provider.get());",
+ " case 5: return (T) new Binding6(",
+ " testComponent.binding7Provider.get());",
+ " case 6: return (T) new Binding7();",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
+ " }")
+ .build());
}
private static JavaFileObject createBinding(String bindingName, String... deps) {
@@ -252,29 +312,11 @@ public class ComponentShardTest {
"}");
}
- private static JavaFileObject createComponent(ImmutableList<String> entryPoints) {
- return JavaFileObjects.forSourceLines(
- "dagger.internal.codegen.TestComponent",
- "package dagger.internal.codegen;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component",
- "interface TestComponent {",
- " " + entryPoints.stream().collect(joining("\n ")),
- "}");
- }
-
- private static Compiler compilerWithAndroidMode() {
- return javac()
- .withProcessors(new ComponentProcessor())
- .withOptions(
- ImmutableSet.builder()
- .add("-Adagger.keysPerComponentShard=" + BINDINGS_PER_SHARD)
- .addAll(CompilerMode.FAST_INIT_MODE.javacopts())
- .build());
+ private Compiler compiler() {
+ return compilerWithOptions(
+ ImmutableSet.<String>builder()
+ .add("-Adagger.keysPerComponentShard=" + BINDINGS_PER_SHARD)
+ .addAll(compilerMode.javacopts())
+ .build());
}
}
diff --git a/javatests/dagger/internal/codegen/ComponentValidationKtTest.java b/javatests/dagger/internal/codegen/ComponentValidationKtTest.java
new file mode 100644
index 000000000..4600f9923
--- /dev/null
+++ b/javatests/dagger/internal/codegen/ComponentValidationKtTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.truth.Truth.assertThat;
+import static dagger.testing.compile.CompilerTests.kotlinCompiler;
+
+import com.google.common.collect.ImmutableList;
+import com.tschuchort.compiletesting.KotlinCompilation;
+import com.tschuchort.compiletesting.KotlinCompilation.ExitCode;
+import com.tschuchort.compiletesting.SourceFile;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class ComponentValidationKtTest {
+ @Test
+ public void creatorMethodNameIsJavaKeyword_compilationError() {
+ SourceFile componentSrc =
+ SourceFile.Companion.kotlin(
+ "FooComponent.kt",
+ String.join(
+ "\n",
+ "package test",
+ "",
+ "import dagger.BindsInstance",
+ "import dagger.Component",
+ "",
+ "@Component",
+ "interface FooComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " @BindsInstance public fun int(str: Int): Builder",
+ " public fun build(): FooComponent",
+ " }",
+ "}"),
+ false);
+ KotlinCompilation compilation = kotlinCompiler();
+ compilation.setSources(ImmutableList.of(componentSrc));
+
+ KotlinCompilation.Result result = compilation.compile();
+
+ // TODO(b/192396673): Add error count when the feature request is fulfilled.
+ assertThat(result.getExitCode()).isEqualTo(ExitCode.COMPILATION_ERROR);
+ assertThat(result.getMessages())
+ .contains("Can not use a Java keyword as method name: int(I)Ltest/FooComponent$Builder");
+ }
+
+ @Test
+ public void componentMethodNameIsJavaKeyword_compilationError() {
+ SourceFile componentSrc =
+ SourceFile.Companion.kotlin(
+ "FooComponent.kt",
+ String.join(
+ "\n",
+ "package test",
+ "",
+ "import dagger.BindsInstance",
+ "import dagger.Component",
+ "",
+ "@Component(modules = [TestModule::class])",
+ "interface FooComponent {",
+ " fun int(str: Int): String",
+ "}"),
+ false);
+ SourceFile moduleSrc =
+ SourceFile.Companion.kotlin(
+ "TestModule.kt",
+ String.join(
+ "\n",
+ "package test",
+ "",
+ "import dagger.Module",
+ "",
+ "@Module",
+ "interface TestModule {",
+ " fun providesString(): String {",
+ " return \"test\"",
+ " }",
+ "}"),
+ false);
+ KotlinCompilation compilation = kotlinCompiler();
+ compilation.setSources(ImmutableList.of(componentSrc, moduleSrc));
+
+ KotlinCompilation.Result result = compilation.compile();
+
+ assertThat(result.getExitCode()).isEqualTo(ExitCode.COMPILATION_ERROR);
+ assertThat(result.getMessages())
+ .contains("Can not use a Java keyword as method name: int(I)Ljava/lang/String");
+ }
+}
diff --git a/javatests/dagger/internal/codegen/ComponentValidationTest.java b/javatests/dagger/internal/codegen/ComponentValidationTest.java
index 6c642a409..157511131 100644
--- a/javatests/dagger/internal/codegen/ComponentValidationTest.java
+++ b/javatests/dagger/internal/codegen/ComponentValidationTest.java
@@ -44,6 +44,118 @@ public final class ComponentValidationTest {
assertThat(compilation).hadErrorContaining("interface");
}
+ @Test
+ public void componentOnOverridingBuilder_failsWhenMethodNameConflictsWithStaticCreatorName() {
+ JavaFileObject componentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules=TestModule.class)",
+ "interface TestComponent {",
+ " String builder();",
+ "}");
+ JavaFileObject moduleFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "interface TestModule {",
+ " @Provides",
+ " static String provideString() { return \"test\"; }",
+ "}");
+
+ Compilation compilation = daggerCompiler().compile(componentFile, moduleFile);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining("Cannot override generated method: TestComponent.builder()");
+ }
+
+ @Test
+ public void componentOnOverridingCreate_failsWhenGeneratedCreateMethod() {
+ JavaFileObject componentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules=TestModule.class)",
+ "interface TestComponent {",
+ " String create();",
+ "}");
+ JavaFileObject moduleFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "interface TestModule {",
+ " @Provides",
+ " static String provideString() { return \"test\"; }",
+ "}");
+
+ Compilation compilation = daggerCompiler().compile(componentFile, moduleFile);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining("Cannot override generated method: TestComponent.create()");
+ }
+
+ @Test
+ public void subcomponentMethodNameBuilder_succeeds() {
+ JavaFileObject componentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " TestSubcomponent.Builder subcomponent();",
+ "}");
+ JavaFileObject subcomponentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestSubcomponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules=TestModule.class)",
+ "interface TestSubcomponent {",
+ " String builder();",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " TestSubcomponent build();",
+ " }",
+ "}");
+ JavaFileObject moduleFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "interface TestModule {",
+ " @Provides",
+ " static String provideString() { return \"test\"; }",
+ "}");
+
+ Compilation compilation = daggerCompiler().compile(componentFile, subcomponentFile, moduleFile);
+ assertThat(compilation).succeeded();
+ }
+
@Test public void componentOnEnum() {
JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
"package test;",
diff --git a/javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java b/javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java
new file mode 100644
index 000000000..a754108ea
--- /dev/null
+++ b/javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java
@@ -0,0 +1,615 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static org.junit.Assert.assertThrows;
+
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.XVariableElement;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import com.google.testing.compile.JavaFileObjects;
+import dagger.Component;
+import dagger.internal.codegen.base.DaggerSuperficialValidation;
+import dagger.internal.codegen.base.DaggerSuperficialValidation.ValidationException;
+import dagger.internal.codegen.javac.JavacPluginModule;
+import java.util.Set;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.inject.Singleton;
+import javax.lang.model.element.TypeElement;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class DaggerSuperficialValidationTest {
+ private static final Joiner NEW_LINES = Joiner.on("\n ");
+
+ @Test
+ public void missingReturnType() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "test.TestClass",
+ "package test;",
+ "",
+ "abstract class TestClass {",
+ " abstract MissingType blah();",
+ "}");
+ assertAbout(javaSource())
+ .that(javaFileObject)
+ .processedWith(
+ new AssertingProcessor() {
+ @Override
+ void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => element (METHOD): blah()",
+ " => type (EXECUTABLE method): ()MissingType",
+ " => type (ERROR return type): MissingType"));
+ }
+ })
+ .failsToCompile();
+ }
+
+ @Test
+ public void missingGenericReturnType() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "test.TestClass",
+ "package test;",
+ "",
+ "abstract class TestClass {",
+ " abstract MissingType<?> blah();",
+ "}");
+ assertAbout(javaSource())
+ .that(javaFileObject)
+ .processedWith(
+ new AssertingProcessor() {
+ @Override
+ void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => element (METHOD): blah()",
+ " => type (EXECUTABLE method): ()<any>",
+ " => type (ERROR return type): <any>"));
+ }
+ })
+ .failsToCompile();
+ }
+
+ @Test
+ public void missingReturnTypeTypeParameter() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "test.TestClass",
+ "package test;",
+ "",
+ "import java.util.Map;",
+ "import java.util.Set;",
+ "",
+ "abstract class TestClass {",
+ " abstract Map<Set<?>, MissingType<?>> blah();",
+ "}");
+ assertAbout(javaSource())
+ .that(javaFileObject)
+ .processedWith(
+ new AssertingProcessor() {
+ @Override
+ void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => element (METHOD): blah()",
+ " => type (EXECUTABLE method): "
+ + "()java.util.Map<java.util.Set<?>,<any>>",
+ " => type (DECLARED return type): "
+ + "java.util.Map<java.util.Set<?>,<any>>",
+ " => type (ERROR type argument): <any>"));
+ }
+ })
+ .failsToCompile();
+ }
+
+ @Test
+ public void missingTypeParameter() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "test.TestClass", //
+ "package test;",
+ "",
+ "class TestClass<T extends MissingType> {}");
+ assertAbout(javaSource())
+ .that(javaFileObject)
+ .processedWith(
+ new AssertingProcessor() {
+ @Override
+ void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => element (TYPE_PARAMETER): T",
+ " => type (ERROR bound type): MissingType"));
+ }
+ })
+ .failsToCompile();
+ }
+
+ @Test
+ public void missingParameterType() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "test.TestClass",
+ "package test;",
+ "",
+ "abstract class TestClass {",
+ " abstract void foo(MissingType x);",
+ "}");
+ assertAbout(javaSource())
+ .that(javaFileObject)
+ .processedWith(
+ new AssertingProcessor() {
+ @Override
+ void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => element (METHOD): foo(MissingType)",
+ " => type (EXECUTABLE method): (MissingType)void",
+ " => type (ERROR parameter type): MissingType"));
+ }
+ })
+ .failsToCompile();
+ }
+
+ @Test
+ public void missingAnnotation() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "test.TestClass", //
+ "package test;",
+ "",
+ "@MissingAnnotation",
+ "class TestClass {}");
+ assertAbout(javaSource())
+ .that(javaFileObject)
+ .processedWith(
+ new AssertingProcessor() {
+ @Override
+ void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => annotation: @MissingAnnotation",
+ " => type (ERROR annotation type): MissingAnnotation"));
+ }
+ })
+ .failsToCompile();
+ }
+
+ @Test
+ public void handlesRecursiveTypeParams() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "test.TestClass", //
+ "package test;",
+ "",
+ "class TestClass<T extends Comparable<T>> {}");
+ assertAbout(javaSource())
+ .that(javaFileObject)
+ .processedWith(
+ new AssertingProcessor() {
+ @Override
+ void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ superficialValidation.validateElement(testClassElement);
+ }
+ })
+ .compilesWithoutError();
+ }
+
+ @Test
+ public void handlesRecursiveType() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "test.TestClass",
+ "package test;",
+ "",
+ "abstract class TestClass {",
+ " abstract TestClass foo(TestClass x);",
+ "}");
+ assertAbout(javaSource())
+ .that(javaFileObject)
+ .processedWith(
+ new AssertingProcessor() {
+ @Override
+ void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ superficialValidation.validateElement(testClassElement);
+ }
+ })
+ .compilesWithoutError();
+ }
+
+ @Test
+ public void missingWildcardBound() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "test.TestClass",
+ "package test;",
+ "",
+ "import java.util.Set;",
+ "",
+ "class TestClass {",
+ " Set<? extends MissingType> extendsTest() {",
+ " return null;",
+ " }",
+ "",
+ " Set<? super MissingType> superTest() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(javaFileObject)
+ .processedWith(
+ new AssertingProcessor() {
+ @Override
+ void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => element (METHOD): extendsTest()",
+ " => type (EXECUTABLE method): ()java.util.Set<? extends MissingType>",
+ " => type (DECLARED return type): "
+ + "java.util.Set<? extends MissingType>",
+ " => type (WILDCARD type argument): ? extends MissingType",
+ " => type (ERROR extends bound type): MissingType"));
+ }
+ })
+ .failsToCompile();
+ }
+
+ @Test
+ public void missingIntersection() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "test.TestClass",
+ "package test;",
+ "",
+ "class TestClass<T extends Number & Missing> {}");
+ assertAbout(javaSource())
+ .that(javaFileObject)
+ .processedWith(
+ new AssertingProcessor() {
+ @Override
+ void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => element (TYPE_PARAMETER): T",
+ " => type (ERROR bound type): Missing"));
+ }
+ })
+ .failsToCompile();
+ }
+
+ @Test
+ public void invalidAnnotationValue() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "test.Outer",
+ "package test;",
+ "",
+ "final class Outer {",
+ " @interface TestAnnotation {",
+ " Class[] classes();",
+ " }",
+ "",
+ " @TestAnnotation(classes = Foo)",
+ " static class TestClass {}",
+ "}");
+ assertAbout(javaSource())
+ .that(javaFileObject)
+ .processedWith(
+ new AssertingProcessor() {
+ @Override
+ void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
+ XTypeElement testClassElement =
+ processingEnv.findTypeElement("test.Outer.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.Outer.TestClass",
+ " => annotation: @test.Outer.TestAnnotation(classes = \"<error>\")",
+ " => annotation method: java.lang.Class[] classes()",
+ " => annotation value (ARRAY): value '<error>' with expected type"
+ + " java.lang.Class[]",
+ " => annotation value (STRING): value '<error>' with expected type"
+ + " java.lang.Class"));
+ }
+ })
+ .failsToCompile();
+ }
+
+ @Test
+ public void invalidAnnotationValueOnParameter() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "test.Outer",
+ "package test;",
+ "",
+ "final class Outer {",
+ " @interface TestAnnotation {",
+ " Class[] classes();",
+ " }",
+ "",
+ " static class TestClass {",
+ " TestClass(@TestAnnotation(classes = Foo) String strParam) {}",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(javaFileObject)
+ .processedWith(
+ new AssertingProcessor() {
+ @Override
+ void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
+ XTypeElement testClassElement =
+ processingEnv.findTypeElement("test.Outer.TestClass");
+ XConstructorElement constructor = testClassElement.getConstructors().get(0);
+ XVariableElement parameter = constructor.getParameters().get(0);
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(parameter));
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.Outer.TestClass",
+ " => element (CONSTRUCTOR): TestClass(java.lang.String)",
+ " => element (PARAMETER): strParam",
+ " => annotation: @test.Outer.TestAnnotation(classes = \"<error>\")",
+ " => annotation method: java.lang.Class[] classes()",
+ " => annotation value (ARRAY): value '<error>' with expected type"
+ + " java.lang.Class[]",
+ " => annotation value (STRING): value '<error>' with expected type"
+ + " java.lang.Class"));
+ }
+ })
+ .failsToCompile();
+ }
+
+ @Test
+ public void invalidSuperclassInTypeHierarchy() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "test.Outer",
+ "package test;",
+ "",
+ "final class Outer {",
+ " Child<Long> getChild() { return null; }",
+ "",
+ " static class Child<T> extends Parent<T> {}",
+ "",
+ " static class Parent<T> extends MissingType<T> {}",
+ "}");
+ assertAbout(javaSource())
+ .that(javaFileObject)
+ .processedWith(
+ new AssertingProcessor() {
+ @Override
+ void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
+ XTypeElement outerElement = processingEnv.findTypeElement("test.Outer");
+ XMethodElement getChildMethod = outerElement.getDeclaredMethods().get(0);
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () ->
+ superficialValidation.validateTypeHierarchyOf(
+ "return type", getChildMethod, getChildMethod.getReturnType()));
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.Outer",
+ " => element (METHOD): getChild()",
+ " => type (DECLARED return type): test.Outer.Child<java.lang.Long>",
+ " => type (DECLARED supertype): test.Outer.Parent<java.lang.Long>",
+ " => type (ERROR supertype): MissingType<T>"));
+ }
+ })
+ .failsToCompile();
+ }
+
+ @Test
+ public void invalidSuperclassTypeParameterInTypeHierarchy() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "test.Outer",
+ "package test;",
+ "",
+ "final class Outer {",
+ " Child getChild() { return null; }",
+ "",
+ " static class Child extends Parent<MissingType> {}",
+ "",
+ " static class Parent<T> {}",
+ "}");
+ assertAbout(javaSource())
+ .that(javaFileObject)
+ .processedWith(
+ new AssertingProcessor() {
+ @Override
+ void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
+ XTypeElement outerElement = processingEnv.findTypeElement("test.Outer");
+ XMethodElement getChildMethod = outerElement.getDeclaredMethods().get(0);
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () ->
+ superficialValidation.validateTypeHierarchyOf(
+ "return type", getChildMethod, getChildMethod.getReturnType()));
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.Outer",
+ " => element (METHOD): getChild()",
+ " => type (DECLARED return type): test.Outer.Child",
+ " => type (DECLARED supertype): test.Outer.Parent<MissingType>",
+ " => type (ERROR type argument): MissingType"));
+ }
+ })
+ .failsToCompile();
+ }
+
+ private abstract static class AssertingProcessor extends AbstractProcessor {
+ private boolean processed = false;
+
+ @Override
+ public Set<String> getSupportedAnnotationTypes() {
+ return ImmutableSet.of("*");
+ }
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (!processed) {
+ processed = true; // only process once.
+ TestComponent component =
+ DaggerDaggerSuperficialValidationTest_TestComponent.builder()
+ .javacPluginModule(
+ new JavacPluginModule(
+ processingEnv.getElementUtils(), processingEnv.getTypeUtils()))
+ .build();
+ try {
+ runAssertions(component.processingEnv(), component.superficialValidation());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return false;
+ }
+
+ abstract void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation)
+ throws Exception;
+ }
+
+ @Singleton
+ @Component(modules = JavacPluginModule.class)
+ interface TestComponent {
+ XProcessingEnv processingEnv();
+
+ DaggerSuperficialValidation superficialValidation();
+ }
+}
diff --git a/javatests/dagger/internal/codegen/DelegateBindingExpressionTest.java b/javatests/dagger/internal/codegen/DelegateRequestRepresentationTest.java
index dc8b7588d..e24bebb86 100644
--- a/javatests/dagger/internal/codegen/DelegateBindingExpressionTest.java
+++ b/javatests/dagger/internal/codegen/DelegateRequestRepresentationTest.java
@@ -32,7 +32,7 @@ import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class DelegateBindingExpressionTest {
+public class DelegateRequestRepresentationTest {
@Parameters(name = "{0}")
public static Collection<Object[]> parameters() {
return CompilerMode.TEST_PARAMETERS;
@@ -40,7 +40,7 @@ public class DelegateBindingExpressionTest {
private final CompilerMode compilerMode;
- public DelegateBindingExpressionTest(CompilerMode compilerMode) {
+ public DelegateRequestRepresentationTest(CompilerMode compilerMode) {
this.compilerMode = compilerMode;
}
@@ -147,32 +147,20 @@ public class DelegateBindingExpressionTest {
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
FAST_INIT_MODE,
- " private volatile Object regularScoped = new MemoizedSentinel();",
- " private volatile ReusableScoped reusableScoped;",
- "",
- " private RegularScoped regularScoped() {",
- " Object local = regularScoped;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = regularScoped;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new RegularScoped();",
- " regularScoped = DoubleCheck.reentrantCheck(regularScoped, local);",
- " }",
- " }",
- " }",
- " return (RegularScoped) local;",
- " }",
- "",
- " private ReusableScoped reusableScoped() {",
- " Object local = reusableScoped;",
- " if (local == null) {",
- " local = new ReusableScoped();",
- " reusableScoped = (ReusableScoped) local;",
- " }",
- " return (ReusableScoped) local;",
- " }",
- "")
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.regularScopedProvider =",
+ " DoubleCheck.provider(",
+ " new SwitchingProvider<RegularScoped>(testComponent, 0));",
+ " this.reusableScopedProvider =",
+ " SingleCheck.provider(",
+ " new SwitchingProvider<ReusableScoped>(testComponent, 1));",
+ " this.reusableProvider =",
+ " DoubleCheck.provider((Provider) reusableScopedProvider);",
+ " this.unscopedProvider = new SwitchingProvider<>(testComponent, 2);",
+ " this.unscopedProvider2 =",
+ " DoubleCheck.provider((Provider) unscopedProvider);",
+ " }")
.addLinesIn(
DEFAULT_MODE,
" @SuppressWarnings(\"unchecked\")",
@@ -186,8 +174,20 @@ public class DelegateBindingExpressionTest {
" this.unscopedProvider = DoubleCheck.provider(",
" (Provider) Unscoped_Factory.create());",
" }")
- .addLines( //
- "}")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0: return (T) new RegularScoped();",
+ " case 1: return (T) new ReusableScoped();",
+ " case 2: return (T) new Unscoped();",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
+ " }")
.build());
}
@@ -226,32 +226,18 @@ public class DelegateBindingExpressionTest {
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
FAST_INIT_MODE,
- " private volatile Object regularScoped = new MemoizedSentinel();",
- " private volatile ReusableScoped reusableScoped;",
- "",
- " private RegularScoped regularScoped() {",
- " Object local = regularScoped;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = regularScoped;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new RegularScoped();",
- " regularScoped = DoubleCheck.reentrantCheck(regularScoped, local);",
- " }",
- " }",
- " }",
- " return (RegularScoped) local;",
- " }",
- "",
- " private ReusableScoped reusableScoped() {",
- " Object local = reusableScoped;",
- " if (local == null) {",
- " local = new ReusableScoped();",
- " reusableScoped = (ReusableScoped) local;",
- " }",
- " return (ReusableScoped) local;",
- " }",
- "")
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.regularScopedProvider =",
+ " DoubleCheck.provider(",
+ " new SwitchingProvider<RegularScoped>(testComponent, 0));",
+ " this.reusableScopedProvider =",
+ " SingleCheck.provider(",
+ " new SwitchingProvider<ReusableScoped>(testComponent, 1));",
+ " this.unscopedProvider = new SwitchingProvider<>(testComponent, 2);",
+ " this.unscopedProvider2 =",
+ " SingleCheck.provider((Provider) unscopedProvider);",
+ " }")
.addLinesIn(
DEFAULT_MODE,
" @SuppressWarnings(\"unchecked\")",
@@ -263,8 +249,6 @@ public class DelegateBindingExpressionTest {
" this.unscopedProvider = SingleCheck.provider(",
" (Provider) Unscoped_Factory.create());",
" }")
- .addLines( //
- "}")
.build());
}
@@ -299,35 +283,9 @@ public class DelegateBindingExpressionTest {
"package test;",
"",
GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Object regularScoped = new MemoizedSentinel();",
- " private volatile ReusableScoped reusableScoped;",
- "",
- " private RegularScoped regularScoped() {",
- " Object local = regularScoped;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = regularScoped;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new RegularScoped();",
- " regularScoped = DoubleCheck.reentrantCheck(regularScoped, local);",
- " }",
- " }",
- " }",
- " return (RegularScoped) local;",
- " }",
- "",
- " private ReusableScoped reusableScoped() {",
- " Object local = reusableScoped;",
- " if (local == null) {",
- " local = new ReusableScoped();",
- " reusableScoped = (ReusableScoped) local;",
- " }",
- " return (ReusableScoped) local;",
- " }",
- "")
+ "final class DaggerTestComponent implements TestComponent {",
+ " private Provider<RegularScoped> regularScopedProvider;",
+ " private Provider<ReusableScoped> reusableScopedProvider;")
.addLinesIn(
DEFAULT_MODE,
" @SuppressWarnings(\"unchecked\")",
@@ -337,8 +295,17 @@ public class DelegateBindingExpressionTest {
" this.reusableScopedProvider = ",
" SingleCheck.provider(ReusableScoped_Factory.create());",
" }")
- .addLines( //
- "}")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.regularScopedProvider =",
+ " DoubleCheck.provider(",
+ " new SwitchingProvider<RegularScoped>(testComponent, 0));",
+ " this.reusableScopedProvider =",
+ " SingleCheck.provider(",
+ " new SwitchingProvider<ReusableScoped>(testComponent, 1));",
+ " }")
.build());
}
@@ -401,43 +368,29 @@ public class DelegateBindingExpressionTest {
"package test;",
"",
GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {")
+ "final class DaggerTestComponent implements TestComponent {",
+ " @SuppressWarnings(\"rawtypes\")",
+ " private Provider subtypeProvider;")
.addLinesIn(
DEFAULT_MODE,
- " @SuppressWarnings(\"rawtypes\")",
- " private Provider subtypeProvider;",
- "",
" @SuppressWarnings(\"unchecked\")",
" private void initialize() {",
" this.subtypeProvider = DoubleCheck.provider(Subtype_Factory.create());",
- " }",
- "",
- " @Override",
- " public Supertype supertype() {",
- " return (Supertype) subtypeProvider.get();",
" }")
.addLinesIn(
FAST_INIT_MODE,
- " private volatile Object subtype = new MemoizedSentinel();",
- "",
- " private Object subtype() {",
- " Object local = subtype;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = subtype;",
- " if (local instanceof MemoizedSentinel) {",
- " local = Subtype_Factory.newInstance();",
- " subtype = DoubleCheck.reentrantCheck(subtype, local);",
- " }",
- " }",
- " }",
- " return (Object) local;",
- " }",
- "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.subtypeProvider =",
+ " DoubleCheck.provider(",
+ " new SwitchingProvider<Object>(testComponent, 0));",
+ " }")
+ .addLines(
" @Override",
" public Supertype supertype() {",
- " return (Supertype) subtype();",
- " }")
+ " return (Supertype) subtypeProvider.get();",
+ " }",
+ "}")
.build());
}
@@ -509,9 +462,7 @@ public class DelegateBindingExpressionTest {
"package test;",
"",
GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {")
- .addLinesIn(
- DEFAULT_MODE,
+ "final class DaggerTestComponent implements TestComponent {",
" @SuppressWarnings(\"rawtypes\")",
" private Provider subtypeProvider;",
"",
@@ -521,28 +472,6 @@ public class DelegateBindingExpressionTest {
" return UsesSupertype_Factory.newInstance(subtypeProvider.get());",
" }",
"}")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Object subtype = new MemoizedSentinel();",
- "",
- " private Object subtype() {",
- " Object local = subtype;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = subtype;",
- " if (local instanceof MemoizedSentinel) {",
- " local = Subtype_Factory.newInstance();",
- " subtype = DoubleCheck.reentrantCheck(subtype, local);",
- " }",
- " }",
- " }",
- " return (Object) local;",
- " }",
- "",
- " @Override",
- " public UsesSupertype usesSupertype() {",
- " return UsesSupertype_Factory.newInstance(subtype());",
- " }")
.build());
}
@@ -582,6 +511,7 @@ public class DelegateBindingExpressionTest {
"@Component(modules = TestModule.class)",
"interface TestComponent {",
" Provider<CharSequence> charSequence();",
+ " CharSequence charSequenceInstance();",
"",
" @Named(\"named\") Provider<String> namedString();",
"}");
@@ -604,7 +534,12 @@ public class DelegateBindingExpressionTest {
DEFAULT_MODE,
" @Override",
" public Provider<CharSequence> charSequence() {",
- " return (Provider) TestModule_ProvideStringFactory.create();",
+ " return ((Provider) TestModule_ProvideStringFactory.create());",
+ " }",
+ "",
+ " @Override",
+ " public CharSequence charSequenceInstance() {",
+ " return TestModule_ProvideStringFactory.provideString();",
" }",
"",
" @Override",
@@ -614,36 +549,30 @@ public class DelegateBindingExpressionTest {
"}")
.addLinesIn(
FAST_INIT_MODE,
- " private volatile Provider<String> provideStringProvider;",
+ " private Provider<String> provideStringProvider;",
"",
- " private Provider<String> stringProvider() {",
- " Object local = provideStringProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " provideStringProvider = (Provider<String>) local;",
- " }",
- " return (Provider<String>) local;",
+ " @Override",
+ " public Provider<CharSequence> charSequence() {",
+ " return ((Provider) provideStringProvider);",
" }",
"",
" @Override",
- " public Provider<CharSequence> charSequence() {",
- " return (Provider) stringProvider();",
+ " public CharSequence charSequenceInstance() {",
+ " return (CharSequence) ((Provider) provideStringProvider).get();",
" }",
"",
" @Override",
" public Provider<String> namedString() {",
- " return stringProvider();",
+ " return provideStringProvider;",
" }",
"",
- " private final class SwitchingProvider<T> implements Provider<T> {",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
" switch (id) {",
- " case 0:",
- " return (T) TestModule_ProvideStringFactory.provideString();",
- " default:",
- " throw new AssertionError(id);",
+ " case 0: return (T) TestModule_ProvideStringFactory.provideString();",
+ " default: throw new AssertionError(id);",
" }",
" }",
" }")
@@ -705,45 +634,39 @@ public class DelegateBindingExpressionTest {
DEFAULT_MODE,
" @Override",
" public Provider<CharSequence> charSequence() {",
- " return (Provider) TestModule_ProvideStringFactory.create();",
+ " return ((Provider) TestModule_ProvideStringFactory.create());",
" }",
" @Override",
" public Provider<Object> object() {",
- " return (Provider) TestModule_ProvideStringFactory.create();",
+ " return ((Provider) TestModule_ProvideStringFactory.create());",
" }",
"}")
.addLinesIn(
FAST_INIT_MODE,
- " private volatile Provider<String> provideStringProvider;",
+ " private Provider<String> provideStringProvider;",
"",
- " private Provider<String> stringProvider() {",
- " Object local = provideStringProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " provideStringProvider = (Provider<String>) local;",
- " }",
- " return (Provider<String>) local;",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.provideStringProvider = new SwitchingProvider<>(testComponent, 0);",
" }",
"",
" @Override",
" public Provider<CharSequence> charSequence() {",
- " return (Provider) stringProvider();",
+ " return ((Provider) provideStringProvider);",
" }",
"",
" @Override",
" public Provider<Object> object() {",
- " return (Provider) stringProvider();",
+ " return ((Provider) provideStringProvider);",
" }",
"",
- " private final class SwitchingProvider<T> implements Provider<T> {",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
" switch (id) {",
- " case 0:",
- " return (T) TestModule_ProvideStringFactory.provideString();",
- " default:",
- " throw new AssertionError(id);",
+ " case 0: return (T) TestModule_ProvideStringFactory.provideString();",
+ " default: throw new AssertionError(id);",
" }",
" }",
" }")
@@ -811,28 +734,20 @@ public class DelegateBindingExpressionTest {
DEFAULT_MODE,
" @Override",
" public Provider<Supertype> supertypeProvider() {",
- " return (Provider) Subtype_Factory.create();",
+ " return ((Provider) Subtype_Factory.create());",
" }",
"}")
.addLinesIn(
FAST_INIT_MODE,
- " private volatile Provider subtypeProvider;",
- "",
- " private Provider subtypeProvider() {",
- " Object local = subtypeProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " subtypeProvider = (Provider) local;",
- " }",
- " return (Provider) local;",
- " }",
+ " @SuppressWarnings(\"rawtypes\")",
+ " private Provider subtypeProvider;",
"",
" @Override",
" public Provider<Supertype> supertypeProvider() {",
- " return subtypeProvider();",
+ " return subtypeProvider;",
" }",
"",
- " private final class SwitchingProvider<T> implements Provider<T> {",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
@@ -897,70 +812,41 @@ public class DelegateBindingExpressionTest {
"package test;",
"",
GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {")
+ "final class DaggerTestComponent implements TestComponent {",
+ " private Provider<String> provideStringProvider;",
+ " private Provider<Object> bindStringProvider;")
.addLinesIn(
DEFAULT_MODE,
- " private Provider<String> provideStringProvider;",
- " private Provider<Object> bindStringProvider;",
- "",
" @SuppressWarnings(\"unchecked\")",
" private void initialize() {",
" this.provideStringProvider =",
" SingleCheck.provider(TestModule_ProvideStringFactory.create());",
" this.bindStringProvider =",
" DoubleCheck.provider((Provider) provideStringProvider);",
- " }",
- "",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.provideStringProvider =",
+ " SingleCheck.provider(",
+ " new SwitchingProvider<String>(testComponent, 0));",
+ " this.bindStringProvider =",
+ " DoubleCheck.provider((Provider) provideStringProvider);",
+ " }")
+ .addLines(
" @Override",
" public Provider<Object> object() {",
" return bindStringProvider;",
- " }",
- "}")
+ " }")
.addLinesIn(
FAST_INIT_MODE,
- " private volatile String string;",
- " private volatile Object object = new MemoizedSentinel();",
- " private volatile Provider<Object> bindStringProvider;",
- "",
- " private String string() {",
- " Object local = string;",
- " if (local == null) {",
- " local = TestModule_ProvideStringFactory.provideString();",
- " string = (String) local;",
- " }",
- " return (String) local;",
- " }",
- "",
- " private Object object2() {",
- " Object local = object;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = object;",
- " if (local instanceof MemoizedSentinel) {",
- " local = string();",
- " object = DoubleCheck.reentrantCheck(object, local);",
- " }",
- " }",
- " }",
- " return (Object) local;",
- " }",
- "",
- " @Override",
- " public Provider<Object> object() {",
- " Object local = bindStringProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " bindStringProvider = (Provider<Object>) local;",
- " }",
- " return (Provider<Object>) local;",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
" switch (id) {",
- " case 0: return (T) DaggerTestComponent.this.object2();",
+ " case 0: return (T) TestModule_ProvideStringFactory.provideString();",
" default: throw new AssertionError(id);",
" }",
" }",
diff --git a/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java b/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java
index 22547b5cb..2b7ae64da 100644
--- a/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java
+++ b/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java
@@ -82,6 +82,11 @@ public class DependencyCycleValidationTest {
" Outer.B(aParam)",
" Outer.B is injected at",
" Outer.C(bParam)",
+ " Outer.C is injected at",
+ " Outer.A(cParam)",
+ " ...",
+ "",
+ "The cycle is requested via:",
" Outer.C is requested at",
" Outer.CComponent.getC()"))
.inFile(SIMPLE_CYCLIC_DEPENDENCY)
@@ -104,6 +109,9 @@ public class DependencyCycleValidationTest {
" Outer.B(aParam)",
" Outer.B is injected at",
" Outer.C(bParam)",
+ " Outer.C is injected at",
+ " Outer.A(cParam)",
+ " ...",
"",
"======================",
"Full classname legend:",
@@ -178,6 +186,11 @@ public class DependencyCycleValidationTest {
" Outer.B is injected at",
" Outer.C(bParam)",
" Outer.C is injected at",
+ " Outer.A(cParam)",
+ " ...",
+ "",
+ "The cycle is requested via:",
+ " Outer.C is injected at",
" Outer.D(cParam)",
" Outer.D is requested at",
" Outer.DComponent.getD()"))
@@ -242,6 +255,11 @@ public class DependencyCycleValidationTest {
" Outer.B(aParam)",
" Outer.B is injected at",
" Outer.C(bParam)",
+ " Outer.C is injected at",
+ " Outer.CModule.c(c)",
+ " ...",
+ "",
+ "The cycle is requested via:",
" Outer.C is requested at",
" Outer.CComponent.getC()"))
.inFile(component)
@@ -303,6 +321,11 @@ public class DependencyCycleValidationTest {
" Outer.B(aParam)",
" Outer.B is injected at",
" Outer.C(bParam)",
+ " Outer.C is injected at",
+ " Outer.CModule.c(c)",
+ " ...",
+ "",
+ "The cycle is requested via:",
" Outer.C is requested at",
" Outer.CComponent.getC()"))
.inFile(component)
@@ -357,6 +380,11 @@ public class DependencyCycleValidationTest {
" Outer.B(aParam)",
" Outer.B is injected at",
" Outer.C(bParam)",
+ " Outer.C is injected at",
+ " Outer.A(cParam)",
+ " ...",
+ "",
+ "The cycle is requested via:",
" Provider<Outer.C> is injected at",
" Outer.D(cParam)",
" Outer.D is requested at",
@@ -439,6 +467,11 @@ public class DependencyCycleValidationTest {
" CycleModule.object(string)",
" Object is injected at",
" CycleModule.string(object)",
+ " String is injected at",
+ " CycleModule.object(string)",
+ " ...",
+ "",
+ "The cycle is requested via:",
" String is requested at",
" Grandchild.entry()"))
.inFile(parent)
@@ -521,6 +554,11 @@ public class DependencyCycleValidationTest {
" CycleModule.object(string)",
" Object is injected at",
" CycleModule.string(object)",
+ " String is injected at",
+ " CycleModule.object(string)",
+ " ...",
+ "",
+ "The cycle is requested via:",
" String is requested at",
" Child.entry() [Parent → Child]"))
.inFile(parent)
@@ -572,6 +610,11 @@ public class DependencyCycleValidationTest {
" TestModule.bindQualified(unqualified)",
" @SomeQualifier Object is injected at",
" TestModule.bindUnqualified(qualified)",
+ " Object is injected at",
+ " TestModule.bindQualified(unqualified)",
+ " ...",
+ "",
+ "The cycle is requested via:",
" Object is requested at",
" TestComponent.unqualified()"))
.inFile(component)
@@ -612,6 +655,11 @@ public class DependencyCycleValidationTest {
"Found a dependency cycle:",
" Object is injected at",
" TestModule.bindToSelf(sameKey)",
+ " Object is injected at",
+ " TestModule.bindToSelf(sameKey)",
+ " ...",
+ "",
+ "The cycle is requested via:",
" Object is requested at",
" TestComponent.selfReferential()"))
.inFile(component)
@@ -666,6 +714,11 @@ public class DependencyCycleValidationTest {
" test.B.a",
" test.B is injected at",
" test.A.b",
+ " ...",
+ "",
+ "The cycle is requested via:",
+ " test.B is injected at",
+ " test.A.b",
" test.A is injected at",
" CycleComponent.inject(test.A)"))
.inFile(component)
diff --git a/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java b/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java
index fbda59d78..ecb11468a 100644
--- a/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java
+++ b/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java
@@ -1096,4 +1096,74 @@ public class DuplicateBindingsValidationTest {
.onLineContaining("interface Parent");
assertThat(compilation).hadErrorCount(1);
}
+
+ // Tests the format of the error for a somewhat complex binding method.
+ @Test
+ public void formatTest() {
+ JavaFileObject modules =
+ JavaFileObjects.forSourceLines(
+ "test.Modules",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableList;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Singleton;",
+ "",
+ "interface Modules {",
+ " @interface Foo {",
+ " Class<?> bar();",
+ " }",
+ "",
+ " @Module",
+ " interface Module1 {",
+ " @Provides",
+ " @Singleton",
+ " @Foo(bar = String.class)",
+ " static String foo(",
+ " @SuppressWarnings(\"unused\") int a,",
+ " @SuppressWarnings(\"unused\") ImmutableList<Boolean> blah) {",
+ " return \"\";",
+ " }",
+ " }",
+ "",
+ " @Module",
+ " interface Module2 {",
+ " @Provides",
+ " @Singleton",
+ " @Foo(bar = String.class)",
+ " static String foo(",
+ " @SuppressWarnings(\"unused\") int a,",
+ " @SuppressWarnings(\"unused\") ImmutableList<Boolean> blah) {",
+ " return \"\";",
+ " }",
+ " }",
+ "}");
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.BindsInstance;",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "@Component(modules = {Modules.Module1.class, Modules.Module2.class})",
+ "interface TestComponent {",
+ " @Modules.Foo(bar = String.class) String foo();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(modules, component);
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(1);
+ assertThat(compilation)
+ .hadErrorContaining(
+ message(
+ "String is bound multiple times:",
+ " @Provides @Singleton @Modules.Foo(bar = String.class) String "
+ + "Modules.Module1.foo(int, ImmutableList<Boolean>)",
+ " @Provides @Singleton @Modules.Foo(bar = String.class) String "
+ + "Modules.Module2.foo(int, ImmutableList<Boolean>)"))
+ .inFile(component);
+ }
}
diff --git a/javatests/dagger/internal/codegen/ElidedFactoriesTest.java b/javatests/dagger/internal/codegen/ElidedFactoriesTest.java
index 0c557c0a8..5180c4894 100644
--- a/javatests/dagger/internal/codegen/ElidedFactoriesTest.java
+++ b/javatests/dagger/internal/codegen/ElidedFactoriesTest.java
@@ -17,6 +17,8 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
+import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
+import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
import static dagger.internal.codegen.Compilers.compilerWithOptions;
import com.google.testing.compile.Compilation;
@@ -84,6 +86,8 @@ public class ElidedFactoriesTest {
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerSimpleComponent implements SimpleComponent {",
+ " private final DaggerSimpleComponent simpleComponent = this;",
+ "",
" private DaggerSimpleComponent() {}",
"",
" public static Builder builder() {",
@@ -100,8 +104,7 @@ public class ElidedFactoriesTest {
" }",
"",
" static final class Builder {",
- " private Builder() {",
- " }",
+ " private Builder() {}",
"",
" public SimpleComponent build() {",
" return new DaggerSimpleComponent();",
@@ -169,147 +172,64 @@ public class ElidedFactoriesTest {
"interface SimpleComponent {",
" NeedsProvider needsProvider();",
"}");
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerSimpleComponent",
- "package test;",
- "",
- GeneratedLines.generatedImports(
- "import dagger.internal.DoubleCheck;",
- "import dagger.internal.MemoizedSentinel;",
- "import javax.inject.Provider;"),
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " private volatile Object scopedType = new MemoizedSentinel();",
- " private volatile Provider<DependsOnScoped> dependsOnScopedProvider;",
- "",
- " private DaggerSimpleComponent() {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static SimpleComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " private ScopedType scopedType() {",
- " Object local = scopedType;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = scopedType;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new ScopedType();",
- " scopedType = DoubleCheck.reentrantCheck(scopedType, local);",
- " }",
- " }",
- " }",
- " return (ScopedType) local;",
- " }",
- "",
- " private DependsOnScoped dependsOnScoped() {",
- " return new DependsOnScoped(scopedType());",
- " }",
- "",
- " private Provider<DependsOnScoped> dependsOnScopedProvider() {",
- " Object local = dependsOnScopedProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " dependsOnScopedProvider = (Provider<DependsOnScoped>) local;",
- " }",
- " return (Provider<DependsOnScoped>) local;",
- " }",
- "",
- " @Override",
- " public NeedsProvider needsProvider() {",
- " return new NeedsProvider(dependsOnScopedProvider());",
- " }",
- "",
- " static final class Builder {",
- " private Builder() {}",
- "",
- " public SimpleComponent build() {",
- " return new DaggerSimpleComponent();",
- " }",
- " }",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0: return (T) DaggerSimpleComponent.this.dependsOnScoped();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerSimpleComponent",
- "package test;",
- "",
- GeneratedLines.generatedImports(
- "import dagger.internal.DoubleCheck;",
- "import javax.inject.Provider;"),
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " private Provider<ScopedType> scopedTypeProvider;",
- " private Provider<DependsOnScoped> dependsOnScopedProvider;",
- "",
- " private DaggerSimpleComponent() {",
- " initialize();",
- " }",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static SimpleComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.scopedTypeProvider = DoubleCheck.provider(ScopedType_Factory.create());",
- " this.dependsOnScopedProvider = ",
- " DependsOnScoped_Factory.create(scopedTypeProvider);",
- " }",
- "",
- " @Override",
- " public NeedsProvider needsProvider() {",
- " return new NeedsProvider(dependsOnScopedProvider);",
- " }",
- "",
- " static final class Builder {",
- " private Builder() {",
- " }",
- "",
- " public SimpleComponent build() {",
- " return new DaggerSimpleComponent();",
- " }",
- " }",
- "}");
- }
+
Compilation compilation =
compilerWithOptions(compilerMode.javacopts())
.compile(scopedType, dependsOnScoped, componentFile, needsProvider);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerSimpleComponent")
- .hasSourceEquivalentTo(generatedComponent);
+ .containsElementsIn(
+ compilerMode
+ .javaFileBuilder("test.DaggerSimpleComponent")
+ .addLines(
+ "package test;",
+ "",
+ GeneratedLines.generatedAnnotations(),
+ "final class DaggerSimpleComponent implements SimpleComponent {",
+ " private final DaggerSimpleComponent simpleComponent = this;",
+ "",
+ " private Provider<ScopedType> scopedTypeProvider;",
+ " private Provider<DependsOnScoped> dependsOnScopedProvider;")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.scopedTypeProvider =",
+ " DoubleCheck.provider(ScopedType_Factory.create());",
+ " this.dependsOnScopedProvider = ",
+ " DependsOnScoped_Factory.create(scopedTypeProvider);",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.scopedTypeProvider =",
+ " DoubleCheck.provider(",
+ " new SwitchingProvider<ScopedType>(simpleComponent, 1));",
+ " this.dependsOnScopedProvider = ",
+ " new SwitchingProvider<>(simpleComponent, 0);",
+ " }")
+ .addLines(
+ " @Override",
+ " public NeedsProvider needsProvider() {",
+ " return new NeedsProvider(dependsOnScopedProvider);",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0: return (T) new DependsOnScoped(",
+ " simpleComponent.scopedTypeProvider.get());",
+ " case 1: return (T) new ScopedType();",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
+ " }")
+ .build());
}
@Test
@@ -363,130 +283,63 @@ public class ElidedFactoriesTest {
" DependsOnScoped dependsOnScoped();",
"}");
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerSimpleComponent",
- "package test;",
- "",
- GeneratedLines.generatedImports(
- "import dagger.internal.DoubleCheck;",
- "import dagger.internal.MemoizedSentinel;"),
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " private volatile Object scopedType = new MemoizedSentinel();",
- "",
- " private DaggerSimpleComponent() {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static SimpleComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " private ScopedType scopedType() {",
- " Object local = scopedType;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = scopedType;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new ScopedType();",
- " scopedType = DoubleCheck.reentrantCheck(scopedType, local);",
- " }",
- " }",
- " }",
- " return (ScopedType) local;",
- " }",
- "",
- " @Override",
- " public Sub sub() {",
- " return new SubImpl();",
- " }",
- "",
- " static final class Builder {",
- " private Builder() {}",
- "",
- " public SimpleComponent build() {",
- " return new DaggerSimpleComponent();",
- " }",
- " }",
- "",
- " private final class SubImpl implements Sub {",
- " private SubImpl() {}",
- "",
- " @Override",
- " public DependsOnScoped dependsOnScoped() {",
- " return new DependsOnScoped(DaggerSimpleComponent.this.scopedType());",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerSimpleComponent",
- "package test;",
- "",
- GeneratedLines.generatedImports(
- "import dagger.internal.DoubleCheck;",
- "import javax.inject.Provider;"),
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " private Provider<ScopedType> scopedTypeProvider;",
- "",
- " private DaggerSimpleComponent() {",
- " initialize();",
- " }",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static SimpleComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.scopedTypeProvider = DoubleCheck.provider(ScopedType_Factory.create());",
- " }",
- "",
- " @Override",
- " public Sub sub() {",
- " return new SubImpl();",
- " }",
- "",
- " static final class Builder {",
- " private Builder() {}",
- "",
- " public SimpleComponent build() {",
- " return new DaggerSimpleComponent();",
- " }",
- " }",
- "",
- " private final class SubImpl implements Sub {",
- " private SubImpl() {}",
- "",
- " @Override",
- " public DependsOnScoped dependsOnScoped() {",
- " return new DependsOnScoped(",
- " DaggerSimpleComponent.this.scopedTypeProvider.get());",
- " }",
- " }",
- "}");
- }
Compilation compilation =
compilerWithOptions(compilerMode.javacopts())
.compile(scopedType, dependsOnScoped, componentFile, subcomponentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerSimpleComponent")
- .hasSourceEquivalentTo(generatedComponent);
+ .containsElementsIn(
+ compilerMode
+ .javaFileBuilder("test.DaggerSimpleComponent")
+ .addLines(
+ "package test;",
+ "",
+ GeneratedLines.generatedAnnotations(),
+ "final class DaggerSimpleComponent implements SimpleComponent {",
+ " private final DaggerSimpleComponent simpleComponent = this;",
+ " private Provider<ScopedType> scopedTypeProvider;")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.scopedTypeProvider = DoubleCheck.provider(",
+ " ScopedType_Factory.create());",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.scopedTypeProvider = DoubleCheck.provider(",
+ " new SwitchingProvider<ScopedType>(simpleComponent, 0));",
+ " }")
+ .addLines(
+ " @Override",
+ " public Sub sub() {",
+ " return new SubImpl(simpleComponent);",
+ " }",
+ "",
+ " private static final class SubImpl implements Sub {",
+ " private final DaggerSimpleComponent simpleComponent;",
+ " private final SubImpl subImpl = this;",
+ "",
+ " @Override",
+ " public DependsOnScoped dependsOnScoped() {",
+ " return new DependsOnScoped(simpleComponent.scopedTypeProvider.get());",
+ " }",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0: return (T) new ScopedType();",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
+ " }")
+ .build());
}
}
diff --git a/javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java b/javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java
index e27534d7b..3e7992b6d 100644
--- a/javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java
+++ b/javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java
@@ -17,11 +17,11 @@
package dagger.internal.codegen;
import static com.google.common.truth.Truth.assertThat;
-import static dagger.model.RequestKind.INSTANCE;
-import static dagger.model.RequestKind.LAZY;
-import static dagger.model.RequestKind.PRODUCED;
-import static dagger.model.RequestKind.PRODUCER;
-import static dagger.model.RequestKind.PROVIDER;
+import static dagger.spi.model.RequestKind.INSTANCE;
+import static dagger.spi.model.RequestKind.LAZY;
+import static dagger.spi.model.RequestKind.PRODUCED;
+import static dagger.spi.model.RequestKind.PRODUCER;
+import static dagger.spi.model.RequestKind.PROVIDER;
import dagger.internal.codegen.binding.FrameworkType;
import dagger.internal.codegen.binding.FrameworkTypeMapper;
diff --git a/javatests/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java b/javatests/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java
index 3e78d6b5d..175903354 100644
--- a/javatests/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java
+++ b/javatests/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java
@@ -134,8 +134,12 @@ public final class InjectConstructorFactoryGeneratorTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class GenericClass_Factory<T> implements Factory<GenericClass<T>> {",
" private final Provider<T> tProvider;",
@@ -183,8 +187,12 @@ public final class InjectConstructorFactoryGeneratorTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class GenericClass_Factory<A, B> implements",
" Factory<GenericClass<A, B>> {",
@@ -234,8 +242,13 @@ public final class InjectConstructorFactoryGeneratorTest {
"test.GenericClass_Factory",
"package test;",
"",
- GeneratedLines.generatedImports("import dagger.internal.Factory;"),
+ GeneratedLines.generatedImports(
+ "import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class GenericClass_Factory<T> implements Factory<GenericClass<T>> {",
" @Override",
@@ -279,8 +292,12 @@ public final class InjectConstructorFactoryGeneratorTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class GenericClass_Factory<A, B>",
" implements Factory<GenericClass<A, B>> {",
@@ -331,9 +348,13 @@ public final class InjectConstructorFactoryGeneratorTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import java.util.List;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class GenericClass_Factory<A extends Number & Comparable<A>,",
" B extends List<? extends String>,",
@@ -400,8 +421,12 @@ public final class InjectConstructorFactoryGeneratorTest {
"import dagger.Lazy;",
"import dagger.internal.DoubleCheck;",
"import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata(\"test.QualifierA\")",
GeneratedLines.generatedAnnotations(),
"public final class GenericClass_Factory<A, B>",
" implements Factory<GenericClass<A, B>> {",
@@ -547,14 +572,16 @@ public final class InjectConstructorFactoryGeneratorTest {
"}");
Compilation compilation = daggerCompiler().compile(file);
assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
- .hadErrorContaining("Types may only contain one injected constructor")
- .inFile(file)
- .onLine(6);
- assertThat(compilation)
- .hadErrorContaining("Types may only contain one injected constructor")
+ .hadErrorContaining(
+ "Type test.TooManyInjectConstructors may only contain one injected constructor. "
+ + "Found: ["
+ + "TooManyInjectConstructors(), "
+ + "TooManyInjectConstructors(java.lang.String)"
+ + "]")
.inFile(file)
- .onLine(8);
+ .onLine(5);
}
@Test public void multipleQualifiersOnInjectConstructorParameter() {
@@ -1067,8 +1094,12 @@ public final class InjectConstructorFactoryGeneratorTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class InjectConstructor_Factory ",
" implements Factory<InjectConstructor> {",
@@ -1114,8 +1145,12 @@ public final class InjectConstructorFactoryGeneratorTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class AllInjections_Factory implements Factory<AllInjections> {",
" private final Provider<String> sProvider;",
@@ -1174,9 +1209,13 @@ public final class InjectConstructorFactoryGeneratorTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import java.util.List;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class InjectConstructor_Factory ",
" implements Factory<InjectConstructor> {",
@@ -1227,8 +1266,12 @@ public final class InjectConstructorFactoryGeneratorTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class InjectConstructor_Factory ",
" implements Factory<InjectConstructor> {",
@@ -1283,9 +1326,13 @@ public final class InjectConstructorFactoryGeneratorTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import javax.inject.Provider;",
"import other.pkg.Outer;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class InjectConstructor_Factory ",
" implements Factory<InjectConstructor> {",
@@ -1342,8 +1389,12 @@ public final class InjectConstructorFactoryGeneratorTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class InjectConstructor_Factory ",
" implements Factory<InjectConstructor> {",
@@ -1395,8 +1446,13 @@ public final class InjectConstructorFactoryGeneratorTest {
"test.SimpleType_Factory",
"package test;",
"",
- GeneratedLines.generatedImports("import dagger.internal.Factory;"),
+ GeneratedLines.generatedImports(
+ "import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class SimpleType_Factory implements Factory<SimpleType> {",
" @Override public SimpleType get() {",
@@ -1442,8 +1498,13 @@ public final class InjectConstructorFactoryGeneratorTest {
"test.OuterType_A_Factory",
"package test;",
"",
- GeneratedLines.generatedImports("import dagger.internal.Factory;"),
+ GeneratedLines.generatedImports(
+ "import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class OuterType_A_Factory implements Factory<OuterType.A> {",
" @Override public OuterType.A get() {",
@@ -1467,4 +1528,452 @@ public final class InjectConstructorFactoryGeneratorTest {
.compilesWithoutError()
.and().generatesSources(aFactory);
}
+
+ @Test
+ public void testScopedMetadata() {
+ JavaFileObject scopedBinding =
+ JavaFileObjects.forSourceLines(
+ "test.ScopedBinding",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "class ScopedBinding {",
+ " @Inject",
+ " ScopedBinding() {}",
+ "}");
+ Compilation compilation = daggerCompiler().compile(scopedBinding);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test.ScopedBinding_Factory")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.ScopedBinding_Factory",
+ "package test;",
+ "",
+ "@ScopeMetadata(\"javax.inject.Singleton\")",
+ "@QualifierMetadata",
+ GeneratedLines.generatedAnnotations(),
+ "public final class ScopedBinding_Factory implements Factory<ScopedBinding> {}"));
+ }
+
+ @Test
+ public void testScopedMetadataWithCustomScope() {
+ JavaFileObject customScope =
+ JavaFileObjects.forSourceLines(
+ "test.CustomScope",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope",
+ "@interface CustomScope {",
+ " String value();",
+ "}");
+
+ JavaFileObject customAnnotation =
+ JavaFileObjects.forSourceLines(
+ "test.CustomAnnotation",
+ "package test;",
+ "",
+ "@interface CustomAnnotation {",
+ " String value();",
+ "}");
+
+ JavaFileObject scopedBinding =
+ JavaFileObjects.forSourceLines(
+ "test.ScopedBinding",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Singleton;",
+ "",
+ "@CustomAnnotation(\"someValue\")",
+ "@CustomScope(\"someOtherValue\")",
+ "class ScopedBinding {",
+ " @Inject",
+ " ScopedBinding() {}",
+ "}");
+ Compilation compilation =
+ daggerCompiler().compile(scopedBinding, customScope, customAnnotation);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test.ScopedBinding_Factory")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.ScopedBinding_Factory",
+ "package test;",
+ "",
+ "@ScopeMetadata(\"test.CustomScope\")",
+ "@QualifierMetadata",
+ GeneratedLines.generatedAnnotations(),
+ "public final class ScopedBinding_Factory implements Factory<ScopedBinding> {}"));
+ }
+
+ @Test
+ public void testQualifierMetadata() {
+ JavaFileObject someBinding =
+ JavaFileObjects.forSourceLines(
+ "test.SomeBinding",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Singleton;",
+ "",
+ "@NonQualifier",
+ "@MisplacedQualifier",
+ "class SomeBinding {",
+ " @NonQualifier @FieldQualifier @Inject String injectField;",
+ " @NonQualifier @MisplacedQualifier String nonDaggerField;",
+ "",
+ " @NonQualifier",
+ " @Inject",
+ " SomeBinding(@NonQualifier @ConstructorParameterQualifier Double d) {}",
+ "",
+ " @NonQualifier",
+ " @MisplacedQualifier",
+ " SomeBinding(@NonQualifier @MisplacedQualifier Double d, int i) {}",
+ "",
+ " @NonQualifier",
+ " @MisplacedQualifier",
+ " @Inject",
+ " void injectMethod(@NonQualifier @MethodParameterQualifier Float f) {}",
+ "",
+ " @NonQualifier",
+ " @MisplacedQualifier",
+ " void nonDaggerMethod(@NonQualifier @MisplacedQualifier Float f) {}",
+ "}");
+ JavaFileObject fieldQualifier =
+ JavaFileObjects.forSourceLines(
+ "test.FieldQualifier",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "@interface FieldQualifier {}");
+ JavaFileObject constructorParameterQualifier =
+ JavaFileObjects.forSourceLines(
+ "test.ConstructorParameterQualifier",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "@interface ConstructorParameterQualifier {}");
+ JavaFileObject methodParameterQualifier =
+ JavaFileObjects.forSourceLines(
+ "test.MethodParameterQualifier",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "@interface MethodParameterQualifier {}");
+ JavaFileObject misplacedQualifier =
+ JavaFileObjects.forSourceLines(
+ "test.MisplacedQualifier",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "@interface MisplacedQualifier {}");
+ JavaFileObject nonQualifier =
+ JavaFileObjects.forSourceLines(
+ "test.NonQualifier",
+ "package test;",
+ "",
+ "@interface NonQualifier {}");
+ Compilation compilation =
+ daggerCompiler().compile(
+ someBinding,
+ fieldQualifier,
+ constructorParameterQualifier,
+ methodParameterQualifier,
+ misplacedQualifier,
+ nonQualifier);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test.SomeBinding_Factory")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.SomeBinding_Factory",
+ "package test;",
+ "",
+ // Verifies that the @QualifierMetadata for the generated Factory does not contain
+ // @MisplacedQualifier, @NonQualifier, @MethodParameterQualifier or @FieldQualifier.
+ "@ScopeMetadata",
+ "@QualifierMetadata(\"test.ConstructorParameterQualifier\")",
+ GeneratedLines.generatedAnnotations(),
+ "public final class SomeBinding_Factory implements Factory<SomeBinding> {}"));
+ assertThat(compilation)
+ .generatedSourceFile("test.SomeBinding_MembersInjector")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.SomeBinding_MembersInjector",
+ "package test;",
+ "",
+ // Verifies that the @QualifierMetadata for the generated MembersInjector does not
+ // contain @MisplacedQualifier, @NonQualifier, or @ConstructorParameterQualifier.
+ "@QualifierMetadata({",
+ " \"test.FieldQualifier\",",
+ " \"test.MethodParameterQualifier\"",
+ "})",
+ GeneratedLines.generatedAnnotations(),
+ "public final class SomeBinding_MembersInjector",
+ " implements MembersInjector<SomeBinding> {}"));
+ }
+
+ @Test
+ public void testComplexQualifierMetadata() {
+ JavaFileObject someBinding =
+ JavaFileObjects.forSourceLines(
+ "test.SomeBinding",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Inject;",
+ "",
+ "class SomeBinding {",
+ " @QualifierWithValue(1) @Inject String injectField;",
+ "",
+ " @Inject",
+ " SomeBinding(",
+ " @pkg1.SameNameQualifier String str1,",
+ " @pkg2.SameNameQualifier String str2) {}",
+ "",
+ " @Inject",
+ " void injectMethod(@test.Outer.NestedQualifier Float f) {}",
+ "}");
+ JavaFileObject qualifierWithValue =
+ JavaFileObjects.forSourceLines(
+ "test.QualifierWithValue",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "@interface QualifierWithValue {",
+ " int value();",
+ "}");
+ JavaFileObject pkg1SameNameQualifier =
+ JavaFileObjects.forSourceLines(
+ "pkg1.SameNameQualifier",
+ "package pkg1;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "public @interface SameNameQualifier {}");
+ JavaFileObject pkg2SameNameQualifier =
+ JavaFileObjects.forSourceLines(
+ "pkg2.SameNameQualifier",
+ "package pkg2;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "public @interface SameNameQualifier {}");
+ JavaFileObject nestedQualifier =
+ JavaFileObjects.forSourceLines(
+ "test.Outer",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "interface Outer {",
+ " @Qualifier",
+ " @interface NestedQualifier {}",
+ "}");
+ Compilation compilation =
+ daggerCompiler().compile(
+ someBinding,
+ qualifierWithValue,
+ pkg1SameNameQualifier,
+ pkg2SameNameQualifier,
+ nestedQualifier);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test.SomeBinding_Factory")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.SomeBinding_Factory",
+ "package test;",
+ "",
+ "@ScopeMetadata",
+ "@QualifierMetadata({\"pkg1.SameNameQualifier\", \"pkg2.SameNameQualifier\"})",
+ GeneratedLines.generatedAnnotations(),
+ "public final class SomeBinding_Factory implements Factory<SomeBinding> {}"));
+ assertThat(compilation)
+ .generatedSourceFile("test.SomeBinding_MembersInjector")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.SomeBinding_MembersInjector",
+ "package test;",
+ "",
+ "@QualifierMetadata({",
+ " \"test.QualifierWithValue\",",
+ " \"test.Outer.NestedQualifier\"",
+ "})",
+ GeneratedLines.generatedAnnotations(),
+ "public final class SomeBinding_MembersInjector",
+ " implements MembersInjector<SomeBinding> {}"));
+ }
+
+ @Test
+ public void testBaseClassQualifierMetadata() {
+ JavaFileObject foo =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Singleton;",
+ "",
+ "class Foo extends FooBase {",
+ " @FooFieldQualifier @Inject String injectField;",
+ "",
+ " @Inject",
+ " Foo(@FooConstructorQualifier int i) { super(i); }",
+ "",
+ " @Inject",
+ " void injectMethod(@FooMethodQualifier float f) {}",
+ "}");
+ JavaFileObject fooFieldQualifier =
+ JavaFileObjects.forSourceLines(
+ "test.FooFieldQualifier",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "@interface FooFieldQualifier {}");
+ JavaFileObject fooConstructorQualifier =
+ JavaFileObjects.forSourceLines(
+ "test.FooConstructorQualifier",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "@interface FooConstructorQualifier {}");
+ JavaFileObject fooMethodQualifier =
+ JavaFileObjects.forSourceLines(
+ "test.FooMethodQualifier",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "@interface FooMethodQualifier {}");
+ JavaFileObject fooBase =
+ JavaFileObjects.forSourceLines(
+ "test.FooBase",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Singleton;",
+ "",
+ "class FooBase {",
+ " @FooBaseFieldQualifier @Inject String injectField;",
+ "",
+ " @Inject",
+ " FooBase(@FooBaseConstructorQualifier int i) {}",
+ "",
+ " @Inject",
+ " void injectMethod(@FooBaseMethodQualifier float f) {}",
+ "}");
+ JavaFileObject fooBaseFieldQualifier =
+ JavaFileObjects.forSourceLines(
+ "test.FooBaseFieldQualifier",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "@interface FooBaseFieldQualifier {}");
+ JavaFileObject fooBaseConstructorQualifier =
+ JavaFileObjects.forSourceLines(
+ "test.FooBaseConstructorQualifier",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "@interface FooBaseConstructorQualifier {}");
+ JavaFileObject fooBaseMethodQualifier =
+ JavaFileObjects.forSourceLines(
+ "test.FooBaseMethodQualifier",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "@interface FooBaseMethodQualifier {}");
+ Compilation compilation =
+ daggerCompiler().compile(
+ foo,
+ fooBase,
+ fooFieldQualifier,
+ fooConstructorQualifier,
+ fooMethodQualifier,
+ fooBaseFieldQualifier,
+ fooBaseConstructorQualifier,
+ fooBaseMethodQualifier);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test.Foo_Factory")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.Foo_Factory",
+ "package test;",
+ "",
+ "@ScopeMetadata",
+ // Verifies that Foo_Factory only contains Foo's qualifiers and not FooBase's too.
+ "@QualifierMetadata(\"test.FooConstructorQualifier\")",
+ GeneratedLines.generatedAnnotations(),
+ "public final class Foo_Factory implements Factory<Foo> {}"));
+ assertThat(compilation)
+ .generatedSourceFile("test.Foo_MembersInjector")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.Foo_MembersInjector",
+ "package test;",
+ "",
+ // Verifies that Foo_Factory only contains Foo's qualifiers and not FooBase's too.
+ "@QualifierMetadata({",
+ " \"test.FooFieldQualifier\",",
+ " \"test.FooMethodQualifier\"",
+ "})",
+ GeneratedLines.generatedAnnotations(),
+ "public final class Foo_MembersInjector implements MembersInjector<Foo> {}"));
+ assertThat(compilation)
+ .generatedSourceFile("test.FooBase_Factory")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.Foo_Factory",
+ "package test;",
+ "",
+ "@ScopeMetadata",
+ "@QualifierMetadata(\"test.FooBaseConstructorQualifier\")",
+ GeneratedLines.generatedAnnotations(),
+ "public final class FooBase_Factory implements Factory<FooBase> {}"));
+ assertThat(compilation)
+ .generatedSourceFile("test.FooBase_MembersInjector")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.FooBase_MembersInjector",
+ "package test;",
+ "",
+ "@QualifierMetadata({",
+ " \"test.FooBaseFieldQualifier\",",
+ " \"test.FooBaseMethodQualifier\"",
+ "})",
+ GeneratedLines.generatedAnnotations(),
+ "public final class FooBase_MembersInjector",
+ " implements MembersInjector<FooBase> {}"));
+ }
}
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/KotlinApplication.kt b/javatests/dagger/internal/codegen/InvalidInjectConstructor.java
index 765fb3614..ac3e61f70 100644
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/KotlinApplication.kt
+++ b/javatests/dagger/internal/codegen/InvalidInjectConstructor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Dagger Authors.
+ * Copyright (C) 2022 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,17 +14,20 @@
* limitations under the License.
*/
-package dagger.hilt.android.example.gradle.simpleKotlin
+package dagger.internal.codegen;
-import android.app.Application
-import dagger.hilt.android.HiltAndroidApp
-import javax.inject.Inject
+import javax.inject.Inject;
+
+
+/** A class that invalidly declares 2 inject constructors. */
+@SuppressWarnings("MoreThanOneInjectableConstructor") // Testing too many constructors
+public final class InvalidInjectConstructor {
+
+ @Inject String str;
+
+ @Inject
+ InvalidInjectConstructor() {}
-@HiltAndroidApp
-class KotlinApplication : Application() {
- // Shows that we can inject SingletonComponent bindings into an application.
@Inject
- @Model
- @JvmField
- var model: String? = null
+ InvalidInjectConstructor(String str) {}
}
diff --git a/javatests/dagger/internal/codegen/InvalidInjectConstructorTest.java b/javatests/dagger/internal/codegen/InvalidInjectConstructorTest.java
new file mode 100644
index 000000000..b49593ab3
--- /dev/null
+++ b/javatests/dagger/internal/codegen/InvalidInjectConstructorTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.testing.compile.CompilationSubject.assertThat;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+// Tests an invalid inject constructor that avoids validation in its own library by using
+// a dependency on jsr330 rather than Dagger gets validated when used in a component.
+@RunWith(JUnit4.class)
+public final class InvalidInjectConstructorTest {
+
+ @Test
+ public void usedInvalidConstructorFails() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.internal.codegen.InvalidInjectConstructor;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " InvalidInjectConstructor invalidInjectConstructor();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(component);
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(2);
+ assertThat(compilation)
+ .hadErrorContaining(
+ "Type dagger.internal.codegen.InvalidInjectConstructor may only contain one injected "
+ + "constructor. Found: ["
+ + "InvalidInjectConstructor(), "
+ + "InvalidInjectConstructor(java.lang.String)"
+ + "]");
+ // TODO(b/215620949): Avoid reporting missing bindings on a type that has errors.
+ assertThat(compilation)
+ .hadErrorContaining(
+ "InvalidInjectConstructor cannot be provided without an @Inject constructor or an "
+ + "@Provides-annotated method.");
+ }
+
+ @Test
+ public void unusedInvalidConstructorFails() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.internal.codegen.InvalidInjectConstructor;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ // Here we're only using the members injection, but we're testing that we still validate
+ // the constructors
+ " void inject(InvalidInjectConstructor instance);",
+ "}");
+ Compilation compilation = daggerCompiler().compile(component);
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(2);
+ assertThat(compilation)
+ .hadErrorContaining(
+ "Type dagger.internal.codegen.InvalidInjectConstructor may only contain one injected "
+ + "constructor. Found: ["
+ + "InvalidInjectConstructor(), "
+ + "InvalidInjectConstructor(java.lang.String)"
+ + "]");
+ // TODO(b/215620949): Avoid reporting missing bindings on a type that has errors.
+ assertThat(compilation)
+ .hadErrorContaining(
+ "InvalidInjectConstructor cannot be provided without an @Inject constructor or an "
+ + "@Provides-annotated method.");
+ }
+}
diff --git a/javatests/dagger/internal/codegen/KeyFactoryTest.java b/javatests/dagger/internal/codegen/KeyFactoryTest.java
index fdf62cbbf..604bfe2fe 100644
--- a/javatests/dagger/internal/codegen/KeyFactoryTest.java
+++ b/javatests/dagger/internal/codegen/KeyFactoryTest.java
@@ -16,27 +16,31 @@
package dagger.internal.codegen;
+import static androidx.room.compiler.processing.compat.XConverters.toXProcessing;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XProcessingEnv;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.testing.compile.CompilationRule;
-import dagger.BindsInstance;
+import com.squareup.javapoet.TypeName;
import dagger.Component;
import dagger.Module;
import dagger.Provides;
import dagger.internal.codegen.binding.KeyFactory;
+import dagger.internal.codegen.javac.JavacPluginModule;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
-import dagger.model.Key.MultibindingContributionIdentifier;
import dagger.multibindings.ElementsIntoSet;
import dagger.multibindings.IntoSet;
import dagger.producers.ProducerModule;
import dagger.producers.Produces;
+import dagger.spi.model.DaggerAnnotation;
+import dagger.spi.model.DaggerType;
+import dagger.spi.model.Key;
+import dagger.spi.model.Key.MultibindingContributionIdentifier;
import java.lang.annotation.Retention;
import java.util.Set;
import javax.inject.Inject;
@@ -61,12 +65,17 @@ import org.junit.runners.JUnit4;
public class KeyFactoryTest {
@Rule public CompilationRule compilationRule = new CompilationRule();
+ @Inject XProcessingEnv processingEnv;
@Inject DaggerElements elements;
@Inject DaggerTypes types;
@Inject KeyFactory keyFactory;
@Before public void setUp() {
- DaggerKeyFactoryTest_TestComponent.factory().create(compilationRule).inject(this);
+ DaggerKeyFactoryTest_TestComponent.builder()
+ .javacPluginModule(
+ new JavacPluginModule(compilationRule.getElements(), compilationRule.getTypes()))
+ .build()
+ .inject(this);
}
@Test public void forInjectConstructorWithResolvedType() {
@@ -76,7 +85,7 @@ public class KeyFactoryTest {
Iterables.getOnlyElement(ElementFilter.constructorsIn(typeElement.getEnclosedElements()));
Key key =
keyFactory.forInjectConstructorWithResolvedType(constructor.getEnclosingElement().asType());
- assertThat(key).isEqualTo(Key.builder(typeElement.asType()).build());
+ assertThat(key).isEqualTo(Key.builder(fromJava(typeElement.asType())).build());
assertThat(key.toString()).isEqualTo("dagger.internal.codegen.KeyFactoryTest.InjectedClass");
}
@@ -92,7 +101,7 @@ public class KeyFactoryTest {
ExecutableElement providesMethod =
Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements()));
Key key = keyFactory.forProvidesMethod(providesMethod, moduleElement);
- assertThat(key).isEqualTo(Key.builder(stringType).build());
+ assertThat(key).isEqualTo(Key.builder(fromJava(stringType)).build());
assertThat(key.toString()).isEqualTo("java.lang.String");
}
@@ -112,10 +121,9 @@ public class KeyFactoryTest {
ExecutableElement providesMethod =
Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements()));
Key key = keyFactory.forProvidesMethod(providesMethod, moduleElement);
- assertThat(MoreTypes.equivalence().wrap(key.qualifier().get().getAnnotationType()))
- .isEqualTo(MoreTypes.equivalence().wrap(qualifierElement.asType()));
- assertThat(MoreTypes.equivalence().wrap(key.type()))
- .isEqualTo(MoreTypes.equivalence().wrap(stringType));
+ assertThat(TypeName.get(key.qualifier().get().java().getAnnotationType()))
+ .isEqualTo(TypeName.get(qualifierElement.asType()));
+ assertThat(TypeName.get(key.type().java())).isEqualTo(TypeName.get(stringType));
assertThat(key.toString())
.isEqualTo(
"@dagger.internal.codegen.KeyFactoryTest.TestQualifier({"
@@ -141,7 +149,7 @@ public class KeyFactoryTest {
Element injectionField =
Iterables.getOnlyElement(ElementFilter.fieldsIn(injectableElement.getEnclosedElements()));
AnnotationMirror qualifier = Iterables.getOnlyElement(injectionField.getAnnotationMirrors());
- Key injectionKey = Key.builder(type).qualifier(qualifier).build();
+ Key injectionKey = Key.builder(fromJava(type)).qualifier(fromJava(qualifier)).build();
assertThat(provisionKey).isEqualTo(injectionKey);
assertThat(injectionKey.toString())
@@ -203,7 +211,7 @@ public class KeyFactoryTest {
Key key = keyFactory.forProvidesMethod(providesMethod, moduleElement);
assertThat(key)
.isEqualTo(
- Key.builder(setOfStringsType)
+ Key.builder(fromJava(setOfStringsType))
.multibindingContributionIdentifier(
new MultibindingContributionIdentifier(providesMethod, moduleElement))
.build());
@@ -270,7 +278,7 @@ public class KeyFactoryTest {
for (ExecutableElement producesMethod
: ElementFilter.methodsIn(moduleElement.getEnclosedElements())) {
Key key = keyFactory.forProducesMethod(producesMethod, moduleElement);
- assertThat(key).isEqualTo(Key.builder(stringType).build());
+ assertThat(key).isEqualTo(Key.builder(fromJava(stringType)).build());
assertThat(key.toString()).isEqualTo("java.lang.String");
}
}
@@ -297,7 +305,7 @@ public class KeyFactoryTest {
Key key = keyFactory.forProducesMethod(producesMethod, moduleElement);
assertThat(key)
.isEqualTo(
- Key.builder(setOfStringsType)
+ Key.builder(fromJava(setOfStringsType))
.multibindingContributionIdentifier(
new MultibindingContributionIdentifier(producesMethod, moduleElement))
.build());
@@ -310,6 +318,14 @@ public class KeyFactoryTest {
}
}
+ private DaggerAnnotation fromJava(AnnotationMirror annotation) {
+ return DaggerAnnotation.from(toXProcessing(annotation, processingEnv));
+ }
+
+ private DaggerType fromJava(TypeMirror typeMirror) {
+ return DaggerType.from(toXProcessing(typeMirror, processingEnv));
+ }
+
@ProducerModule
static final class SetProducesMethodsModule {
@Produces @IntoSet String produceString() {
@@ -331,26 +347,8 @@ public class KeyFactoryTest {
}
@Singleton
- @Component(modules = {TestModule.class})
+ @Component(modules = JavacPluginModule.class)
interface TestComponent {
void inject(KeyFactoryTest test);
-
- @Component.Factory
- interface Factory {
- TestComponent create(@BindsInstance CompilationRule compilationRule);
- }
- }
-
- @Module
- static class TestModule {
- @Provides
- static DaggerElements elements(CompilationRule compilationRule) {
- return new DaggerElements(compilationRule.getElements(), compilationRule.getTypes());
- }
-
- @Provides
- static DaggerTypes types(CompilationRule compilationRule, DaggerElements elements) {
- return new DaggerTypes(compilationRule.getTypes(), elements);
- }
}
}
diff --git a/javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java b/javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java
index aa2a0ff6b..622ca8601 100644
--- a/javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java
+++ b/javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java
@@ -17,6 +17,8 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
+import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
+import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
@@ -93,22 +95,24 @@ public class MapBindingComponentProcessorTest {
" LOGIN;",
"}");
- JavaFileObject HandlerFile = JavaFileObjects.forSourceLines("test.Handler",
- "package test;",
- "",
- "interface Handler {}");
- JavaFileObject LoginHandlerFile = JavaFileObjects.forSourceLines("test.LoginHandler",
- "package test;",
- "",
- "class LoginHandler implements Handler {",
- " public LoginHandler() {}",
- "}");
- JavaFileObject AdminHandlerFile = JavaFileObjects.forSourceLines("test.AdminHandler",
- "package test;",
- "",
- "class AdminHandler implements Handler {",
- " public AdminHandler() {}",
- "}");
+ JavaFileObject handlerFile =
+ JavaFileObjects.forSourceLines("test.Handler", "package test;", "", "interface Handler {}");
+ JavaFileObject loginHandlerFile =
+ JavaFileObjects.forSourceLines(
+ "test.LoginHandler",
+ "package test;",
+ "",
+ "class LoginHandler implements Handler {",
+ " public LoginHandler() {}",
+ "}");
+ JavaFileObject adminHandlerFile =
+ JavaFileObjects.forSourceLines(
+ "test.AdminHandler",
+ "package test;",
+ "",
+ "class AdminHandler implements Handler {",
+ " public AdminHandler() {}",
+ "}");
JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
"package test;",
"",
@@ -120,119 +124,7 @@ public class MapBindingComponentProcessorTest {
"interface TestComponent {",
" Provider<Map<PathEnum, Provider<Handler>>> dispatcher();",
"}");
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {",
- " private final MapModuleOne mapModuleOne;",
- " private final MapModuleTwo mapModuleTwo;",
- " private volatile Provider<Handler> provideAdminHandlerProvider;",
- " private volatile Provider<Handler> provideLoginHandlerProvider;",
- " private volatile Provider<Map<PathEnum, Provider<Handler>>>",
- " mapOfPathEnumAndProviderOfHandlerProvider;",
- "",
- " private Provider<Handler> provideAdminHandlerProvider() {",
- " Object local = provideAdminHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(1);",
- " provideAdminHandlerProvider = (Provider<Handler>) local;",
- " }",
- " return (Provider<Handler>) local;",
- " }",
- "",
- " private Provider<Handler> provideLoginHandlerProvider() {",
- " Object local = provideLoginHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(2);",
- " provideLoginHandlerProvider = (Provider<Handler>) local;",
- " }",
- " return (Provider<Handler>) local;",
- " }",
- "",
- " private Map<PathEnum, Provider<Handler>>",
- " mapOfPathEnumAndProviderOfHandler() {",
- " return ImmutableMap.<PathEnum, Provider<Handler>>of(",
- " PathEnum.ADMIN, provideAdminHandlerProvider(),",
- " PathEnum.LOGIN, provideLoginHandlerProvider());",
- " }",
- "",
- " @Override",
- " public Provider<Map<PathEnum, Provider<Handler>>> dispatcher() {",
- " Object local = mapOfPathEnumAndProviderOfHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " mapOfPathEnumAndProviderOfHandlerProvider =",
- " (Provider<Map<PathEnum, Provider<Handler>>>) local;",
- " }",
- " return (Provider<Map<PathEnum, Provider<Handler>>>) local;",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0:",
- " return (T) DaggerTestComponent.this",
- " .mapOfPathEnumAndProviderOfHandler();",
- " case 1:",
- " return (T) MapModuleOne_ProvideAdminHandlerFactory",
- " .provideAdminHandler(DaggerTestComponent.this.mapModuleOne);",
- " case 2:",
- " return (T) MapModuleTwo_ProvideLoginHandlerFactory",
- " .provideLoginHandler(DaggerTestComponent.this.mapModuleTwo);",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {",
- " private Provider<Handler> provideAdminHandlerProvider;",
- " private Provider<Handler> provideLoginHandlerProvider;",
- " private Provider<Map<PathEnum, Provider<Handler>>>",
- " mapOfPathEnumAndProviderOfHandlerProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(",
- " final MapModuleOne mapModuleOneParam,",
- " final MapModuleTwo mapModuleTwoParam) {",
- " this.provideAdminHandlerProvider =",
- " MapModuleOne_ProvideAdminHandlerFactory.create(mapModuleOneParam);",
- " this.provideLoginHandlerProvider =",
- " MapModuleTwo_ProvideLoginHandlerFactory.create(mapModuleTwoParam);",
- " this.mapOfPathEnumAndProviderOfHandlerProvider =",
- " MapProviderFactory.<PathEnum, Handler>builder(2)",
- " .put(PathEnum.ADMIN, provideAdminHandlerProvider)",
- " .put(PathEnum.LOGIN, provideLoginHandlerProvider)",
- " .build();",
- " }",
- "",
- " @Override",
- " public Provider<Map<PathEnum, Provider<Handler>>> dispatcher() {",
- " return mapOfPathEnumAndProviderOfHandlerProvider;",
- " }",
- "}");
- }
+
Compilation compilation =
compilerWithOptions(compilerMode.javacopts())
.compile(
@@ -240,14 +132,82 @@ public class MapBindingComponentProcessorTest {
mapModuleTwoFile,
enumKeyFile,
pathEnumFile,
- HandlerFile,
- LoginHandlerFile,
- AdminHandlerFile,
+ handlerFile,
+ loginHandlerFile,
+ adminHandlerFile,
componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
+ .containsElementsIn(
+ compilerMode
+ .javaFileBuilder("test.DaggerTestComponent")
+ .addLines(
+ "package test;",
+ "",
+ GeneratedLines.generatedAnnotations(),
+ "final class DaggerTestComponent implements TestComponent {",
+ " private final DaggerTestComponent testComponent = this;",
+ " private Provider<Handler> provideAdminHandlerProvider;",
+ " private Provider<Handler> provideLoginHandlerProvider;",
+ " private Provider<Map<PathEnum, Provider<Handler>>>",
+ " mapOfPathEnumAndProviderOfHandlerProvider;")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(",
+ " final MapModuleOne mapModuleOneParam,",
+ " final MapModuleTwo mapModuleTwoParam) {",
+ " this.provideAdminHandlerProvider =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(mapModuleOneParam);",
+ " this.provideLoginHandlerProvider =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(mapModuleTwoParam);",
+ " this.mapOfPathEnumAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<PathEnum, Handler>builder(2)",
+ " .put(PathEnum.ADMIN, provideAdminHandlerProvider)",
+ " .put(PathEnum.LOGIN, provideLoginHandlerProvider)",
+ " .build();",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final MapModuleOne mapModuleOneParam,",
+ " final MapModuleTwo mapModuleTwoParam) {",
+ " this.provideAdminHandlerProvider =",
+ " new SwitchingProvider<>(testComponent, 1);",
+ " this.provideLoginHandlerProvider =",
+ " new SwitchingProvider<>(testComponent, 2);",
+ " this.mapOfPathEnumAndProviderOfHandlerProvider =",
+ " new SwitchingProvider<>(testComponent, 0);",
+ " }")
+ .addLines(
+ " @Override",
+ " public Provider<Map<PathEnum, Provider<Handler>>> dispatcher() {",
+ " return mapOfPathEnumAndProviderOfHandlerProvider;",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ "",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0: return (T) ImmutableMap.<PathEnum, Provider<Handler>>of(",
+ " PathEnum.ADMIN,",
+ " testComponent.provideAdminHandlerProvider,",
+ " PathEnum.LOGIN,",
+ " testComponent.provideLoginHandlerProvider);",
+ " case 1: return (T) MapModuleOne_ProvideAdminHandlerFactory",
+ " .provideAdminHandler(testComponent.mapModuleOne);",
+ " case 2: return (T) MapModuleTwo_ProvideLoginHandlerFactory",
+ " .provideLoginHandler(testComponent.mapModuleTwo);",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
+ " }",
+ "}")
+ .build());
}
@Test
@@ -500,22 +460,24 @@ public class MapBindingComponentProcessorTest {
" return new LoginHandler();",
" }",
"}");
- JavaFileObject HandlerFile = JavaFileObjects.forSourceLines("test.Handler",
- "package test;",
- "",
- "interface Handler {}");
- JavaFileObject LoginHandlerFile = JavaFileObjects.forSourceLines("test.LoginHandler",
- "package test;",
- "",
- "class LoginHandler implements Handler {",
- " public LoginHandler() {}",
- "}");
- JavaFileObject AdminHandlerFile = JavaFileObjects.forSourceLines("test.AdminHandler",
- "package test;",
- "",
- "class AdminHandler implements Handler {",
- " public AdminHandler() {}",
- "}");
+ JavaFileObject handlerFile =
+ JavaFileObjects.forSourceLines("test.Handler", "package test;", "", "interface Handler {}");
+ JavaFileObject loginHandlerFile =
+ JavaFileObjects.forSourceLines(
+ "test.LoginHandler",
+ "package test;",
+ "",
+ "class LoginHandler implements Handler {",
+ " public LoginHandler() {}",
+ "}");
+ JavaFileObject adminHandlerFile =
+ JavaFileObjects.forSourceLines(
+ "test.AdminHandler",
+ "package test;",
+ "",
+ "class AdminHandler implements Handler {",
+ " public AdminHandler() {}",
+ "}");
JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
"package test;",
"",
@@ -527,132 +489,88 @@ public class MapBindingComponentProcessorTest {
"interface TestComponent {",
" Provider<Map<String, Provider<Handler>>> dispatcher();",
"}");
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {",
- " private final MapModuleOne mapModuleOne;",
- " private final MapModuleTwo mapModuleTwo;",
- " private volatile Provider<Handler> provideAdminHandlerProvider;",
- " private volatile Provider<Handler> provideLoginHandlerProvider;",
- " private volatile Provider<Map<String, Provider<Handler>>>",
- " mapOfStringAndProviderOfHandlerProvider;",
- "",
- " private Provider<Handler> provideAdminHandlerProvider() {",
- " Object local = provideAdminHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(1);",
- " provideAdminHandlerProvider = (Provider<Handler>) local;",
- " }",
- " return (Provider<Handler>) local;",
- " }",
- "",
- " private Provider<Handler> provideLoginHandlerProvider() {",
- " Object local = provideLoginHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(2);",
- " provideLoginHandlerProvider = (Provider<Handler>) local;",
- " }",
- " return (Provider<Handler>) local;",
- " }",
- "",
- " private Map<String, Provider<Handler>>",
- " mapOfStringAndProviderOfHandler() {",
- " return ImmutableMap.<String, Provider<Handler>>of(",
- " \"Admin\", provideAdminHandlerProvider(),",
- " \"Login\", provideLoginHandlerProvider());",
- " }",
- "",
- " @Override",
- " public Provider<Map<String, Provider<Handler>>> dispatcher() {",
- " Object local = mapOfStringAndProviderOfHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " mapOfStringAndProviderOfHandlerProvider =",
- " (Provider<Map<String, Provider<Handler>>>) local;",
- " }",
- " return (Provider<Map<String, Provider<Handler>>>) local;",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0:",
- " return (T) DaggerTestComponent.this",
- " .mapOfStringAndProviderOfHandler();",
- " case 1:",
- " return (T) MapModuleOne_ProvideAdminHandlerFactory",
- " .provideAdminHandler(DaggerTestComponent.this.mapModuleOne);",
- " case 2:",
- " return (T) MapModuleTwo_ProvideLoginHandlerFactory",
- " .provideLoginHandler(DaggerTestComponent.this.mapModuleTwo);",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {",
- " private Provider<Handler> provideAdminHandlerProvider;",
- " private Provider<Handler> provideLoginHandlerProvider;",
- " private Provider<Map<String, Provider<Handler>>>",
- " mapOfStringAndProviderOfHandlerProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(",
- " final MapModuleOne mapModuleOneParam,",
- " final MapModuleTwo mapModuleTwoParam) {",
- " this.provideAdminHandlerProvider =",
- " MapModuleOne_ProvideAdminHandlerFactory.create(mapModuleOneParam);",
- " this.provideLoginHandlerProvider =",
- " MapModuleTwo_ProvideLoginHandlerFactory.create(mapModuleTwoParam);",
- " this.mapOfStringAndProviderOfHandlerProvider =",
- " MapProviderFactory.<String, Handler>builder(2)",
- " .put(\"Admin\", provideAdminHandlerProvider)",
- " .put(\"Login\", provideLoginHandlerProvider)",
- " .build();",
- " }",
- "",
- " @Override",
- " public Provider<Map<String, Provider<Handler>>> dispatcher() {",
- " return mapOfStringAndProviderOfHandlerProvider;",
- " }",
- "}");
- }
+
Compilation compilation =
compilerWithOptions(compilerMode.javacopts())
.compile(
mapModuleOneFile,
mapModuleTwoFile,
- HandlerFile,
- LoginHandlerFile,
- AdminHandlerFile,
+ handlerFile,
+ loginHandlerFile,
+ adminHandlerFile,
componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
+ .containsElementsIn(
+ compilerMode
+ .javaFileBuilder("test.DaggerTestComponent")
+ .addLines(
+ "package test;",
+ "",
+ GeneratedLines.generatedAnnotations(),
+ "final class DaggerTestComponent implements TestComponent {",
+ " private final DaggerTestComponent testComponent = this;",
+ " private Provider<Handler> provideAdminHandlerProvider;",
+ " private Provider<Handler> provideLoginHandlerProvider;",
+ " private Provider<Map<String, Provider<Handler>>>",
+ " mapOfStringAndProviderOfHandlerProvider;")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(",
+ " final MapModuleOne mapModuleOneParam,",
+ " final MapModuleTwo mapModuleTwoParam) {",
+ " this.provideAdminHandlerProvider =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(mapModuleOneParam);",
+ " this.provideLoginHandlerProvider =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(mapModuleTwoParam);",
+ " this.mapOfStringAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<String, Handler>builder(2)",
+ " .put(\"Admin\", provideAdminHandlerProvider)",
+ " .put(\"Login\", provideLoginHandlerProvider)",
+ " .build();",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(",
+ " final MapModuleOne mapModuleOneParam,",
+ " final MapModuleTwo mapModuleTwoParam) {",
+ " this.provideAdminHandlerProvider =",
+ " new SwitchingProvider<>(testComponent, 1);",
+ " this.provideLoginHandlerProvider =",
+ " new SwitchingProvider<>(testComponent, 2);",
+ " this.mapOfStringAndProviderOfHandlerProvider =",
+ " new SwitchingProvider<>(testComponent, 0);",
+ " }")
+ .addLines(
+ " @Override",
+ " public Provider<Map<String, Provider<Handler>>> dispatcher() {",
+ " return mapOfStringAndProviderOfHandlerProvider;",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0: return (T) ImmutableMap.<String, Provider<Handler>>of(",
+ " \"Admin\",",
+ " testComponent.provideAdminHandlerProvider,",
+ " \"Login\",",
+ " testComponent.provideLoginHandlerProvider);",
+ " case 1: return (T) MapModuleOne_ProvideAdminHandlerFactory",
+ " .provideAdminHandler(testComponent.mapModuleOne);",
+ " case 2: return (T) MapModuleTwo_ProvideLoginHandlerFactory",
+ " .provideLoginHandler(testComponent.mapModuleTwo);",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
+ " }",
+ "}")
+ .build());
}
@Test
@@ -700,22 +618,24 @@ public class MapBindingComponentProcessorTest {
"public @interface WrappedClassKey {",
" Class<?> value();",
"}");
- JavaFileObject HandlerFile = JavaFileObjects.forSourceLines("test.Handler",
- "package test;",
- "",
- "interface Handler {}");
- JavaFileObject LoginHandlerFile = JavaFileObjects.forSourceLines("test.LoginHandler",
- "package test;",
- "",
- "class LoginHandler implements Handler {",
- " public LoginHandler() {}",
- "}");
- JavaFileObject AdminHandlerFile = JavaFileObjects.forSourceLines("test.AdminHandler",
- "package test;",
- "",
- "class AdminHandler implements Handler {",
- " public AdminHandler() {}",
- "}");
+ JavaFileObject handlerFile =
+ JavaFileObjects.forSourceLines("test.Handler", "package test;", "", "interface Handler {}");
+ JavaFileObject loginHandlerFile =
+ JavaFileObjects.forSourceLines(
+ "test.LoginHandler",
+ "package test;",
+ "",
+ "class LoginHandler implements Handler {",
+ " public LoginHandler() {}",
+ "}");
+ JavaFileObject adminHandlerFile =
+ JavaFileObjects.forSourceLines(
+ "test.AdminHandler",
+ "package test;",
+ "",
+ "class AdminHandler implements Handler {",
+ " public AdminHandler() {}",
+ "}");
JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
"package test;",
"",
@@ -727,144 +647,91 @@ public class MapBindingComponentProcessorTest {
"interface TestComponent {",
" Provider<Map<WrappedClassKey, Provider<Handler>>> dispatcher();",
"}");
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {",
- " private final MapModuleOne mapModuleOne;",
- " private final MapModuleTwo mapModuleTwo;",
- " private volatile Provider<Handler> provideAdminHandlerProvider;",
- " private volatile Provider<Handler> provideLoginHandlerProvider;",
- " private volatile Provider<Map<WrappedClassKey, Provider<Handler>>>",
- " mapOfWrappedClassKeyAndProviderOfHandlerProvider;",
- "",
- " private DaggerTestComponent(",
- " MapModuleOne mapModuleOneParam,",
- " MapModuleTwo mapModuleTwoParam) {",
- " this.mapModuleOne = mapModuleOneParam;",
- " this.mapModuleTwo = mapModuleTwoParam;",
- " }",
- "",
- " private Provider<Handler> provideAdminHandlerProvider() {",
- " Object local = provideAdminHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(1);",
- " provideAdminHandlerProvider = (Provider<Handler>) local;",
- " }",
- " return (Provider<Handler>) local;",
- " }",
- "",
- " private Provider<Handler> provideLoginHandlerProvider() {",
- " Object local = provideLoginHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(2);",
- " provideLoginHandlerProvider = (Provider<Handler>) local;",
- " }",
- " return (Provider<Handler>) local;",
- " }",
- "",
- " private Map<WrappedClassKey, Provider<Handler>>",
- " mapOfWrappedClassKeyAndProviderOfHandler() {",
- " return ImmutableMap.<WrappedClassKey, Provider<Handler>>of(",
- " WrappedClassKeyCreator.createWrappedClassKey(Integer.class),",
- " provideAdminHandlerProvider(),",
- " WrappedClassKeyCreator.createWrappedClassKey(Long.class),",
- " provideLoginHandlerProvider());",
- " }",
- "",
- " @Override",
- " public Provider<Map<WrappedClassKey, Provider<Handler>>> dispatcher() {",
- " Object local = mapOfWrappedClassKeyAndProviderOfHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " mapOfWrappedClassKeyAndProviderOfHandlerProvider =",
- " (Provider<Map<WrappedClassKey, Provider<Handler>>>) local;",
- " }",
- " return (Provider<Map<WrappedClassKey, Provider<Handler>>>) local;",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0:",
- " return (T) DaggerTestComponent.this",
- " .mapOfWrappedClassKeyAndProviderOfHandler();",
- " case 1:",
- " return (T) MapModuleOne_ProvideAdminHandlerFactory",
- " .provideAdminHandler(DaggerTestComponent.this.mapModuleOne);",
- " case 2:",
- " return (T) MapModuleTwo_ProvideLoginHandlerFactory",
- " .provideLoginHandler(DaggerTestComponent.this.mapModuleTwo);",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {",
- " private Provider<Handler> provideAdminHandlerProvider;",
- " private Provider<Handler> provideLoginHandlerProvider;",
- " private Provider<Map<WrappedClassKey, Provider<Handler>>>",
- " mapOfWrappedClassKeyAndProviderOfHandlerProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(",
- " final MapModuleOne mapModuleOneParam,",
- " final MapModuleTwo mapModuleTwoParam) {",
- " this.provideAdminHandlerProvider =",
- " MapModuleOne_ProvideAdminHandlerFactory.create(mapModuleOneParam);",
- " this.provideLoginHandlerProvider =",
- " MapModuleTwo_ProvideLoginHandlerFactory.create(mapModuleTwoParam);",
- " this.mapOfWrappedClassKeyAndProviderOfHandlerProvider =",
- " MapProviderFactory.<WrappedClassKey, Handler>builder(2)",
- " .put(WrappedClassKeyCreator.createWrappedClassKey(Integer.class),",
- " provideAdminHandlerProvider)",
- " .put(WrappedClassKeyCreator.createWrappedClassKey(Long.class),",
- " provideLoginHandlerProvider)",
- " .build();",
- " }",
- "",
- " @Override",
- " public Provider<Map<WrappedClassKey, Provider<Handler>>> dispatcher() {",
- " return mapOfWrappedClassKeyAndProviderOfHandlerProvider;",
- " }",
- "}");
- }
+
Compilation compilation =
compilerWithOptions(compilerMode.javacopts())
.compile(
mapModuleOneFile,
mapModuleTwoFile,
wrappedClassKeyFile,
- HandlerFile,
- LoginHandlerFile,
- AdminHandlerFile,
+ handlerFile,
+ loginHandlerFile,
+ adminHandlerFile,
componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
+ .containsElementsIn(
+ compilerMode
+ .javaFileBuilder("test.DaggerTestComponent")
+ .addLines(
+ "package test;",
+ "",
+ GeneratedLines.generatedAnnotations(),
+ "final class DaggerTestComponent implements TestComponent {",
+ " private final DaggerTestComponent testComponent = this;",
+ " private Provider<Handler> provideAdminHandlerProvider;",
+ " private Provider<Handler> provideLoginHandlerProvider;",
+ " private Provider<Map<WrappedClassKey, Provider<Handler>>>",
+ " mapOfWrappedClassKeyAndProviderOfHandlerProvider;")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(",
+ " final MapModuleOne mapModuleOneParam,",
+ " final MapModuleTwo mapModuleTwoParam) {",
+ " this.provideAdminHandlerProvider =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(mapModuleOneParam);",
+ " this.provideLoginHandlerProvider =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(mapModuleTwoParam);",
+ " this.mapOfWrappedClassKeyAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<WrappedClassKey, Handler>builder(2)",
+ " .put(WrappedClassKeyCreator.createWrappedClassKey(Integer.class),",
+ " provideAdminHandlerProvider)",
+ " .put(WrappedClassKeyCreator.createWrappedClassKey(Long.class),",
+ " provideLoginHandlerProvider)",
+ " .build();",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final MapModuleOne mapModuleOneParam,",
+ " final MapModuleTwo mapModuleTwoParam) {",
+ " this.provideAdminHandlerProvider =",
+ " new SwitchingProvider<>(testComponent, 1);",
+ " this.provideLoginHandlerProvider =",
+ " new SwitchingProvider<>(testComponent, 2);",
+ " this.mapOfWrappedClassKeyAndProviderOfHandlerProvider =",
+ " new SwitchingProvider<>(testComponent, 0);",
+ " }")
+ .addLines(
+ " @Override",
+ " public Provider<Map<WrappedClassKey, Provider<Handler>>> dispatcher() {",
+ " return mapOfWrappedClassKeyAndProviderOfHandlerProvider;",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0:",
+ " return (T) ImmutableMap.<WrappedClassKey, Provider<Handler>>of(",
+ " WrappedClassKeyCreator.createWrappedClassKey(Integer.class),",
+ " testComponent.provideAdminHandlerProvider,",
+ " WrappedClassKeyCreator.createWrappedClassKey(Long.class),",
+ " testComponent.provideLoginHandlerProvider);",
+ " case 1: return (T) MapModuleOne_ProvideAdminHandlerFactory",
+ " .provideAdminHandler(testComponent.mapModuleOne);",
+ " case 2: return (T) MapModuleTwo_ProvideLoginHandlerFactory",
+ " .provideLoginHandler(testComponent.mapModuleTwo);",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
+ " }",
+ "}")
+ .build());
}
@Test
@@ -913,22 +780,24 @@ public class MapBindingComponentProcessorTest {
" ADMIN,",
" LOGIN;",
"}");
- JavaFileObject HandlerFile = JavaFileObjects.forSourceLines("test.Handler",
- "package test;",
- "",
- "interface Handler {}");
- JavaFileObject LoginHandlerFile = JavaFileObjects.forSourceLines("test.LoginHandler",
- "package test;",
- "",
- "class LoginHandler implements Handler {",
- " public LoginHandler() {}",
- "}");
- JavaFileObject AdminHandlerFile = JavaFileObjects.forSourceLines("test.AdminHandler",
- "package test;",
- "",
- "class AdminHandler implements Handler {",
- " public AdminHandler() {}",
- "}");
+ JavaFileObject handlerFile =
+ JavaFileObjects.forSourceLines("test.Handler", "package test;", "", "interface Handler {}");
+ JavaFileObject loginHandlerFile =
+ JavaFileObjects.forSourceLines(
+ "test.LoginHandler",
+ "package test;",
+ "",
+ "class LoginHandler implements Handler {",
+ " public LoginHandler() {}",
+ "}");
+ JavaFileObject adminHandlerFile =
+ JavaFileObjects.forSourceLines(
+ "test.AdminHandler",
+ "package test;",
+ "",
+ "class AdminHandler implements Handler {",
+ " public AdminHandler() {}",
+ "}");
JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
"package test;",
"",
@@ -940,92 +809,7 @@ public class MapBindingComponentProcessorTest {
"interface TestComponent {",
" Provider<Map<PathEnum, Handler>> dispatcher();",
"}");
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {",
- " private final MapModuleOne mapModuleOne;",
- " private final MapModuleTwo mapModuleTwo;",
- " private volatile Provider<Map<PathEnum, Handler>>",
- " mapOfPathEnumAndHandlerProvider;",
- "",
- " private Map<PathEnum, Handler> mapOfPathEnumAndHandler() {",
- " return ImmutableMap.<PathEnum, Handler>of(",
- " PathEnum.ADMIN,",
- " MapModuleOne_ProvideAdminHandlerFactory.provideAdminHandler(",
- " mapModuleOne),",
- " PathEnum.LOGIN,",
- " MapModuleTwo_ProvideLoginHandlerFactory.provideLoginHandler(",
- " mapModuleTwo));",
- " }",
- "",
- " @Override",
- " public Provider<Map<PathEnum, Handler>> dispatcher() {",
- " Object local = mapOfPathEnumAndHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " mapOfPathEnumAndHandlerProvider = (Provider<Map<PathEnum, Handler>>) local;",
- " }",
- " return (Provider<Map<PathEnum, Handler>>) local;",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0: return (T) DaggerTestComponent.this.mapOfPathEnumAndHandler();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {",
- " private Provider<Handler> provideAdminHandlerProvider;",
- " private Provider<Handler> provideLoginHandlerProvider;",
- " private Provider<Map<PathEnum, Handler>> mapOfPathEnumAndHandlerProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(",
- " final MapModuleOne mapModuleOneParam,",
- " final MapModuleTwo mapModuleTwoParam) {",
- " this.provideAdminHandlerProvider =",
- " MapModuleOne_ProvideAdminHandlerFactory.create(mapModuleOneParam);",
- " this.provideLoginHandlerProvider =",
- " MapModuleTwo_ProvideLoginHandlerFactory.create(mapModuleTwoParam);",
- " this.mapOfPathEnumAndHandlerProvider =",
- " MapFactory.<PathEnum, Handler>builder(2)",
- " .put(PathEnum.ADMIN, provideAdminHandlerProvider)",
- " .put(PathEnum.LOGIN, provideLoginHandlerProvider)",
- " .build();",
- " }",
- "",
- " @Override",
- " public Provider<Map<PathEnum, Handler>> dispatcher() {",
- " return mapOfPathEnumAndHandlerProvider;",
- " }",
- "}");
- }
+
Compilation compilation =
compilerWithOptions(compilerMode.javacopts())
.compile(
@@ -1033,14 +817,76 @@ public class MapBindingComponentProcessorTest {
mapModuleTwoFile,
enumKeyFile,
pathEnumFile,
- HandlerFile,
- LoginHandlerFile,
- AdminHandlerFile,
+ handlerFile,
+ loginHandlerFile,
+ adminHandlerFile,
componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
+ .containsElementsIn(
+ compilerMode
+ .javaFileBuilder("test.DaggerTestComponent")
+ .addLines(
+ "package test;",
+ "",
+ GeneratedLines.generatedAnnotations(),
+ "final class DaggerTestComponent implements TestComponent {")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " private Provider<Handler> provideAdminHandlerProvider;",
+ " private Provider<Handler> provideLoginHandlerProvider;",
+ " private Provider<Map<PathEnum, Handler>> mapOfPathEnumAndHandlerProvider;",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(",
+ " final MapModuleOne mapModuleOneParam,",
+ " final MapModuleTwo mapModuleTwoParam) {",
+ " this.provideAdminHandlerProvider =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(mapModuleOneParam);",
+ " this.provideLoginHandlerProvider =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(mapModuleTwoParam);",
+ " this.mapOfPathEnumAndHandlerProvider =",
+ " MapFactory.<PathEnum, Handler>builder(2)",
+ " .put(PathEnum.ADMIN, provideAdminHandlerProvider)",
+ " .put(PathEnum.LOGIN, provideLoginHandlerProvider)",
+ " .build();",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " private Provider<Map<PathEnum, Handler>> mapOfPathEnumAndHandlerProvider;",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final MapModuleOne mapModuleOneParam,",
+ " final MapModuleTwo mapModuleTwoParam) {",
+ " this.mapOfPathEnumAndHandlerProvider =",
+ " new SwitchingProvider<>(testComponent, 0);",
+ " }")
+ .addLines(
+ " @Override",
+ " public Provider<Map<PathEnum, Handler>> dispatcher() {",
+ " return mapOfPathEnumAndHandlerProvider;",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0: return (T) ImmutableMap.<PathEnum, Handler>of(",
+ " PathEnum.ADMIN,",
+ " MapModuleOne_ProvideAdminHandlerFactory.provideAdminHandler(",
+ " testComponent.mapModuleOne),",
+ " PathEnum.LOGIN,",
+ " MapModuleTwo_ProvideLoginHandlerFactory.provideLoginHandler(",
+ " testComponent.mapModuleTwo));",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
+ " }",
+ "}")
+ .build());
}
@Test
diff --git a/javatests/dagger/internal/codegen/MapBindingExpressionTest.java b/javatests/dagger/internal/codegen/MapRequestRepresentationTest.java
index 9acc20d5a..1f59bd8de 100644
--- a/javatests/dagger/internal/codegen/MapBindingExpressionTest.java
+++ b/javatests/dagger/internal/codegen/MapRequestRepresentationTest.java
@@ -33,7 +33,7 @@ import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class MapBindingExpressionTest {
+public class MapRequestRepresentationTest {
@Parameters(name = "{0}")
public static Collection<Object[]> parameters() {
return CompilerMode.TEST_PARAMETERS;
@@ -41,7 +41,7 @@ public class MapBindingExpressionTest {
private final CompilerMode compilerMode;
- public MapBindingExpressionTest(CompilerMode compilerMode) {
+ public MapRequestRepresentationTest(CompilerMode compilerMode) {
this.compilerMode = compilerMode;
}
@@ -89,51 +89,21 @@ public class MapBindingExpressionTest {
.addLines(
"package test;",
"",
- "import dagger.internal.MapBuilder;",
- "",
GeneratedLines.generatedAnnotations(),
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
FAST_INIT_MODE,
- " private volatile Provider<Integer> provideIntProvider;",
- " private volatile Provider<Long> provideLong0Provider;",
- " private volatile Provider<Long> provideLong1Provider;",
- " private volatile Provider<Long> provideLong2Provider;",
- "",
- " private Provider<Integer> provideIntProvider() {",
- " Object local = provideIntProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " provideIntProvider = (Provider<Integer>) local;",
- " }",
- " return (Provider<Integer>) local;",
- " }",
- "",
- " private Provider<Long> provideLong0Provider() {",
- " Object local = provideLong0Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(1);",
- " provideLong0Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
- " }",
- "",
- " private Provider<Long> provideLong1Provider() {",
- " Object local = provideLong1Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(2);",
- " provideLong1Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
- " }",
+ " private Provider<Integer> provideIntProvider;",
+ " private Provider<Long> provideLong0Provider;",
+ " private Provider<Long> provideLong1Provider;",
+ " private Provider<Long> provideLong2Provider;",
"",
- " private Provider<Long> provideLong2Provider() {",
- " Object local = provideLong2Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(3);",
- " provideLong2Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.provideIntProvider = new SwitchingProvider<>(testComponent, 0);",
+ " this.provideLong0Provider = new SwitchingProvider<>(testComponent, 1);",
+ " this.provideLong1Provider = new SwitchingProvider<>(testComponent, 2);",
+ " this.provideLong2Provider = new SwitchingProvider<>(testComponent, 3);",
" }")
.addLines(
" @Override",
@@ -145,22 +115,31 @@ public class MapBindingExpressionTest {
" public Map<String, Provider<String>> providerStrings() {",
" return Collections.<String, Provider<String>>emptyMap();",
" }",
- "",
+ "")
+ .addLinesIn(
+ DEFAULT_MODE,
" @Override",
" public Map<Integer, Integer> ints() {",
- " return Collections.<Integer, Integer>singletonMap(0, MapModule.provideInt());",
- " }",
- "",
+ " return Collections.<Integer, Integer>",
+ " singletonMap(0, MapModule.provideInt());",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @Override",
+ " public Map<Integer, Integer> ints() {",
+ " return Collections.<Integer, Integer>singletonMap(0,"
+ + " provideIntProvider.get());",
+ " }")
+ .addLines(
" @Override",
" public Map<Integer, Provider<Integer>> providerInts() {",
" return Collections.<Integer, Provider<Integer>>singletonMap(")
.addLinesIn(
DEFAULT_MODE, //
" 0, MapModule_ProvideIntFactory.create());")
+ .addLinesIn(FAST_INIT_MODE, " 0, provideIntProvider;")
.addLinesIn(
- FAST_INIT_MODE,
- " 0, provideIntProvider());")
- .addLines(
+ DEFAULT_MODE,
" }",
"",
" @Override",
@@ -170,9 +149,21 @@ public class MapBindingExpressionTest {
" .put(1L, MapModule.provideLong1())",
" .put(2L, MapModule.provideLong2())",
" .build();",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
" }",
"",
" @Override",
+ " public Map<Long, Long> longs() {",
+ " return MapBuilder.<Long, Long>newMapBuilder(3)",
+ " .put(0L, provideLong0Provider.get())",
+ " .put(1L, provideLong1Provider.get())",
+ " .put(2L, provideLong2Provider.get())",
+ " .build();",
+ " }")
+ .addLines(
+ " @Override",
" public Map<Long, Provider<Long>> providerLongs() {",
" return MapBuilder.<Long, Provider<Long>>newMapBuilder(3)")
.addLinesIn(
@@ -182,20 +173,14 @@ public class MapBindingExpressionTest {
" .put(2L, MapModule_ProvideLong2Factory.create())")
.addLinesIn(
FAST_INIT_MODE,
- " .put(0L, provideLong0Provider())",
- " .put(1L, provideLong1Provider())",
- " .put(2L, provideLong2Provider())")
+ " .put(0L, provideLong0Provider)",
+ " .put(1L, provideLong1Provider)",
+ " .put(2L, provideLong2Provider)")
.addLines( //
" .build();", " }")
.addLinesIn(
FAST_INIT_MODE,
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
@@ -340,13 +325,12 @@ public class MapBindingExpressionTest {
"final class DaggerParent implements Parent {",
" private final ParentModule parentModule;",
"",
- " private final class ChildImpl implements Child {",
+ " private static final class ChildImpl implements Child {",
" @Override",
" public Map<String, Object> objectMap() {",
" return Collections.<String, Object>singletonMap(",
" \"parent key\",",
- " ParentModule_ParentKeyObjectFactory.parentKeyObject(",
- " DaggerParent.this.parentModule));",
+ " ParentModule_ParentKeyObjectFactory.parentKeyObject(parent.parentModule));",
" }",
" }",
"}");
diff --git a/javatests/dagger/internal/codegen/MapBindingExpressionWithGuavaTest.java b/javatests/dagger/internal/codegen/MapRequestRepresentationWithGuavaTest.java
index 30b05190a..db7d039f8 100644
--- a/javatests/dagger/internal/codegen/MapBindingExpressionWithGuavaTest.java
+++ b/javatests/dagger/internal/codegen/MapRequestRepresentationWithGuavaTest.java
@@ -31,7 +31,7 @@ import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class MapBindingExpressionWithGuavaTest {
+public class MapRequestRepresentationWithGuavaTest {
@Parameters(name = "{0}")
public static Collection<Object[]> parameters() {
return CompilerMode.TEST_PARAMETERS;
@@ -39,7 +39,7 @@ public class MapBindingExpressionWithGuavaTest {
private final CompilerMode compilerMode;
- public MapBindingExpressionWithGuavaTest(CompilerMode compilerMode) {
+ public MapRequestRepresentationWithGuavaTest(CompilerMode compilerMode) {
this.compilerMode = compilerMode;
}
@@ -130,45 +130,17 @@ public class MapBindingExpressionWithGuavaTest {
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
FAST_INIT_MODE,
- " private volatile Provider<Integer> provideIntProvider;",
- " private volatile Provider<Long> provideLong0Provider;",
- " private volatile Provider<Long> provideLong1Provider;",
- " private volatile Provider<Long> provideLong2Provider;",
+ " private Provider<Integer> provideIntProvider;",
+ " private Provider<Long> provideLong0Provider;",
+ " private Provider<Long> provideLong1Provider;",
+ " private Provider<Long> provideLong2Provider;",
"",
- " private Provider<Integer> provideIntProvider() {",
- " Object local = provideIntProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " provideIntProvider = (Provider<Integer>) local;",
- " }",
- " return (Provider<Integer>) local;",
- " }",
- "",
- " private Provider<Long> provideLong0Provider() {",
- " Object local = provideLong0Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(1);",
- " provideLong0Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
- " }",
- "",
- " private Provider<Long> provideLong1Provider() {",
- " Object local = provideLong1Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(2);",
- " provideLong1Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
- " }",
- "",
- " private Provider<Long> provideLong2Provider() {",
- " Object local = provideLong2Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(3);",
- " provideLong2Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.provideIntProvider = new SwitchingProvider<>(testComponent, 0);",
+ " this.provideLong0Provider = new SwitchingProvider<>(testComponent, 1);",
+ " this.provideLong1Provider = new SwitchingProvider<>(testComponent, 2);",
+ " this.provideLong2Provider = new SwitchingProvider<>(testComponent, 3);",
" }")
.addLines(
" @Override",
@@ -179,89 +151,92 @@ public class MapBindingExpressionWithGuavaTest {
" @Override",
" public Map<String, Provider<String>> providerStrings() {",
" return ImmutableMap.<String, Provider<String>>of();",
- " }",
- "",
+ " }")
+ .addLinesIn(
+ DEFAULT_MODE,
" @Override",
" public Map<Integer, Integer> ints() {",
" return ImmutableMap.<Integer, Integer>of(0, MapModule.provideInt());",
- " }",
- "",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @Override",
+ " public Map<Integer, Integer> ints() {",
+ " return ImmutableMap.<Integer, Integer>of(0, provideIntProvider.get());",
+ " }")
+ .addLinesIn(
+ DEFAULT_MODE,
" @Override",
" public Map<Integer, Provider<Integer>> providerInts() {",
- " return ImmutableMap.<Integer, Provider<Integer>>of(")
+ " return ImmutableMap.<Integer, Provider<Integer>>of(",
+ " 0, MapModule_ProvideIntFactory.create());",
+ " }")
.addLinesIn(
- DEFAULT_MODE, //
- " 0, MapModule_ProvideIntFactory.create());")
+ FAST_INIT_MODE,
+ " @Override",
+ " public Map<Integer, Provider<Integer>> providerInts() {",
+ " return ImmutableMap.<Integer, Provider<Integer>>of(0, provideIntProvider);",
+ " }")
.addLinesIn(
- FAST_INIT_MODE, //
- " 0, provideIntProvider());")
- .addLines(
- " }",
- "",
+ DEFAULT_MODE,
" @Override",
" public Map<Long, Long> longs() {",
" return ImmutableMap.<Long, Long>of(",
" 0L, MapModule.provideLong0(),",
" 1L, MapModule.provideLong1(),",
" 2L, MapModule.provideLong2());",
- " }",
- "",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
" @Override",
- " public Map<Long, Provider<Long>> providerLongs() {",
- " return ImmutableMap.<Long, Provider<Long>>of(")
+ " public Map<Long, Long> longs() {",
+ " return ImmutableMap.<Long, Long>of(",
+ " 0L, provideLong0Provider.get(),",
+ " 1L, provideLong1Provider.get(),",
+ " 2L, provideLong2Provider.get());",
+ " }")
.addLinesIn(
DEFAULT_MODE,
+ " @Override",
+ " public Map<Long, Provider<Long>> providerLongs() {",
+ " return ImmutableMap.<Long, Provider<Long>>of(",
" 0L, MapModule_ProvideLong0Factory.create(),",
" 1L, MapModule_ProvideLong1Factory.create(),",
- " 2L, MapModule_ProvideLong2Factory.create());")
+ " 2L, MapModule_ProvideLong2Factory.create());",
+ " }")
.addLinesIn(
FAST_INIT_MODE,
- " 0L, provideLong0Provider(),",
- " 1L, provideLong1Provider(),",
- " 2L, provideLong2Provider());")
+ " @Override",
+ " public Map<Long, Provider<Long>> providerLongs() {",
+ " return ImmutableMap.<Long, Provider<Long>>of(",
+ " 0L, provideLong0Provider,",
+ " 1L, provideLong1Provider,",
+ " 2L, provideLong2Provider);",
+ " }")
.addLines(
- " }",
- "",
" @Override",
" public Sub sub() {",
- " return new SubImpl();",
+ " return new SubImpl(testComponent);",
" }",
"",
- " private final class SubImpl implements Sub {")
+ " private static final class SubImpl implements Sub {")
.addLinesIn(
FAST_INIT_MODE,
- " private volatile Provider<Long> provideLong3Provider;",
- " private volatile Provider<Long> provideLong4Provider;",
- " private volatile Provider<Long> provideLong5Provider;",
- " private SubImpl() {}",
- "",
- " private Provider<Long> provideLong3Provider() {",
- " Object local = provideLong3Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " provideLong3Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
- " }",
+ " private Provider<Long> provideLong3Provider;",
+ " private Provider<Long> provideLong4Provider;",
+ " private Provider<Long> provideLong5Provider;",
"",
- " private Provider<Long> provideLong4Provider() {",
- " Object local = provideLong4Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(1);",
- " provideLong4Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
- " }",
- "",
- " private Provider<Long> provideLong5Provider() {",
- " Object local = provideLong5Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(2);",
- " provideLong5Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.provideLong3Provider =",
+ " new SwitchingProvider<>(testComponent, subImpl, 0);",
+ " this.provideLong4Provider =",
+ " new SwitchingProvider<>(testComponent, subImpl, 1);",
+ " this.provideLong5Provider =",
+ " new SwitchingProvider<>(testComponent, subImpl, 2);",
" }")
- .addLines(
+ .addLinesIn(
+ DEFAULT_MODE,
" @Override",
" public Map<Long, Long> longs() {",
" return ImmutableMap.<Long, Long>builderWithExpectedSize(6)",
@@ -272,38 +247,49 @@ public class MapBindingExpressionWithGuavaTest {
" .put(4L, SubcomponentMapModule.provideLong4())",
" .put(5L, SubcomponentMapModule.provideLong5())",
" .build();",
- " }",
- "",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
" @Override",
- " public Map<Long, Provider<Long>> providerLongs() {",
- " return ImmutableMap.<Long, Provider<Long>>builderWithExpectedSize(6)")
+ " public Map<Long, Long> longs() {",
+ " return ImmutableMap.<Long, Long>builderWithExpectedSize(6)",
+ " .put(0L, testComponent.provideLong0Provider.get())",
+ " .put(1L, testComponent.provideLong1Provider.get())",
+ " .put(2L, testComponent.provideLong2Provider.get())",
+ " .put(3L, provideLong3Provider.get())",
+ " .put(4L, provideLong4Provider.get())",
+ " .put(5L, provideLong5Provider.get())",
+ " .build();",
+ " }")
.addLinesIn(
DEFAULT_MODE,
+ " @Override",
+ " public Map<Long, Provider<Long>> providerLongs() {",
+ " return ImmutableMap.<Long, Provider<Long>>builderWithExpectedSize(6)",
" .put(0L, MapModule_ProvideLong0Factory.create())",
" .put(1L, MapModule_ProvideLong1Factory.create())",
" .put(2L, MapModule_ProvideLong2Factory.create())",
" .put(3L, SubcomponentMapModule_ProvideLong3Factory.create())",
" .put(4L, SubcomponentMapModule_ProvideLong4Factory.create())",
- " .put(5L, SubcomponentMapModule_ProvideLong5Factory.create())")
+ " .put(5L, SubcomponentMapModule_ProvideLong5Factory.create())",
+ " .build();",
+ " }")
.addLinesIn(
FAST_INIT_MODE,
- " .put(0L, DaggerTestComponent.this.provideLong0Provider())",
- " .put(1L, DaggerTestComponent.this.provideLong1Provider())",
- " .put(2L, DaggerTestComponent.this.provideLong2Provider())",
- " .put(3L, provideLong3Provider())",
- " .put(4L, provideLong4Provider())",
- " .put(5L, provideLong5Provider())")
- .addLines( //
- " .build();", " }")
+ " @Override",
+ " public Map<Long, Provider<Long>> providerLongs() {",
+ " return ImmutableMap.<Long, Provider<Long>>builderWithExpectedSize(6)",
+ " .put(0L, testComponent.provideLong0Provider)",
+ " .put(1L, testComponent.provideLong1Provider)",
+ " .put(2L, testComponent.provideLong2Provider)",
+ " .put(3L, provideLong3Provider)",
+ " .put(4L, provideLong4Provider)",
+ " .put(5L, provideLong5Provider)",
+ " .build();",
+ " }")
.addLinesIn(
FAST_INIT_MODE,
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
@@ -317,13 +303,7 @@ public class MapBindingExpressionWithGuavaTest {
" }",
" }",
"",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
@@ -466,13 +446,12 @@ public class MapBindingExpressionWithGuavaTest {
"final class DaggerParent implements Parent {",
" private final ParentModule parentModule;",
"",
- " private final class ChildImpl implements Child {",
+ " private static final class ChildImpl implements Child {",
" @Override",
" public Map<String, Object> objectMap() {",
" return ImmutableMap.<String, Object>of(",
" \"parent key\",",
- " ParentModule_ParentKeyObjectFactory.parentKeyObject(",
- " DaggerParent.this.parentModule));",
+ " ParentModule_ParentKeyObjectFactory.parentKeyObject(parent.parentModule));",
" }",
" }",
"}");
diff --git a/javatests/dagger/internal/codegen/MembersInjectionTest.java b/javatests/dagger/internal/codegen/MembersInjectionTest.java
index c44277922..ca22d563a 100644
--- a/javatests/dagger/internal/codegen/MembersInjectionTest.java
+++ b/javatests/dagger/internal/codegen/MembersInjectionTest.java
@@ -189,8 +189,10 @@ public class MembersInjectionTest {
GeneratedLines.generatedImports(
"import dagger.MembersInjector;",
"import dagger.internal.InjectedFieldSignature;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class GenericClass_MembersInjector<A, B>",
" implements MembersInjector<GenericClass<A, B>> {",
@@ -279,8 +281,10 @@ public class MembersInjectionTest {
GeneratedLines.generatedImports(
"import dagger.MembersInjector;",
"import dagger.internal.InjectedFieldSignature;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class Child_MembersInjector<T>",
" implements MembersInjector<Child<T>> {",
@@ -364,8 +368,10 @@ public class MembersInjectionTest {
"import dagger.MembersInjector;",
"import dagger.internal.DoubleCheck;",
"import dagger.internal.InjectedFieldSignature;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class FieldInjection_MembersInjector",
" implements MembersInjector<FieldInjection> {",
@@ -444,9 +450,11 @@ public class MembersInjectionTest {
GeneratedLines.generatedImports(
"import dagger.MembersInjector;",
"import dagger.internal.InjectedFieldSignature;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Named;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata(\"javax.inject.Named\")",
GeneratedLines.generatedAnnotations(),
"public final class FieldInjectionWithQualifier_MembersInjector",
" implements MembersInjector<FieldInjectionWithQualifier> {",
@@ -514,8 +522,10 @@ public class MembersInjectionTest {
"import dagger.Lazy;",
"import dagger.MembersInjector;",
"import dagger.internal.DoubleCheck;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class MethodInjection_MembersInjector",
" implements MembersInjector<MethodInjection> {",
@@ -603,8 +613,10 @@ public class MembersInjectionTest {
GeneratedLines.generatedImports(
"import dagger.MembersInjector;",
"import dagger.internal.InjectedFieldSignature;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class MixedMemberInjection_MembersInjector",
" implements MembersInjector<MixedMemberInjection> {",
@@ -686,8 +698,10 @@ public class MembersInjectionTest {
GeneratedLines.generatedImports(
"import dagger.MembersInjector;",
"import dagger.internal.InjectedFieldSignature;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class AllInjections_MembersInjector ",
" implements MembersInjector<AllInjections> {",
@@ -747,14 +761,16 @@ public class MembersInjectionTest {
"}");
JavaFileObject expectedMembersInjector =
JavaFileObjects.forSourceLines(
- "test.AllInjections_MembersInjector",
+ "test.B_MembersInjector",
"package test;",
"",
GeneratedLines.generatedImports(
"import dagger.MembersInjector;",
"import dagger.internal.InjectedFieldSignature;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class B_MembersInjector implements MembersInjector<B> {",
" private final Provider<String> sProvider;",
@@ -815,8 +831,10 @@ public class MembersInjectionTest {
GeneratedLines.generatedImports(
"import dagger.MembersInjector;",
"import dagger.internal.InjectedFieldSignature;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class OuterType_B_MembersInjector",
" implements MembersInjector<OuterType.B> {",
@@ -881,8 +899,10 @@ public class MembersInjectionTest {
GeneratedLines.generatedImports(
"import dagger.MembersInjector;",
"import dagger.internal.InjectedFieldSignature;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class OuterType_B_MembersInjector",
" implements MembersInjector<OuterType.B> {",
@@ -1057,8 +1077,10 @@ public class MembersInjectionTest {
GeneratedLines.generatedImports(
"import dagger.MembersInjector;",
"import dagger.internal.InjectedFieldSignature;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class Child_MembersInjector implements MembersInjector<Child> {",
" private final Provider<Foo> objectProvider;",
@@ -1255,8 +1277,10 @@ public class MembersInjectionTest {
GeneratedLines.generatedImports(
"import dagger.MembersInjector;",
"import dagger.internal.InjectedFieldSignature;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class InjectedType_MembersInjector ",
" implements MembersInjector<InjectedType> {",
@@ -1296,8 +1320,12 @@ public class MembersInjectionTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class InjectedType_Factory implements Factory<InjectedType> {",
" private final Provider<Integer> primitiveIntProvider;",
@@ -1400,8 +1428,10 @@ public class MembersInjectionTest {
GeneratedLines.generatedImports(
"import dagger.MembersInjector;",
"import dagger.internal.InjectedFieldSignature;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class Inaccessible_MembersInjector",
" implements MembersInjector<Inaccessible> {",
@@ -1537,65 +1567,52 @@ public class MembersInjectionTest {
.addLines(
"package test;",
"",
- GeneratedLines.generatedImports(
- "import com.google.errorprone.annotations.CanIgnoreReturnValue;",
- "import other.InaccessiblesModule;",
- "import other.InaccessiblesModule_InaccessiblesFactory;",
- "import other.UsesInaccessibles;",
- "import other.UsesInaccessibles_Factory;",
- "import other.UsesInaccessibles_MembersInjector;"),
- "",
GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent {")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Object listOfInaccessible = new MemoizedSentinel();",
+ "final class DaggerTestComponent implements TestComponent {",
+ " private final DaggerTestComponent testComponent = this;",
"",
- " private List listOfInaccessible() {",
- " Object local = listOfInaccessible;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = listOfInaccessible;",
- " if (local instanceof MemoizedSentinel) {",
- " local = InaccessiblesModule_InaccessiblesFactory.inaccessibles();",
- " listOfInaccessible =",
- " DoubleCheck.reentrantCheck(listOfInaccessible, local);",
- " }",
- " }",
- " }",
- " return (List) local;",
- " }")
+ " @SuppressWarnings(\"rawtypes\")",
+ " private Provider inaccessiblesProvider;")
.addLinesIn(
DEFAULT_MODE,
- " @SuppressWarnings(\"rawtypes\")",
- " private Provider inaccessiblesProvider;",
- "",
" @SuppressWarnings(\"unchecked\")",
" private void initialize() {",
" this.inaccessiblesProvider =",
" DoubleCheck.provider(InaccessiblesModule_InaccessiblesFactory.create());",
" }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.inaccessiblesProvider =",
+ " DoubleCheck.provider(",
+ " new SwitchingProvider<List>(testComponent, 0));",
+ " }")
.addLines(
- "",
" @Override",
" public UsesInaccessibles usesInaccessibles() {",
- " return injectUsesInaccessibles(",
- " UsesInaccessibles_Factory.newInstance());",
- " }",
- "",
- " @CanIgnoreReturnValue",
- " private UsesInaccessibles injectUsesInaccessibles(",
- " UsesInaccessibles instance) {",
- " UsesInaccessibles_MembersInjector.injectInaccessibles(")
+ " return injectUsesInaccessibles(UsesInaccessibles_Factory.newInstance());",
+ " }")
.addLinesIn(
FAST_INIT_MODE,
- " instance, (List) listOfInaccessible());")
- .addLinesIn(
- DEFAULT_MODE,
- " instance, (List) inaccessiblesProvider.get());")
- .addLines(
+ " @CanIgnoreReturnValue",
+ " private UsesInaccessibles injectUsesInaccessibles(UsesInaccessibles instance) {",
+ " UsesInaccessibles_MembersInjector",
+ " .injectInaccessibles(instance, (List) inaccessiblesProvider.get());",
" return instance;",
" }",
+ "",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0:",
+ " return (T) InaccessiblesModule_InaccessiblesFactory.inaccessibles();",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
+ " }",
"}")
.build();
assertThat(compilation)
@@ -1738,8 +1755,10 @@ public class MembersInjectionTest {
GeneratedLines.generatedImports(
"import dagger.MembersInjector;",
"import dagger.internal.InjectedFieldSignature;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class A_MembersInjector implements MembersInjector<A> {",
" private final Provider<String> valueCProvider;",
@@ -1776,8 +1795,10 @@ public class MembersInjectionTest {
GeneratedLines.generatedImports(
"import dagger.MembersInjector;",
"import dagger.internal.InjectedFieldSignature;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class C_MembersInjector implements MembersInjector<C> {",
" private final Provider<String> valueCProvider;",
@@ -1855,8 +1876,10 @@ public class MembersInjectionTest {
"",
GeneratedLines.generatedImports(
"import dagger.MembersInjector;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class A_MembersInjector implements MembersInjector<A> {",
" private final Provider<String> valueBProvider;",
@@ -1883,8 +1906,10 @@ public class MembersInjectionTest {
GeneratedLines.generatedImports(
"import dagger.MembersInjector;",
"import dagger.internal.InjectedFieldSignature;",
+ "import dagger.internal.QualifierMetadata;",
"import javax.inject.Provider;"),
"",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class B_MembersInjector implements MembersInjector<B> {",
" private final Provider<String> valueBProvider;",
@@ -1921,4 +1946,223 @@ public class MembersInjectionTest {
.generatedSourceFile("test.B_MembersInjector")
.hasSourceEquivalentTo(expectedBMembersInjector);
}
+
+ // Regression test for https://github.com/google/dagger/issues/3143
+ @Test
+ public void testMembersInjectionBindingExistsInParentComponent() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = MyComponentModule.class)",
+ "public interface MyComponent {",
+ " void inject(Bar bar);",
+ "",
+ " MySubcomponent subcomponent();",
+ "}");
+
+ JavaFileObject subcomponent =
+ JavaFileObjects.forSourceLines(
+ "test.MySubcomponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = MySubcomponentModule.class)",
+ "interface MySubcomponent {",
+ " Foo foo();",
+ "}");
+
+ JavaFileObject foo =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Foo {",
+ " @Inject Foo(Bar bar) {}",
+ "}");
+
+ JavaFileObject bar =
+ JavaFileObjects.forSourceLines(
+ "test.Bar",
+ "package test;",
+ "",
+ "import java.util.Set;",
+ "import javax.inject.Inject;",
+ "",
+ "class Bar {",
+ " @Inject Set<String> multibindingStrings;",
+ " @Inject Bar() {}",
+ "}");
+
+ JavaFileObject componentModule =
+ JavaFileObjects.forSourceLines(
+ "test.MyComponentModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "",
+ "@Module",
+ "interface MyComponentModule {",
+ " @Provides",
+ " @IntoSet",
+ " static String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+
+ JavaFileObject subcomponentModule =
+ JavaFileObjects.forSourceLines(
+ "test.MySubcomponentModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "",
+ "@Module",
+ "interface MySubcomponentModule {",
+ " @Provides",
+ " @IntoSet",
+ " static String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+
+ Compilation compilation =
+ compilerWithOptions(compilerMode.javacopts())
+ .compile(component, subcomponent, foo, bar, componentModule, subcomponentModule);
+ assertThat(compilation).succeeded();
+
+ // Check that the injectBar() method is not shared across components.
+ // We avoid sharing them in general because they may be different (e.g. in this case we inject
+ // multibindings that are different across components).
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerMyComponent")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.DaggerMyComponent",
+ "package test;",
+ "",
+ GeneratedLines.generatedAnnotations(),
+ "public final class DaggerMyComponent implements MyComponent {",
+ " private Set<String> setOfString() {",
+ " return ImmutableSet.<String>of(",
+ " MyComponentModule_ProvideStringFactory.provideString());",
+ " }",
+ "",
+ " @Override",
+ " public void inject(Bar bar) {",
+ " injectBar(bar);",
+ " }",
+ "",
+ " @CanIgnoreReturnValue",
+ " private Bar injectBar(Bar instance) {",
+ " Bar_MembersInjector.injectMultibindingStrings(instance, setOfString());",
+ " return instance;",
+ " }",
+ "",
+ " private static final class MySubcomponentImpl implements MySubcomponent {",
+ " private Set<String> setOfString() {",
+ " return ImmutableSet.<String>of(",
+ " MyComponentModule_ProvideStringFactory.provideString(),",
+ " MySubcomponentModule_ProvideStringFactory.provideString());",
+ " }",
+ "",
+ " private Bar bar() {",
+ " return injectBar(Bar_Factory.newInstance());",
+ " }",
+ "",
+ " @Override",
+ " public Foo foo() {",
+ " return new Foo(bar());",
+ " }",
+ "",
+ " @CanIgnoreReturnValue",
+ " private Bar injectBar(Bar instance) {",
+ " Bar_MembersInjector.injectMultibindingStrings(instance, setOfString());",
+ " return instance;",
+ " }",
+ " }",
+ "}"));
+ }
+
+ // Test that if both a MembersInjectionBinding and ProvisionBinding both exist in the same
+ // component they share the same inject methods rather than generating their own.
+ @Test
+ public void testMembersInjectionBindingSharesInjectMethodsWithProvisionBinding() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "public interface MyComponent {",
+ " Foo foo();",
+ "",
+ " void inject(Foo foo);",
+ "}");
+
+ JavaFileObject foo =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Foo {",
+ " @Inject Bar bar;",
+ " @Inject Foo() {}",
+ "}");
+
+ JavaFileObject bar =
+ JavaFileObjects.forSourceLines(
+ "test.Bar",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Bar {",
+ " @Inject Bar() {}",
+ "}");
+
+ Compilation compilation =
+ compilerWithOptions(compilerMode.javacopts()).compile(component, foo, bar);
+ assertThat(compilation).succeeded();
+
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerMyComponent")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.DaggerMyComponent",
+ "package test;",
+ "",
+ GeneratedLines.generatedAnnotations(),
+ "public final class DaggerMyComponent implements MyComponent {",
+ " @Override",
+ " public Foo foo() {",
+ " return injectFoo(Foo_Factory.newInstance());",
+ " }",
+ "",
+ " @Override",
+ " public void inject(Foo foo) {",
+ " injectFoo(foo);",
+ " }",
+ "",
+ " @CanIgnoreReturnValue",
+ " private Foo injectFoo(Foo instance) {",
+ " Foo_MembersInjector.injectBar(instance, new Bar());",
+ " return instance;",
+ " }",
+ "}"));
+ }
}
diff --git a/javatests/dagger/internal/codegen/MethodSignatureFormatterTest.java b/javatests/dagger/internal/codegen/MethodSignatureFormatterTest.java
deleted file mode 100644
index 6d2f98988..000000000
--- a/javatests/dagger/internal/codegen/MethodSignatureFormatterTest.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2014 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen;
-
-import static com.google.common.truth.Truth.assertThat;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.testing.compile.CompilationRule;
-import dagger.BindsInstance;
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.internal.codegen.MethodSignatureFormatterTest.OuterClass.InnerClass;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.binding.MethodSignatureFormatter;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class MethodSignatureFormatterTest {
- @Rule public CompilationRule compilationRule = new CompilationRule();
-
- @Inject DaggerElements elements;
- @Inject DaggerTypes types;
- @Inject InjectionAnnotations injectionAnnotations;
-
- static class OuterClass {
- @interface Foo {
- Class<?> bar();
- }
-
- static class InnerClass {
- @Foo(bar = String.class)
- @Singleton
- String foo(
- @SuppressWarnings("unused") int a,
- @SuppressWarnings("unused") ImmutableList<Boolean> blah) {
- return "foo";
- }
- }
- }
-
- @Before
- public void setUp() {
- DaggerMethodSignatureFormatterTest_TestComponent.factory().create(compilationRule).inject(this);
- }
-
- @Test public void methodSignatureTest() {
- TypeElement inner = elements.getTypeElement(InnerClass.class);
- ExecutableElement method = Iterables.getOnlyElement(methodsIn(inner.getEnclosedElements()));
- String formatted = new MethodSignatureFormatter(types, injectionAnnotations).format(method);
- // This is gross, but it turns out that annotation order is not guaranteed when getting
- // all the AnnotationMirrors from an Element, so I have to test this chopped-up to make it
- // less brittle.
- assertThat(formatted).contains("@Singleton");
- assertThat(formatted).doesNotContain("@javax.inject.Singleton"); // maybe more importantly
- assertThat(formatted)
- .contains("@dagger.internal.codegen.MethodSignatureFormatterTest.OuterClass.Foo"
- + "(bar=String.class)");
- assertThat(formatted).contains(" String "); // return type compressed
- assertThat(formatted).contains("int, ImmutableList<Boolean>)"); // parameters compressed.
- }
-
- @Singleton
- @Component(modules = TestModule.class)
- interface TestComponent {
- void inject(MethodSignatureFormatterTest test);
-
- @Component.Factory
- interface Factory {
- TestComponent create(@BindsInstance CompilationRule compilationRule);
- }
- }
-
- @Module
- static class TestModule {
- @Provides
- static DaggerElements elements(CompilationRule compilationRule) {
- return new DaggerElements(compilationRule.getElements(), compilationRule.getTypes());
- }
-
- @Provides
- static DaggerTypes types(CompilationRule compilationRule, DaggerElements elements) {
- return new DaggerTypes(compilationRule.getTypes(), elements);
- }
- }
-}
diff --git a/javatests/dagger/internal/codegen/MissingBindingSuggestionsTest.java b/javatests/dagger/internal/codegen/MissingBindingSuggestionsTest.java
index 3c066bab2..a5a72f7d3 100644
--- a/javatests/dagger/internal/codegen/MissingBindingSuggestionsTest.java
+++ b/javatests/dagger/internal/codegen/MissingBindingSuggestionsTest.java
@@ -96,8 +96,7 @@ public class MissingBindingSuggestionsTest {
daggerCompiler().compile(fooComponent, barComponent, topComponent, foo, bar, barModule);
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining("A binding with matching key exists in component: BarComponent");
+ assertThat(compilation).hadErrorContaining("A binding for Bar exists in BarComponent:");
}
@Test public void suggestsBindingInNestedSubcomponent() {
@@ -157,8 +156,7 @@ public class MissingBindingSuggestionsTest {
.compile(fooComponent, barComponent, bazComponent, topComponent, foo, baz, bazModule);
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining("A binding with matching key exists in component: BazComponent");
+ assertThat(compilation).hadErrorContaining("A binding for Baz exists in BazComponent:");
}
@Test
@@ -220,11 +218,11 @@ public class MissingBindingSuggestionsTest {
message(
"\033[1;31m[Dagger/MissingBinding]\033[0m Baz cannot be provided without an "
+ "@Inject constructor or an @Provides-annotated method.",
- "A binding with matching key exists in component: Child",
+ "A binding for Baz exists in Child:",
" Baz is injected at",
- " Bar(baz)",
+ " [Parent] Bar(baz)",
" Bar is requested at",
- " Parent.bar()",
+ " [Parent] Parent.bar()",
"The following other entry points also depend on it:",
" Parent.foo()",
" Child.foo() [Parent → Child]"))
@@ -303,11 +301,11 @@ public class MissingBindingSuggestionsTest {
message(
"\033[1;31m[Dagger/MissingBinding]\033[0m Baz cannot be provided without an "
+ "@Inject constructor or an @Provides-annotated method.",
- "A binding with matching key exists in component: Child2",
+ "A binding for Baz exists in Child2:",
" Baz is injected at",
- " Bar(baz)",
+ " [Parent] Bar(baz)",
" Bar is requested at",
- " Parent.bar()",
+ " [Parent] Parent.bar()",
"The following other entry points also depend on it:",
" Parent.foo()",
" Child1.foo() [Parent → Child1]",
diff --git a/javatests/dagger/internal/codegen/MissingBindingValidationTest.java b/javatests/dagger/internal/codegen/MissingBindingValidationTest.java
index 1aabd4899..887ffa4b6 100644
--- a/javatests/dagger/internal/codegen/MissingBindingValidationTest.java
+++ b/javatests/dagger/internal/codegen/MissingBindingValidationTest.java
@@ -538,7 +538,7 @@ public class MissingBindingValidationTest {
assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContainingMatch(
- "(?s)\\QString cannot be provided\\E.*\\QChild.needsString()\\E")
+ "(?s)\\QString cannot be provided\\E.*\\Q[Child] Child.needsString()\\E")
.inFile(parent)
.onLineContaining("interface Parent");
}
@@ -928,4 +928,239 @@ public class MissingBindingValidationTest {
.onLineContaining("interface Parent");
}
+ @Test
+ public void sameSubcomponentUsedInDifferentHierarchiesMissingBindingFromOneSide() {
+ JavaFileObject parent =
+ JavaFileObjects.forSourceLines(
+ "test.Parent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface Parent {",
+ " Child1 getChild1();",
+ " Child2 getChild2();",
+ "}");
+ JavaFileObject child1 =
+ JavaFileObjects.forSourceLines(
+ "test.Child1",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = Child1Module.class)",
+ "interface Child1 {",
+ " RepeatedSub getSub();",
+ "}");
+ JavaFileObject child2 =
+ JavaFileObjects.forSourceLines(
+ "test.Child2",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = Child2Module.class)",
+ "interface Child2 {",
+ " RepeatedSub getSub();",
+ "}");
+ JavaFileObject repeatedSub =
+ JavaFileObjects.forSourceLines(
+ "test.RepeatedSub",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = RepeatedSubModule.class)",
+ "interface RepeatedSub {",
+ " Object getObject();",
+ "}");
+ JavaFileObject child1Module =
+ JavaFileObjects.forSourceLines(
+ "test.Child1Module",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.Set;",
+ "import dagger.multibindings.Multibinds;",
+ "",
+ "@Module",
+ "interface Child1Module {",
+ " @Multibinds Set<Integer> multibindIntegerSet();",
+ "}");
+ JavaFileObject child2Module =
+ JavaFileObjects.forSourceLines(
+ "test.Child2Module",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.Set;",
+ "import dagger.multibindings.Multibinds;",
+ "",
+ "@Module",
+ "interface Child2Module {",
+ " @Multibinds Set<Integer> multibindIntegerSet();",
+ "",
+ " @Provides",
+ " static Object provideObject(Set<Integer> intSet) {",
+ " return new Object();",
+ " }",
+ "}");
+ JavaFileObject repeatedSubModule =
+ JavaFileObjects.forSourceLines(
+ "test.RepeatedSubModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "import java.util.Set;",
+ "import dagger.multibindings.Multibinds;",
+ "",
+ "@Module",
+ "interface RepeatedSubModule {",
+ " @Provides",
+ " @IntoSet",
+ " static Integer provideInt() {",
+ " return 9;",
+ " }",
+ "}");
+
+ Compilation compilation =
+ daggerCompiler()
+ .compile(
+ parent, child1, child2, repeatedSub, child1Module, child2Module, repeatedSubModule);
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(1);
+ assertThat(compilation)
+ .hadErrorContaining("A binding for Object exists in [Parent → Child2 → RepeatedSub]:");
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[Parent → Child1 → RepeatedSub] RepeatedSub.getObject() [Parent → Child1 →"
+ + " RepeatedSub]");
+ }
+
+ @Test
+ public void differentComponentPkgSameSimpleNameMissingBinding() {
+ JavaFileObject parent =
+ JavaFileObjects.forSourceLines(
+ "test.Parent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface Parent {",
+ " Child1 getChild1();",
+ " Child2 getChild2();",
+ "}");
+ JavaFileObject child1 =
+ JavaFileObjects.forSourceLines(
+ "test.Child1",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = Child1Module.class)",
+ "interface Child1 {",
+ " foo.Sub getSub();",
+ "}");
+ JavaFileObject child2 =
+ JavaFileObjects.forSourceLines(
+ "test.Child2",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = Child2Module.class)",
+ "interface Child2 {",
+ " bar.Sub getSub();",
+ "}");
+ JavaFileObject sub1 =
+ JavaFileObjects.forSourceLines(
+ "foo.Sub",
+ "package foo;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = test.RepeatedSubModule.class)",
+ "public interface Sub {",
+ " Object getObject();",
+ "}");
+ JavaFileObject sub2 =
+ JavaFileObjects.forSourceLines(
+ "bar.Sub",
+ "package bar;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = test.RepeatedSubModule.class)",
+ "public interface Sub {",
+ " Object getObject();",
+ "}");
+ JavaFileObject child1Module =
+ JavaFileObjects.forSourceLines(
+ "test.Child1Module",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.Set;",
+ "import dagger.multibindings.Multibinds;",
+ "",
+ "@Module",
+ "interface Child1Module {",
+ " @Multibinds Set<Integer> multibindIntegerSet();",
+ "}");
+ JavaFileObject child2Module =
+ JavaFileObjects.forSourceLines(
+ "test.Child2Module",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.Set;",
+ "import dagger.multibindings.Multibinds;",
+ "",
+ "@Module",
+ "interface Child2Module {",
+ " @Multibinds Set<Integer> multibindIntegerSet();",
+ "",
+ " @Provides",
+ " static Object provideObject(Set<Integer> intSet) {",
+ " return new Object();",
+ " }",
+ "}");
+ JavaFileObject repeatedSubModule =
+ JavaFileObjects.forSourceLines(
+ "test.RepeatedSubModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "import java.util.Set;",
+ "import dagger.multibindings.Multibinds;",
+ "",
+ "@Module",
+ "public interface RepeatedSubModule {",
+ " @Provides",
+ " @IntoSet",
+ " static Integer provideInt() {",
+ " return 9;",
+ " }",
+ "}");
+
+ Compilation compilation =
+ daggerCompiler()
+ .compile(
+ parent, child1, child2, sub1, sub2, child1Module, child2Module, repeatedSubModule);
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(1);
+ assertThat(compilation).hadErrorContaining("A binding for Object exists in bar.Sub:");
+ assertThat(compilation)
+ .hadErrorContaining("[foo.Sub] foo.Sub.getObject() [Parent → Child1 → foo.Sub]");
+ }
}
diff --git a/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java b/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
index 84c7be4b8..3882b47cf 100644
--- a/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
+++ b/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
@@ -189,16 +189,28 @@ public class ModuleFactoryGeneratorTest {
}
@Test public void validatesIncludedModules() {
- JavaFileObject module = JavaFileObjects.forSourceLines("test.Parent",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module(includes = Void.class)",
- "class TestModule {}");
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.Parent",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(",
+ " includes = {",
+ " Void.class,",
+ " String.class,",
+ " }",
+ ")",
+ "class TestModule {}");
Compilation compilation = daggerCompiler().compile(module);
assertThat(compilation).failed();
+ // In java 11, errors reported on individual items in an annotation value's list will show up
+ // as separate errors to the user on the associated lines reported. However, in java 8, errors
+ // reported on individual items in an annotation value's list will show up as a single error
+ // (which ever is reported first) on the list itself, rather than on the items reported.
+ assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
"java.lang.Void is listed as a module, but is not annotated with @Module");
@@ -224,8 +236,12 @@ public class ModuleFactoryGeneratorTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;"),
+ "import dagger.internal.Preconditions;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class TestModule_ProvideStringFactory implements Factory<String> {",
" private final TestModule module;",
@@ -270,8 +286,13 @@ public class ModuleFactoryGeneratorTest {
"TestModule_ProvideStringFactory",
"package test;",
"",
- GeneratedLines.generatedImports("import dagger.internal.Factory;"),
+ GeneratedLines.generatedImports(
+ "import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class TestModule_ProvideStringFactory implements Factory<String> {",
" private final TestModule module;",
@@ -315,8 +336,13 @@ public class ModuleFactoryGeneratorTest {
"TestModule_ProvideStringFactory",
"package test;",
"",
- GeneratedLines.generatedImports("import dagger.internal.Factory;"),
+ GeneratedLines.generatedImports(
+ "import dagger.internal.Factory;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class TestModule_ProvideStringFactory implements Factory<String> {",
" private final TestModule module;",
@@ -388,9 +414,16 @@ public class ModuleFactoryGeneratorTest {
"import dagger.MembersInjector;",
"import dagger.internal.Factory;",
"import dagger.internal.Preconditions;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import java.util.List;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata({",
+ " \"test.QualifierA\",",
+ " \"test.QualifierB\"",
+ "})",
GeneratedLines.generatedAnnotations(),
"public final class TestModule_ProvideObjectsFactory",
" implements Factory<List<Object>> {",
@@ -459,8 +492,12 @@ public class ModuleFactoryGeneratorTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;"),
+ "import dagger.internal.Preconditions;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class TestModule_ProvideStringFactory implements Factory<String> {",
" private final TestModule module;",
@@ -512,8 +549,12 @@ public class ModuleFactoryGeneratorTest {
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
"import dagger.internal.Preconditions;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import java.util.List;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class TestModule_ProvideWildcardListFactory implements "
+ "Factory<List<List<?>>> {",
@@ -565,8 +606,12 @@ public class ModuleFactoryGeneratorTest {
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
"import dagger.internal.Preconditions;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import java.util.Set;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class TestModule_ProvideStringsFactory implements Factory<Set<String>> {",
" private final TestModule module;",
@@ -876,9 +921,13 @@ public class ModuleFactoryGeneratorTest {
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
"import dagger.internal.Preconditions;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import java.util.List;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class ParentModule_ProvideListBFactory<A extends CharSequence,",
" B, C extends Number & Comparable<C>> implements Factory<List<B>> {",
@@ -915,8 +964,12 @@ public class ModuleFactoryGeneratorTest {
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
"import dagger.internal.Preconditions;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class ParentModule_ProvideBElementFactory<A extends CharSequence,",
" B, C extends Number & Comparable<C>> implements Factory<B> {",
@@ -954,8 +1007,12 @@ public class ModuleFactoryGeneratorTest {
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
"import dagger.internal.Preconditions;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class ParentModule_ProvideBEntryFactory<A extends CharSequence,",
" B, C extends Number & Comparable<C>> implements Factory<B>> {",
@@ -992,8 +1049,12 @@ public class ModuleFactoryGeneratorTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;"),
+ "import dagger.internal.Preconditions;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class ChildNumberModule_ProvideNumberFactory",
" implements Factory<Number> {",
@@ -1024,8 +1085,12 @@ public class ModuleFactoryGeneratorTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;"),
+ "import dagger.internal.Preconditions;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class ChildIntegerModule_ProvideIntegerFactory",
" implements Factory<Integer> {",
@@ -1098,8 +1163,12 @@ public class ModuleFactoryGeneratorTest {
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
"import dagger.internal.Preconditions;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import java.util.Map;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class ParameterizedModule_ProvideMapStringNumberFactory",
" implements Factory<Map<String, Number>> {",
@@ -1130,8 +1199,12 @@ public class ModuleFactoryGeneratorTest {
"",
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;"),
+ "import dagger.internal.Preconditions;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class ParameterizedModule_ProvideNonGenericTypeFactory",
" implements Factory<Object> {",
@@ -1163,8 +1236,12 @@ public class ModuleFactoryGeneratorTest {
GeneratedLines.generatedImports(
"import dagger.internal.Factory;",
"import dagger.internal.Preconditions;",
+ "import dagger.internal.QualifierMetadata;",
+ "import dagger.internal.ScopeMetadata;",
"import javax.inject.Provider;"),
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class ParameterizedModule_ProvideNonGenericTypeWithDepsFactory",
" implements Factory<String> {",
@@ -1402,6 +1479,8 @@ public class ModuleFactoryGeneratorTest {
"test.TestModule_GetFactory",
"package test;",
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class TestModule_GetFactory implements Factory<Integer> {",
" @Override",
@@ -1425,6 +1504,8 @@ public class ModuleFactoryGeneratorTest {
"test.TestModule_CreateFactory",
"package test;",
"",
+ "@ScopeMetadata",
+ "@QualifierMetadata",
GeneratedLines.generatedAnnotations(),
"public final class TestModule_CreateFactory implements Factory<Boolean> {",
" @Override",
@@ -1442,6 +1523,202 @@ public class ModuleFactoryGeneratorTest {
"}"));
}
+ @Test
+ public void testScopedMetadataOnStaticProvides() {
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.ScopedBinding",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Module",
+ "interface MyModule {",
+ " @NonScope",
+ " @Singleton",
+ " @Provides",
+ " static String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+ JavaFileObject nonScope =
+ JavaFileObjects.forSourceLines(
+ "test.NonScope",
+ "package test;",
+ "",
+ "@interface NonScope {}");
+ Compilation compilation = daggerCompiler().compile(module, nonScope);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test.MyModule_ProvideStringFactory")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.MyModule_ProvideStringFactory",
+ "package test;",
+ "",
+ "@ScopeMetadata(\"javax.inject.Singleton\")",
+ "@QualifierMetadata",
+ GeneratedLines.generatedAnnotations(),
+ "public final class MyModule_ProvideStringFactory implements Factory<String> {}"));
+ }
+
+ @Test
+ public void testScopedMetadataOnNonStaticProvides() {
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.ScopedBinding",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Module",
+ "class MyModule {",
+ " @NonScope",
+ " @Singleton",
+ " @Provides",
+ " String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+ JavaFileObject nonScope =
+ JavaFileObjects.forSourceLines(
+ "test.NonScope",
+ "package test;",
+ "",
+ "@interface NonScope {}");
+ Compilation compilation = daggerCompiler().compile(module, nonScope);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test.MyModule_ProvideStringFactory")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.MyModule_ProvideStringFactory",
+ "package test;",
+ "",
+ "@ScopeMetadata(\"javax.inject.Singleton\")",
+ "@QualifierMetadata",
+ GeneratedLines.generatedAnnotations(),
+ "public final class MyModule_ProvideStringFactory implements Factory<String> {}"));
+ }
+
+ @Test
+ public void testScopeMetadataWithCustomScope() {
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.ScopedBinding",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Module",
+ "interface MyModule {",
+ " @NonScope(\"someValue\")",
+ " @CustomScope(\"someOtherValue\")",
+ " @Provides",
+ " static String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+ JavaFileObject customScope =
+ JavaFileObjects.forSourceLines(
+ "test.CustomScope",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope",
+ "@interface CustomScope {",
+ " String value();",
+ "}");
+ JavaFileObject nonScope =
+ JavaFileObjects.forSourceLines(
+ "test.NonScope",
+ "package test;",
+ "",
+ "@interface NonScope {",
+ " String value();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(module, customScope, nonScope);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test.MyModule_ProvideStringFactory")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.MyModule_ProvideStringFactory",
+ "package test;",
+ "",
+ "@ScopeMetadata(\"test.CustomScope\")",
+ "@QualifierMetadata",
+ GeneratedLines.generatedAnnotations(),
+ "public final class MyModule_ProvideStringFactory implements Factory<String> {}"));
+ }
+
+ @Test
+ public void testQualifierMetadataOnProvides() {
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.ScopedBinding",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Module",
+ "interface MyModule {",
+ " @Provides",
+ " @NonQualifier",
+ " @MethodQualifier",
+ " static String provideString(@NonQualifier @ParamQualifier int i) {",
+ " return \"\";",
+ " }",
+ "}");
+ JavaFileObject methodQualifier =
+ JavaFileObjects.forSourceLines(
+ "test.MethodQualifier",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "@interface MethodQualifier {}");
+ JavaFileObject paramQualifier =
+ JavaFileObjects.forSourceLines(
+ "test.ParamQualifier",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "@interface ParamQualifier {}");
+ JavaFileObject nonQualifier =
+ JavaFileObjects.forSourceLines(
+ "test.NonQualifier",
+ "package test;",
+ "",
+ "@interface NonQualifier {}");
+ Compilation compilation =
+ daggerCompiler().compile(module, methodQualifier, paramQualifier, nonQualifier);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test.MyModule_ProvideStringFactory")
+ .containsElementsIn(
+ JavaFileObjects.forSourceLines(
+ "test.MyModule_ProvideStringFactory",
+ "package test;",
+ "",
+ "@ScopeMetadata",
+ "@QualifierMetadata({\"test.MethodQualifier\", \"test.ParamQualifier\"})",
+ GeneratedLines.generatedAnnotations(),
+ "public final class MyModule_ProvideStringFactory implements Factory<String> {}"));
+ }
+
private static final String BINDS_METHOD = "@Binds abstract Foo bindFoo(FooImpl impl);";
private static final String MULTIBINDS_METHOD = "@Multibinds abstract Set<Foo> foos();";
private static final String STATIC_PROVIDES_METHOD =
diff --git a/javatests/dagger/internal/codegen/OptionalBindingRequestFulfillmentTest.java b/javatests/dagger/internal/codegen/OptionalBindingRequestFulfillmentTest.java
index 9b4353042..c78d1995f 100644
--- a/javatests/dagger/internal/codegen/OptionalBindingRequestFulfillmentTest.java
+++ b/javatests/dagger/internal/codegen/OptionalBindingRequestFulfillmentTest.java
@@ -107,41 +107,42 @@ public class OptionalBindingRequestFulfillmentTest {
.addLines(
"package test;",
"",
- "import com.google.common.base.Optional;",
- "",
GeneratedLines.generatedAnnotations(),
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
FAST_INIT_MODE,
- " private volatile Provider<Maybe> provideMaybeProvider;",
+ " private Provider<Maybe> provideMaybeProvider;",
"",
- " private Provider<Maybe> maybeProvider() {",
- " Object local = provideMaybeProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " provideMaybeProvider = (Provider<Maybe>) local;",
- " }",
- " return (Provider<Maybe>) local;",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.provideMaybeProvider = new SwitchingProvider<>(testComponent, 0);",
" }")
- .addLines(
+ .addLinesIn(
+ DEFAULT_MODE,
" @Override",
" public Optional<Maybe> maybe() {",
- " return Optional.of(",
- " Maybe_MaybeModule_ProvideMaybeFactory.provideMaybe());",
- " }",
- "",
+ " return Optional.of(Maybe_MaybeModule_ProvideMaybeFactory.provideMaybe());",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
" @Override",
- " public Optional<Provider<Lazy<Maybe>>> providerOfLazyOfMaybe() {",
- " return Optional.of(ProviderOfLazy.create(")
+ " public Optional<Maybe> maybe() {",
+ " return Optional.of(provideMaybeProvider.get());",
+ " }")
.addLinesIn(
- DEFAULT_MODE, //
- " Maybe_MaybeModule_ProvideMaybeFactory.create()));")
+ DEFAULT_MODE,
+ " @Override",
+ " public Optional<Provider<Lazy<Maybe>>> providerOfLazyOfMaybe() {",
+ " return Optional.of(ProviderOfLazy.create(",
+ " Maybe_MaybeModule_ProvideMaybeFactory.create()));",
+ " }")
.addLinesIn(
- FAST_INIT_MODE, //
- " maybeProvider()));")
+ FAST_INIT_MODE,
+ " @Override",
+ " public Optional<Provider<Lazy<Maybe>>> providerOfLazyOfMaybe() {",
+ " return Optional.of(ProviderOfLazy.create(provideMaybeProvider));",
+ " }")
.addLines(
- " }",
- "",
" @Override",
" public Optional<DefinitelyNot> definitelyNot() {",
" return Optional.<DefinitelyNot>absent();",
@@ -154,21 +155,13 @@ public class OptionalBindingRequestFulfillmentTest {
" }")
.addLinesIn(
FAST_INIT_MODE,
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
" switch (id) {",
- " case 0:",
- " return (T) Maybe_MaybeModule_ProvideMaybeFactory.provideMaybe();",
- " default:",
- " throw new AssertionError(id);",
+ " case 0: return (T) Maybe_MaybeModule_ProvideMaybeFactory.provideMaybe();",
+ " default: throw new AssertionError(id);",
" }",
" }",
" }",
diff --git a/javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java b/javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java
index 4043e768f..e0ad55abc 100644
--- a/javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java
+++ b/javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java
@@ -16,9 +16,9 @@
package dagger.internal.codegen;
-import static com.google.common.truth.Truth.assertAbout;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
+import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
@@ -224,321 +224,111 @@ public class ProductionComponentProcessorTest {
" ListenableFuture<A> a();",
" }",
"}");
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestClass_SimpleComponent",
- "package test;",
- "",
- GeneratedLines.generatedImports(
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.internal.DoubleCheck;",
- "import dagger.internal.InstanceFactory;",
- "import dagger.internal.MemoizedSentinel;",
- "import dagger.internal.Preconditions;",
- "import dagger.internal.SetFactory;",
- "import dagger.producers.Producer;",
- "import dagger.producers.internal.CancellationListener;",
- "import dagger.producers.internal.Producers;",
- "import dagger.producers.monitoring.ProductionComponentMonitor;",
- "import java.util.concurrent.Executor;",
- "import javax.inject.Provider;"),
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerTestClass_SimpleComponent",
- " implements TestClass.SimpleComponent, CancellationListener {",
- " private final TestClass.BModule bModule;",
- " private volatile Object productionImplementationExecutor =",
- " new MemoizedSentinel();",
- " private volatile Provider<Executor> productionImplementationExecutorProvider;",
- " private volatile Object productionComponentMonitor = new MemoizedSentinel();",
- " private volatile Provider<ProductionComponentMonitor> monitorProvider;",
- " private volatile Provider<TestClass.B> bProvider;",
- " private Producer<TestClass.A> aEntryPoint;",
- " private Provider<TestClass.SimpleComponent> simpleComponentProvider;",
- " private Producer<TestClass.B> bProducer;",
- " private Producer<TestClass.A> aProducer;",
- "",
- " private DaggerTestClass_SimpleComponent(",
- " TestClass.AModule aModuleParam,",
- " TestClass.BModule bModuleParam) {",
- " this.bModule = bModuleParam;",
- " initialize(aModuleParam, bModuleParam);",
- " }",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static TestClass.SimpleComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " private Executor productionImplementationExecutor() {",
- " Object local = productionImplementationExecutor;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = productionImplementationExecutor;",
- " if (local instanceof MemoizedSentinel) {",
- " local =",
- " TestClass_BModule_ExecutorFactory.executor(bModule);",
- " productionImplementationExecutor =",
- " DoubleCheck.reentrantCheck(",
- " productionImplementationExecutor, local);",
- " }",
- " }",
- " }",
- " return (Executor) local;",
- " }",
- "",
- " private Provider<Executor> productionImplementationExecutorProvider() {",
- " Object local = productionImplementationExecutorProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " productionImplementationExecutorProvider = (Provider<Executor>) local;",
- " }",
- " return (Provider<Executor>) local;",
- " }",
- "",
- " private ProductionComponentMonitor productionComponentMonitor() {",
- " Object local = productionComponentMonitor;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = productionComponentMonitor;",
- " if (local instanceof MemoizedSentinel) {",
- " local =",
- " TestClass_SimpleComponent_MonitoringModule_MonitorFactory",
- " .monitor(",
- " simpleComponentProvider,",
- " SetFactory.<ProductionComponentMonitor.Factory>empty());",
- " productionComponentMonitor =",
- " DoubleCheck.reentrantCheck(",
- " productionComponentMonitor, local);",
- " }",
- " }",
- " }",
- " return (ProductionComponentMonitor) local;",
- " }",
- "",
- " private Provider<ProductionComponentMonitor>",
- " productionComponentMonitorProvider() {",
- " Object local = monitorProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(1);",
- " monitorProvider = (Provider<ProductionComponentMonitor>) local;",
- " }",
- " return (Provider<ProductionComponentMonitor>) local;",
- " }",
- "",
- " private TestClass.B b() {",
- " return TestClass_BModule_BFactory.b(bModule, new TestClass.C());",
- " }",
- "",
- " private Provider<TestClass.B> bProvider() {",
- " Object local = bProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(2);",
- " bProvider = (Provider<TestClass.B>) local;",
- " }",
- " return (Provider<TestClass.B>) local;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(",
- " final TestClass.AModule aModuleParam,",
- " final TestClass.BModule bModuleParam) {",
- " this.simpleComponentProvider =",
- " InstanceFactory.create((TestClass.SimpleComponent) this);",
- " this.bProducer = Producers.producerFromProvider(bProvider());",
- " this.aProducer =",
- " TestClass_AModule_AFactory.create(",
- " aModuleParam,",
- " productionImplementationExecutorProvider(),",
- " productionComponentMonitorProvider(),",
- " bProducer);",
- " this.aEntryPoint = Producers.entryPointViewOf(aProducer, this);",
- " }",
- "",
- " @Override",
- " public ListenableFuture<TestClass.A> a() {",
- " return aEntryPoint.get();",
- " }",
- "",
- " @Override",
- " public void onProducerFutureCancelled(boolean mayInterruptIfRunning) {",
- " Producers.cancel(aProducer, mayInterruptIfRunning);",
- " Producers.cancel(bProducer, mayInterruptIfRunning);",
- " }",
- "",
- " static final class Builder {",
- " private TestClass.AModule aModule;",
- " private TestClass.BModule bModule;",
- "",
- " private Builder() {}",
- "",
- " public Builder aModule(TestClass.AModule aModule) {",
- " this.aModule = Preconditions.checkNotNull(aModule);",
- " return this;",
- " }",
- "",
- " public Builder bModule(TestClass.BModule bModule) {",
- " this.bModule = Preconditions.checkNotNull(bModule);",
- " return this;",
- " }",
- "",
- " public TestClass.SimpleComponent build() {",
- " if (aModule == null) {",
- " this.aModule = new TestClass.AModule();",
- " }",
- " if (bModule == null) {",
- " this.bModule = new TestClass.BModule();",
- " }",
- " return new DaggerTestClass_SimpleComponent(aModule, bModule);",
- " }",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0: return (T) DaggerTestClass_SimpleComponent.this",
- " .productionImplementationExecutor();",
- " case 1: return (T)",
- " DaggerTestClass_SimpleComponent.this.productionComponentMonitor();",
- " case 2: return (T)",
- " DaggerTestClass_SimpleComponent.this.b();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestClass_SimpleComponent",
- "package test;",
- "",
- GeneratedLines.generatedImports(
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.internal.DoubleCheck;",
- "import dagger.internal.InstanceFactory;",
- "import dagger.internal.Preconditions;",
- "import dagger.internal.SetFactory;",
- "import dagger.producers.Producer;",
- "import dagger.producers.internal.CancellationListener;",
- "import dagger.producers.internal.Producers;",
- "import dagger.producers.monitoring.ProductionComponentMonitor;",
- "import java.util.concurrent.Executor;",
- "import javax.inject.Provider;"),
- "",
- GeneratedLines.generatedAnnotations(),
- "final class DaggerTestClass_SimpleComponent",
- " implements TestClass.SimpleComponent, CancellationListener {",
- " private Producer<TestClass.A> aEntryPoint;",
- " private Provider<Executor> executorProvider;",
- " private Provider<Executor> productionImplementationExecutorProvider;",
- " private Provider<TestClass.SimpleComponent> simpleComponentProvider;",
- " private Provider<ProductionComponentMonitor> monitorProvider;",
- " private Provider<TestClass.B> bProvider;",
- " private Producer<TestClass.B> bProducer;",
- " private Producer<TestClass.A> aProducer;",
- "",
- " private DaggerTestClass_SimpleComponent(",
- " TestClass.AModule aModuleParam,",
- " TestClass.BModule bModuleParam) {",
- " initialize(aModuleParam, bModuleParam);",
- " }",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static TestClass.SimpleComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(",
- " final TestClass.AModule aModuleParam,",
- " final TestClass.BModule bModuleParam) {",
- " this.executorProvider =",
- " TestClass_BModule_ExecutorFactory.create(bModuleParam);",
- " this.productionImplementationExecutorProvider =",
- " DoubleCheck.provider((Provider) executorProvider);",
- " this.simpleComponentProvider = ",
- " InstanceFactory.create((TestClass.SimpleComponent) this);",
- " this.monitorProvider =",
- " DoubleCheck.provider(",
- " TestClass_SimpleComponent_MonitoringModule_MonitorFactory.create(",
- " simpleComponentProvider,",
- " SetFactory.<ProductionComponentMonitor.Factory>empty()));",
- " this.bProvider = TestClass_BModule_BFactory.create(",
- " bModuleParam, TestClass_C_Factory.create());",
- " this.bProducer = Producers.producerFromProvider(bProvider);",
- " this.aProducer = TestClass_AModule_AFactory.create(",
- " aModuleParam,",
- " productionImplementationExecutorProvider,",
- " monitorProvider,",
- " bProducer);",
- " this.aEntryPoint = Producers.entryPointViewOf(aProducer, this);",
- " }",
- "",
- " @Override",
- " public ListenableFuture<TestClass.A> a() {",
- " return aEntryPoint.get();",
- " }",
- "",
- " @Override",
- " public void onProducerFutureCancelled(boolean mayInterruptIfRunning) {",
- " Producers.cancel(aProducer, mayInterruptIfRunning);",
- " Producers.cancel(bProducer, mayInterruptIfRunning);",
- " }",
- "",
- " static final class Builder {",
- " private TestClass.AModule aModule;",
- " private TestClass.BModule bModule;",
- "",
- " private Builder() {}",
- "",
- " public Builder aModule(TestClass.AModule aModule) {",
- " this.aModule = Preconditions.checkNotNull(aModule);",
- " return this;",
- " }",
- "",
- " public Builder bModule(TestClass.BModule bModule) {",
- " this.bModule = Preconditions.checkNotNull(bModule);",
- " return this;",
- " }",
- "",
- " public TestClass.SimpleComponent build() {",
- " if (aModule == null) {",
- " this.aModule = new TestClass.AModule();",
- " }",
- " if (bModule == null) {",
- " this.bModule = new TestClass.BModule();",
- " }",
- " return new DaggerTestClass_SimpleComponent(aModule, bModule);",
- " }",
- " }",
- "}");
- }
- assertAbout(javaSource())
- .that(component)
- .withCompilerOptions(compilerMode.javacopts())
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(generatedComponent);
+
+ Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(component);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerTestClass_SimpleComponent")
+ .containsElementsIn(
+ compilerMode
+ .javaFileBuilder("test.DaggerTestClass_SimpleComponent")
+ .addLines(
+ "package test;",
+ "",
+ GeneratedLines.generatedAnnotations(),
+ "final class DaggerTestClass_SimpleComponent",
+ " implements TestClass.SimpleComponent, CancellationListener {",
+ " private Producer<TestClass.A> aEntryPoint;",
+ " private Provider<Executor> executorProvider;",
+ " private Provider<Executor> productionImplementationExecutorProvider;",
+ " private Provider<TestClass.SimpleComponent> simpleComponentProvider;",
+ " private Provider<ProductionComponentMonitor> monitorProvider;",
+ " private Provider<TestClass.B> bProvider;",
+ " private Producer<TestClass.B> bProducer;",
+ " private Producer<TestClass.A> aProducer;")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(",
+ " final TestClass.AModule aModuleParam,",
+ " final TestClass.BModule bModuleParam) {",
+ " this.executorProvider =",
+ " TestClass_BModule_ExecutorFactory.create(bModuleParam);",
+ " this.productionImplementationExecutorProvider =",
+ " DoubleCheck.provider((Provider) executorProvider);",
+ " this.simpleComponentProvider = ",
+ " InstanceFactory.create((TestClass.SimpleComponent) simpleComponent);",
+ " this.monitorProvider =",
+ " DoubleCheck.provider(",
+ " TestClass_SimpleComponent_MonitoringModule_MonitorFactory.create(",
+ " simpleComponentProvider,",
+ " SetFactory.<ProductionComponentMonitor.Factory>empty()));",
+ " this.bProvider = TestClass_BModule_BFactory.create(",
+ " bModuleParam, TestClass_C_Factory.create());",
+ " this.bProducer = Producers.producerFromProvider(bProvider);",
+ " this.aProducer = TestClass_AModule_AFactory.create(",
+ " aModuleParam,",
+ " productionImplementationExecutorProvider,",
+ " monitorProvider,",
+ " bProducer);",
+ " this.aEntryPoint = Producers.entryPointViewOf(aProducer, this);",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(",
+ " final TestClass.AModule aModuleParam,",
+ " final TestClass.BModule bModuleParam) {",
+ " this.executorProvider = new SwitchingProvider<>(simpleComponent, 0);",
+ " this.productionImplementationExecutorProvider =",
+ " DoubleCheck.provider((Provider) executorProvider);",
+ " this.simpleComponentProvider =",
+ " InstanceFactory.create((TestClass.SimpleComponent) simpleComponent);",
+ " this.monitorProvider = DoubleCheck.provider(",
+ " new SwitchingProvider<ProductionComponentMonitor>(",
+ " simpleComponent, 1));",
+ " this.bProvider = new SwitchingProvider<>(simpleComponent, 2);",
+ " this.bProducer = Producers.producerFromProvider(bProvider);",
+ " this.aProducer = TestClass_AModule_AFactory.create(",
+ " aModuleParam,",
+ " productionImplementationExecutorProvider,",
+ " monitorProvider,",
+ " bProducer);",
+ " this.aEntryPoint = Producers.entryPointViewOf(aProducer, this);",
+ " }")
+ .addLines(
+ " @Override",
+ " public ListenableFuture<TestClass.A> a() {",
+ " return aEntryPoint.get();",
+ " }",
+ "",
+ " @Override",
+ " public void onProducerFutureCancelled(boolean mayInterruptIfRunning) {",
+ " Producers.cancel(aProducer, mayInterruptIfRunning);",
+ " Producers.cancel(bProducer, mayInterruptIfRunning);",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0: return (T) TestClass_BModule_ExecutorFactory.executor(",
+ " simpleComponent.bModule);",
+ " case 1: return (T)",
+ " TestClass_SimpleComponent_MonitoringModule_MonitorFactory",
+ " .monitor(",
+ " simpleComponent.simpleComponentProvider,",
+ " SetFactory.<ProductionComponentMonitor.Factory>empty());",
+ " case 2: return (T) TestClass_BModule_BFactory.b(",
+ " simpleComponent.bModule, new TestClass.C());",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
+ " }",
+ "}")
+ .build());
}
@Test public void nullableProducersAreNotErrors() {
@@ -648,20 +438,16 @@ public class ProductionComponentProcessorTest {
new JavaFileBuilder(compilerMode, "test.DaggerRoot")
.addLines(
"package test;",
+ "",
GeneratedLines.generatedAnnotations(),
"final class DaggerParent implements Parent, CancellationListener {",
- " private final class ChildImpl implements Child, CancellationListener {",
+ " private static final class ChildImpl",
+ " implements Child, CancellationListener {",
" @Override",
- " public ProductionScoped productionScoped() {")
- .addLinesIn(
- CompilerMode.DEFAULT_MODE, //
- " return DaggerParent.this.productionScopedProvider.get();")
- .addLinesIn(
- CompilerMode.FAST_INIT_MODE, //
- " return DaggerParent.this.productionScoped();")
- .addLines(
- " }", //
- " }", //
+ " public ProductionScoped productionScoped() {",
+ " return parent.productionScopedProvider.get();",
+ " }",
+ " }",
"}")
.build());
}
diff --git a/javatests/dagger/internal/codegen/RawTypeInjectionTest.java b/javatests/dagger/internal/codegen/RawTypeInjectionTest.java
new file mode 100644
index 000000000..62eaea45d
--- /dev/null
+++ b/javatests/dagger/internal/codegen/RawTypeInjectionTest.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.testing.compile.CompilationSubject.assertThat;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class RawTypeInjectionTest {
+ @Test
+ public void rawEntryPointTest() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " Foo foo();", // Fail: requesting raw type
+ "}");
+ JavaFileObject foo =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Foo<T> {",
+ " @Inject Foo() {}",
+ "}");
+
+ Compilation compilation = daggerCompiler().compile(component, foo);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining("Foo cannot be provided without an @Provides-annotated method.")
+ .inFile(component)
+ .onLine(6);
+ }
+
+ @Test
+ public void rawProvidesRequestTest() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " int integer();",
+ "}");
+ JavaFileObject foo =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Foo<T> {",
+ " @Inject Foo() {}",
+ "}");
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class TestModule {",
+ " @Provides",
+ " int provideFoo(Foo foo) {", // Fail: requesting raw type
+ " return 0;",
+ " }",
+ "}");
+
+
+ Compilation compilation = daggerCompiler().compile(component, foo, module);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining("Foo cannot be provided without an @Provides-annotated method.")
+ .inFile(component)
+ .onLine(6);
+ }
+
+ @Test
+ public void rawInjectConstructorRequestTest() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " Foo foo();",
+ "}");
+ JavaFileObject foo =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Foo<T> {",
+ " @Inject Foo() {}",
+ "}");
+ JavaFileObject bar =
+ JavaFileObjects.forSourceLines(
+ "test.Bar",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Bar {",
+ " @Inject Bar(Foo foo) {}", // Fail: requesting raw type
+ "}");
+
+
+ Compilation compilation = daggerCompiler().compile(component, foo, bar);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining("Foo cannot be provided without an @Provides-annotated method.")
+ .inFile(component)
+ .onLine(6);
+ }
+
+ @Test
+ public void rawProvidesReturnTest() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ // Test that we can request the raw type if it's provided by a module.
+ " Foo foo();",
+ "}");
+ JavaFileObject foo =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Foo<T> {",
+ " @Inject Foo() {}",
+ "}");
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class TestModule {",
+ // Test that Foo<T> can still be requested and is independent of Foo (otherwise we'd
+ // get a cyclic dependency error).
+ " @Provides",
+ " Foo provideFoo(Foo<Integer> fooInteger) {",
+ " return fooInteger;",
+ " }",
+ "",
+ " @Provides",
+ " int provideInt() {",
+ " return 0;",
+ " }",
+ "}");
+
+ Compilation compilation = daggerCompiler().compile(component, foo, module);
+ assertThat(compilation).succeeded();
+ }
+}
diff --git a/javatests/dagger/internal/codegen/ScopingValidationTest.java b/javatests/dagger/internal/codegen/ScopingValidationTest.java
index 58ab2af44..740a44594 100644
--- a/javatests/dagger/internal/codegen/ScopingValidationTest.java
+++ b/javatests/dagger/internal/codegen/ScopingValidationTest.java
@@ -79,6 +79,9 @@ public class ScopingValidationTest {
message(
"MyComponent (unscoped) may not reference scoped bindings:",
" @Singleton class ScopedType",
+ " ScopedType is requested at",
+ " MyComponent.string()",
+ "",
" @Provides @Singleton String ScopedModule.string()"));
}
@@ -236,7 +239,11 @@ public class ScopingValidationTest {
"MyComponent scoped with @Singleton "
+ "may not reference bindings with different scopes:",
" @PerTest class ScopedType",
+ " ScopedType is requested at",
+ " MyComponent.string()",
+ "",
" @Provides @PerTest String ScopedModule.string()",
+ "",
" @Provides @Per(MyComponent.class) boolean "
+ "ScopedModule.bool()"))
.inFile(componentFile)
@@ -251,7 +258,9 @@ public class ScopingValidationTest {
message(
"ScopedModule contains bindings with different scopes:",
" @Provides @PerTest String ScopedModule.string()",
+ "",
" @Provides @Singleton float ScopedModule.floatingPoint()",
+ "",
" @Provides @Per(MyComponent.class) boolean "
+ "ScopedModule.bool()"))
.inFile(moduleFile)
diff --git a/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java b/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java
index a343a601d..e1c49d6ad 100644
--- a/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java
+++ b/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java
@@ -266,6 +266,8 @@ public class SetBindingRequestFulfillmentTest {
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerParent implements Parent {",
+ " private final DaggerParent parent = this;",
+ "",
" private DaggerParent() {}",
"",
" public static Builder builder() {",
@@ -278,7 +280,7 @@ public class SetBindingRequestFulfillmentTest {
"",
" @Override",
" public Child child() {",
- " return new ChildImpl();",
+ " return new ChildImpl(parent);",
" }",
"",
" static final class Builder {",
@@ -295,8 +297,14 @@ public class SetBindingRequestFulfillmentTest {
" }",
" }",
"",
- " private final class ChildImpl implements Child {",
- " private ChildImpl() {}",
+ " private static final class ChildImpl implements Child {",
+ " private final DaggerParent parent;",
+ "",
+ " private final ChildImpl childImpl = this;",
+ "",
+ " private ChildImpl(DaggerParent parent) {",
+ " this.parent = parent;",
+ " }",
"",
" @Override",
" public Set<Object> objectSet() {",
diff --git a/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentWithGuavaTest.java b/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentWithGuavaTest.java
index a08113023..6e6236c99 100644
--- a/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentWithGuavaTest.java
+++ b/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentWithGuavaTest.java
@@ -272,7 +272,7 @@ public class SetBindingRequestFulfillmentWithGuavaTest {
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerParent implements Parent {",
- " private final class ChildImpl implements Child {",
+ " private static final class ChildImpl implements Child {",
" @Override",
" public Set<Object> objectSet() {",
" return ImmutableSet.<Object>of(",
@@ -330,8 +330,10 @@ public class SetBindingRequestFulfillmentWithGuavaTest {
"import java.util.Set;"),
"",
GeneratedLines.generatedAnnotations(),
- "final class DaggerTestComponent implements TestComponent, "
- + "CancellationListener {",
+ "final class DaggerTestComponent implements TestComponent, ",
+ " CancellationListener {",
+ " private final DaggerTestComponent testComponent = this;",
+ "",
" private DaggerTestComponent() {}",
"",
" public static Builder builder() {",
diff --git a/javatests/dagger/internal/codegen/SubcomponentBuilderValidationTest.java b/javatests/dagger/internal/codegen/SubcomponentBuilderValidationTest.java
index 0fd7e084d..2b3c49f51 100644
--- a/javatests/dagger/internal/codegen/SubcomponentBuilderValidationTest.java
+++ b/javatests/dagger/internal/codegen/SubcomponentBuilderValidationTest.java
@@ -18,7 +18,7 @@ package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.SUBCOMPONENT_BUILDER;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.SUBCOMPONENT_BUILDER;
import static dagger.internal.codegen.binding.ErrorMessages.creatorMessagesFor;
import com.google.testing.compile.Compilation;
diff --git a/javatests/dagger/internal/codegen/SubcomponentCreatorRequestFulfillmentTest.java b/javatests/dagger/internal/codegen/SubcomponentCreatorRequestFulfillmentTest.java
index 32ae245dd..245b051c8 100644
--- a/javatests/dagger/internal/codegen/SubcomponentCreatorRequestFulfillmentTest.java
+++ b/javatests/dagger/internal/codegen/SubcomponentCreatorRequestFulfillmentTest.java
@@ -21,13 +21,13 @@ import static com.google.common.collect.Sets.immutableEnumSet;
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.SUBCOMPONENT_BUILDER;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.SUBCOMPONENT_FACTORY;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.SUBCOMPONENT_BUILDER;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.SUBCOMPONENT_FACTORY;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.testing.compile.Compilation;
-import dagger.internal.codegen.binding.ComponentCreatorAnnotation;
+import dagger.internal.codegen.base.ComponentCreatorAnnotation;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -103,23 +103,25 @@ public class SubcomponentCreatorRequestFulfillmentTest extends ComponentCreatorT
"final class DaggerC implements C {",
" @Override",
" public Sub.Builder sBuilder() {",
- " return new SubBuilder();",
+ " return new SubBuilder(c);",
" }",
"",
" @Override",
" public UsesSubcomponent usesSubcomponent() {",
- " return new UsesSubcomponent(new SubBuilder());",
+ " return new UsesSubcomponent(new SubBuilder(c));",
" }",
"",
- " private final class SubBuilder implements Sub.Builder {",
+ " private static final class SubBuilder implements Sub.Builder {",
" @Override",
" public Sub build() {",
- " return new SubImpl();",
+ " return new SubImpl(c);",
" }",
" }",
"",
- " private final class SubImpl implements Sub {",
- " private SubImpl() {}",
+ " private static final class SubImpl implements Sub {",
+ " private SubImpl(DaggerC c) {",
+ " this.c = c;",
+ " }",
" }",
"}");
diff --git a/javatests/dagger/internal/codegen/SubcomponentCreatorValidationTest.java b/javatests/dagger/internal/codegen/SubcomponentCreatorValidationTest.java
index 371253a81..f9b6e5895 100644
--- a/javatests/dagger/internal/codegen/SubcomponentCreatorValidationTest.java
+++ b/javatests/dagger/internal/codegen/SubcomponentCreatorValidationTest.java
@@ -19,18 +19,18 @@ package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
import static dagger.internal.codegen.TestUtils.message;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.SUBCOMPONENT_BUILDER;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.SUBCOMPONENT_FACTORY;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.BUILDER;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.FACTORY;
-import static dagger.internal.codegen.binding.ComponentKind.SUBCOMPONENT;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.SUBCOMPONENT_BUILDER;
+import static dagger.internal.codegen.base.ComponentCreatorAnnotation.SUBCOMPONENT_FACTORY;
+import static dagger.internal.codegen.base.ComponentCreatorKind.BUILDER;
+import static dagger.internal.codegen.base.ComponentCreatorKind.FACTORY;
+import static dagger.internal.codegen.base.ComponentKind.SUBCOMPONENT;
import static dagger.internal.codegen.binding.ErrorMessages.ComponentCreatorMessages.moreThanOneRefToSubcomponent;
import static dagger.internal.codegen.binding.ErrorMessages.componentMessagesFor;
import com.google.common.collect.ImmutableList;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
-import dagger.internal.codegen.binding.ComponentCreatorAnnotation;
+import dagger.internal.codegen.base.ComponentCreatorAnnotation;
import java.util.Collection;
import javax.tools.JavaFileObject;
import org.junit.Test;
@@ -52,17 +52,19 @@ public class SubcomponentCreatorValidationTest extends ComponentCreatorTestHelpe
@Test
public void testRefSubcomponentAndSubCreatorFails() {
- JavaFileObject componentFile = preprocessedJavaFile("test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface ParentComponent {",
- " ChildComponent child();",
- " ChildComponent.Builder builder();",
- "}");
+ JavaFileObject componentFile =
+ preprocessedJavaFile(
+ "test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent child();",
+ " ChildComponent.Builder childComponentBuilder();",
+ "}");
JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
"package test;",
"",
@@ -82,7 +84,7 @@ public class SubcomponentCreatorValidationTest extends ComponentCreatorTestHelpe
String.format(
moreThanOneRefToSubcomponent(),
"test.ChildComponent",
- process("[child(), builder()]")))
+ process("[child(), childComponentBuilder()]")))
.inFile(componentFile);
}
@@ -244,16 +246,18 @@ public class SubcomponentCreatorValidationTest extends ComponentCreatorTestHelpe
@Test
public void testCreatorMissingFactoryMethodFails() {
- JavaFileObject componentFile = preprocessedJavaFile("test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface ParentComponent {",
- " ChildComponent.Builder builder();",
- "}");
+ JavaFileObject componentFile =
+ preprocessedJavaFile(
+ "test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent.Builder childComponentBuilder();",
+ "}");
JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
"package test;",
"",
@@ -726,8 +730,7 @@ public class SubcomponentCreatorValidationTest extends ComponentCreatorTestHelpe
" interface Factory {",
" ChildComponent create(String s, Integer i);",
" }")
- .addLines( //
- "}")
+ .addLines("}")
.build();
Compilation compilation = compile(componentFile, childComponentFile);
assertThat(compilation).failed();
diff --git a/javatests/dagger/internal/codegen/SubcomponentValidationTest.java b/javatests/dagger/internal/codegen/SubcomponentValidationTest.java
index c63522e88..0a24043c2 100644
--- a/javatests/dagger/internal/codegen/SubcomponentValidationTest.java
+++ b/javatests/dagger/internal/codegen/SubcomponentValidationTest.java
@@ -222,7 +222,7 @@ public class SubcomponentValidationTest {
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "A module may only occur once an an argument in a Subcomponent factory method, "
+ "A module may only occur once as an argument in a Subcomponent factory method, "
+ "but test.TestModule was already passed.")
.inFile(componentFile)
.onLine(7)
@@ -456,7 +456,9 @@ public class SubcomponentValidationTest {
"package test;",
"",
GeneratedLines.generatedAnnotations(),
- "final class DaggerParentComponent implements ParentComponent {")
+ "final class DaggerParentComponent implements ParentComponent {",
+ " private Provider<Dep1> dep1Provider;",
+ " private Provider<Dep2> dep2Provider;")
.addLinesIn(
DEFAULT_MODE,
" @SuppressWarnings(\"unchecked\")",
@@ -465,54 +467,30 @@ public class SubcomponentValidationTest {
" this.dep2Provider = DoubleCheck.provider(Dep2_Factory.create());",
" }",
"")
- .addLines(
- " @Override", //
- " public Dep1 dep1() {")
.addLinesIn(
FAST_INIT_MODE,
- " Object local = dep1;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = dep1;",
- " if (local instanceof MemoizedSentinel) {",
- " local = injectDep1(Dep1_Factory.newInstance());",
- " dep1 = DoubleCheck.reentrantCheck(dep1, local);",
- " }",
- " }",
- " }",
- " return (Dep1) local;")
- .addLinesIn(
- DEFAULT_MODE, //
- " return dep1Provider.get();")
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.dep1Provider = DoubleCheck.provider(",
+ " new SwitchingProvider<Dep1>(parentComponent, 0));",
+ " this.dep2Provider = DoubleCheck.provider(",
+ " new SwitchingProvider<Dep2>(parentComponent, 1));",
+ " }")
.addLines(
- " }", //
+ " @Override",
+ " public Dep1 dep1() {",
+ " return dep1Provider.get();",
+ " }",
"",
" @Override",
- " public Dep2 dep2() {")
- .addLinesIn(
- FAST_INIT_MODE,
- " Object local = dep2;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = dep2;",
- " if (local instanceof MemoizedSentinel) {",
- " local = injectDep2(Dep2_Factory.newInstance());",
- " dep2 = DoubleCheck.reentrantCheck(dep2, local);",
- " }",
- " }",
- " }",
- " return (Dep2) local;")
- .addLinesIn(
- DEFAULT_MODE, //
- " return dep2Provider.get();")
- .addLines(
+ " public Dep2 dep2() {",
+ " return dep2Provider.get();",
" }",
"",
" @Override",
" public ChildComponent childComponent() {",
- " return new ChildComponentImpl();",
- " }",
- "")
+ " return new ChildComponentImpl(parentComponent);",
+ " }")
.addLinesIn(
FAST_INIT_MODE,
" @CanIgnoreReturnValue",
@@ -527,38 +505,17 @@ public class SubcomponentValidationTest {
" return instance;",
" }")
.addLines(
- "",
- " private final class ChildComponentImpl implements ChildComponent {",
- " private final ChildModule childModule;",
- "",
- " private ChildComponentImpl() {",
- " this.childModule = new ChildModule();",
- " }",
- "")
- .addLinesIn(
- DEFAULT_MODE,
+ " private static final class ChildComponentImpl implements ChildComponent {",
" private NeedsDep1 needsDep1() {",
- " return new NeedsDep1(DaggerParentComponent.this.dep1Provider.get());",
- " }")
- .addLinesIn(
- FAST_INIT_MODE,
- " private NeedsDep1 needsDep1() {",
- " return new NeedsDep1(DaggerParentComponent.this.dep1());",
- " }")
- .addLines(
+ " return new NeedsDep1(parentComponent.dep1Provider.get());",
+ " }",
+ "",
" private A a() {",
" return injectA(",
" A_Factory.newInstance(",
- " needsDep1(),")
- .addLinesIn(
- DEFAULT_MODE,
- " DaggerParentComponent.this.dep1Provider.get(),",
- " DaggerParentComponent.this.dep2Provider.get()));")
- .addLinesIn(
- FAST_INIT_MODE,
- " DaggerParentComponent.this.dep1(),",
- " DaggerParentComponent.this.dep2()));")
- .addLines(
+ " needsDep1(),",
+ " parentComponent.dep1Provider.get(),",
+ " parentComponent.dep2Provider.get()));",
" }",
"",
" @Override",
@@ -572,6 +529,21 @@ public class SubcomponentValidationTest {
" A_MembersInjector.injectMethodA(instance);",
" return instance;",
" }",
+ " }")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
+ " @SuppressWarnings(\"unchecked\")",
+ " @Override",
+ " public T get() {",
+ " switch (id) {",
+ " case 0:",
+ " return (T) parentComponent.injectDep1(Dep1_Factory.newInstance());",
+ " case 1:",
+ " return (T) parentComponent.injectDep2(Dep2_Factory.newInstance());",
+ " default: throw new AssertionError(id);",
+ " }",
+ " }",
" }",
"}")
.build();
@@ -658,12 +630,12 @@ public class SubcomponentValidationTest {
"final class DaggerParentComponent implements ParentComponent {",
" @Override",
" public Foo.Sub newInstanceSubcomponent() {",
- " return new F_SubImpl();",
+ " return new F_SubImpl(parentComponent);",
" }",
"",
" @Override",
" public NoConflict newNoConflictSubcomponent() {",
- " return new NoConflictImpl();",
+ " return new NoConflictImpl(parentComponent);",
" }",
"",
" static final class Builder {",
@@ -672,23 +644,13 @@ public class SubcomponentValidationTest {
" }",
" }",
"",
- " private final class F_SubImpl implements Foo.Sub {",
- " @Override",
- " public Bar.Sub newBarSubcomponent() {",
- " return new B_SubImpl();",
- " }",
+ " private static final class ts_SubImpl implements Sub {}",
"",
- " private final class B_SubImpl implements Bar.Sub {",
- " @Override",
- " public Sub newSubcomponentInSubpackage() {",
- " return new ts_SubI();",
- " }",
+ " private static final class B_SubImpl implements Bar.Sub {}",
"",
- " private final class ts_SubI implements Sub {}",
- " }",
- " }",
+ " private static final class F_SubImpl implements Foo.Sub {}",
"",
- " private final class NoConflictImpl implements NoConflict {}",
+ " private static final class NoConflictImpl implements NoConflict {}",
"}");
Compilation compilation =
compilerWithOptions(compilerMode.javacopts())
@@ -740,7 +702,7 @@ public class SubcomponentValidationTest {
"final class DaggerParentComponent implements ParentComponent {",
" @Override",
" public Sub newSubcomponent() {",
- " return new t_SubImpl();",
+ " return new t_SubImpl(parentComponent);",
" }",
"",
" static final class Builder {",
@@ -749,17 +711,10 @@ public class SubcomponentValidationTest {
" }",
" }",
"",
- " private final class t_SubImpl implements Sub {",
- " @Override",
- " public test.deep.many.levels.that.match.test.Sub newDeepSubcomponent() {",
- " return new tdmltmt_SubImpl();",
- " }",
+ " private static final class tdmltmt_SubImpl",
+ " implements test.deep.many.levels.that.match.test.Sub {}",
"",
- " private final class tdmltmt_SubImpl implements ",
- " test.deep.many.levels.that.match.test.Sub {",
- " private tdmltmt_SubImpl() {}",
- " }",
- " }",
+ " private static final class t_SubImpl implements Sub {}",
"}");
Compilation compilation =
compilerWithOptions(compilerMode.javacopts()).compile(parent, sub, deepSub);
@@ -805,22 +760,13 @@ public class SubcomponentValidationTest {
"final class DaggerParentComponent implements ParentComponent {",
" @Override",
" public Sub newSubcomponent() {",
- " return new $_SubImpl();",
+ " return new $_SubImpl(parentComponent);",
" }",
"",
- " private final class $_SubImpl implements Sub {",
- " private $_SubImpl() {}",
- "",
- " @Override",
- " public test.deep.many.levels.that.match.test.Sub newDeepSubcomponent() {",
- " return new tdmltmt_SubImpl();",
- " }",
+ " private static final class tdmltmt_SubImpl",
+ " implements test.deep.many.levels.that.match.test.Sub {}",
"",
- " private final class tdmltmt_SubImpl implements ",
- " test.deep.many.levels.that.match.test.Sub {",
- " private tdmltmt_SubImpl() {}",
- " }",
- " }",
+ " private static final class $_SubImpl implements Sub {}",
"}",
"");
@@ -882,19 +828,23 @@ public class SubcomponentValidationTest {
"final class DaggerParentComponent implements ParentComponent {",
" @Override",
" public E.F.Sub top1() {",
- " return new F_SubImpl();",
+ " return new F_SubImpl(parentComponent);",
" }",
"",
" @Override",
" public top2.a.b.c.d.E.F.Sub top2() {",
- " return new F2_SubImpl();",
+ " return new F2_SubImpl(parentComponent);",
" }",
"",
- " private final class F_SubImpl implements E.F.Sub {",
- " private F_SubImpl() {}",
+ " private static final class F_SubImpl implements E.F.Sub {",
+ " private F_SubImpl(DaggerParentComponent parentComponent) {",
+ " this.parentComponent = parentComponent;",
+ " }",
" }",
- " private final class F2_SubImpl implements top2.a.b.c.d.E.F.Sub {",
- " private F2_SubImpl() {}",
+ " private static final class F2_SubImpl implements top2.a.b.c.d.E.F.Sub {",
+ " private F2_SubImpl(DaggerParentComponent parentComponent) {",
+ " this.parentComponent = parentComponent;",
+ " }",
" }",
"}");
@@ -939,10 +889,10 @@ public class SubcomponentValidationTest {
"final class DaggerC implements C {",
" @Override",
" public Foo.C newInstanceC() {",
- " return new F_CImpl();",
+ " return new F_CImpl(c);",
" }",
"",
- " private final class F_CImpl implements Foo.C {}",
+ " private static final class F_CImpl implements Foo.C {}",
"}");
Compilation compilation =
@@ -1000,36 +950,40 @@ public class SubcomponentValidationTest {
"final class DaggerC implements C {",
" @Override",
" public C.Foo.Sub.Builder fooBuilder() {",
- " return new F_SubBuilder();",
+ " return new F_SubBuilder(c);",
" }",
"",
" @Override",
" public C.Bar.Sub.Builder barBuilder() {",
- " return new B_SubBuilder();",
+ " return new B_SubBuilder(c);",
" }",
"",
// TODO(bcorso): Reverse the order of subcomponent and builder so that subcomponent
// comes first.
- " private final class F_SubBuilder implements C.Foo.Sub.Builder {",
+ " private static final class F_SubBuilder implements C.Foo.Sub.Builder {",
" @Override",
" public C.Foo.Sub build() {",
- " return new F_SubImpl();",
+ " return new F_SubImpl(c);",
" }",
" }",
"",
- " private final class F_SubImpl implements C.Foo.Sub {",
- " private F_SubImpl() {}",
- " }",
- "",
- " private final class B_SubBuilder implements C.Bar.Sub.Builder {",
+ " private static final class B_SubBuilder implements C.Bar.Sub.Builder {",
" @Override",
" public C.Bar.Sub build() {",
- " return new B_SubImpl();",
+ " return new B_SubImpl(c);",
" }",
" }",
"",
- " private final class B_SubImpl implements C.Bar.Sub {",
- " private B_SubImpl() {}",
+ " private static final class F_SubImpl implements C.Foo.Sub {",
+ " private F_SubImpl(DaggerC c) {",
+ " this.c = c;",
+ " }",
+ " }",
+ "",
+ " private static final class B_SubImpl implements C.Bar.Sub {",
+ " private B_SubImpl(DaggerC c) {",
+ " this.c = c;",
+ " }",
" }",
"}");
Compilation compilation =
diff --git a/javatests/dagger/internal/codegen/SwitchingProviderTest.java b/javatests/dagger/internal/codegen/SwitchingProviderTest.java
index 615b09dbf..fb0f7e501 100644
--- a/javatests/dagger/internal/codegen/SwitchingProviderTest.java
+++ b/javatests/dagger/internal/codegen/SwitchingProviderTest.java
@@ -17,7 +17,7 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static com.google.testing.compile.Compiler.javac;
+import static dagger.internal.codegen.Compilers.compilerWithOptions;
import com.google.common.collect.ImmutableList;
import com.google.testing.compile.Compilation;
@@ -69,7 +69,7 @@ public class SwitchingProviderTest {
"package test;",
GeneratedLines.generatedAnnotations(),
"final class DaggerTestComponent implements TestComponent {",
- " private final class SwitchingProvider<T> implements Provider<T> {",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" private T get0() {",
" switch (id) {",
@@ -249,36 +249,30 @@ public class SwitchingProviderTest {
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerTestComponent implements TestComponent {",
- " private volatile Provider<String> sProvider;",
+ " private Provider<String> sProvider;",
"",
- " private Provider<String> stringProvider() {",
- " Object local = sProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " sProvider = (Provider<String>) local;",
- " }",
- " return (Provider<String>) local;",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.sProvider = new SwitchingProvider<>(testComponent, 0);",
" }",
"",
" @Override",
" public Provider<Object> objectProvider() {",
- " return (Provider) stringProvider();",
+ " return ((Provider) sProvider);",
" }",
"",
" @Override",
" public Provider<CharSequence> charSequenceProvider() {",
- " return (Provider) stringProvider();",
+ " return ((Provider) sProvider);",
" }",
"",
- " private final class SwitchingProvider<T> implements Provider<T> {",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
" switch (id) {",
- " case 0:",
- " return (T) TestModule_SFactory.s();",
- " default:",
- " throw new AssertionError(id);",
+ " case 0: return (T) TestModule_SFactory.s();",
+ " default: throw new AssertionError(id);",
" }",
" }",
" }",
@@ -334,47 +328,32 @@ public class SwitchingProviderTest {
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerTestComponent implements TestComponent {",
- " private volatile Object charSequence = new MemoizedSentinel();",
- " private volatile Provider<CharSequence> cProvider;",
+ " private Provider<String> sProvider;",
+ " private Provider<CharSequence> cProvider;",
"",
- " private CharSequence charSequence() {",
- " Object local = charSequence;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = charSequence;",
- " if (local instanceof MemoizedSentinel) {",
- " local = TestModule_SFactory.s();",
- " charSequence = DoubleCheck.reentrantCheck(charSequence, local);",
- " }",
- " }",
- " }",
- " return (CharSequence) local;",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.sProvider = new SwitchingProvider<>(testComponent, 0);",
+ " this.cProvider = DoubleCheck.provider((Provider) sProvider);",
" }",
"",
" @Override",
" public Provider<Object> objectProvider() {",
- " return (Provider) charSequenceProvider();",
+ " return ((Provider) cProvider);",
" }",
"",
" @Override",
" public Provider<CharSequence> charSequenceProvider() {",
- " Object local = cProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " cProvider = (Provider<CharSequence>) local;",
- " }",
- " return (Provider<CharSequence>) local;",
+ " return cProvider;",
" }",
"",
- " private final class SwitchingProvider<T> implements Provider<T> {",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
" switch (id) {",
- " case 0:",
- " return (T) DaggerTestComponent.this.charSequence();",
- " default:",
- " throw new AssertionError(id);",
+ " case 0: return (T) TestModule_SFactory.s();",
+ " default: throw new AssertionError(id);",
" }",
" }",
" }",
@@ -544,24 +523,18 @@ public class SwitchingProviderTest {
" @SuppressWarnings(\"rawtypes\")",
" private static final Provider ABSENT_JDK_OPTIONAL_PROVIDER =",
" InstanceFactory.create(Optional.empty());",
- "",
- " private volatile Provider<Optional<Present>> optionalOfPresentProvider;",
- "",
+ " private Provider<Optional<Present>> optionalOfPresentProvider;",
" private Provider<Optional<Absent>> optionalOfAbsentProvider;",
"",
" @SuppressWarnings(\"unchecked\")",
" private void initialize() {",
+ " this.optionalOfPresentProvider = new SwitchingProvider<>(testComponent, 0);",
" this.optionalOfAbsentProvider = absentJdkOptionalProvider();",
" }",
"",
" @Override",
" public Provider<Optional<Present>> providerOfOptionalOfPresent() {",
- " Object local = optionalOfPresentProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " optionalOfPresentProvider = (Provider<Optional<Present>>) local;",
- " }",
- " return (Provider<Optional<Present>>) local;",
+ " return optionalOfPresentProvider;",
" }",
"",
" @Override",
@@ -571,20 +544,18 @@ public class SwitchingProviderTest {
"",
" private static <T> Provider<Optional<T>> absentJdkOptionalProvider() {",
" @SuppressWarnings(\"unchecked\")",
- " Provider<Optional<T>> provider = ",
- " (Provider<Optional<T>>) ABSENT_JDK_OPTIONAL_PROVIDER;",
+ " Provider<Optional<T>> provider =",
+ " (Provider<Optional<T>>) ABSENT_JDK_OPTIONAL_PROVIDER;",
" return provider;",
" }",
"",
- " private final class SwitchingProvider<T> implements Provider<T> {",
+ " private static final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
" switch (id) {",
- " case 0: // java.util.Optional<test.Present>",
- " return (T) Optional.of(TestModule_PFactory.p());",
- " default:",
- " throw new AssertionError(id);",
+ " case 0: return (T) Optional.of(TestModule_PFactory.p());",
+ " default: throw new AssertionError(id);",
" }",
" }",
" }",
@@ -592,8 +563,6 @@ public class SwitchingProviderTest {
}
private Compiler compilerWithAndroidMode() {
- return javac()
- .withProcessors(new ComponentProcessor())
- .withOptions(CompilerMode.FAST_INIT_MODE.javacopts());
+ return compilerWithOptions(CompilerMode.FAST_INIT_MODE.javacopts());
}
}
diff --git a/javatests/dagger/internal/codegen/UnresolvableDependencyTest.java b/javatests/dagger/internal/codegen/UnresolvableDependencyTest.java
new file mode 100644
index 000000000..4a2ff98d0
--- /dev/null
+++ b/javatests/dagger/internal/codegen/UnresolvableDependencyTest.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.testing.compile.CompilationSubject.assertThat;
+import static dagger.internal.codegen.Compilers.compilerWithOptions;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+import static java.util.stream.Collectors.joining;
+
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class UnresolvableDependencyTest {
+
+ @Test
+ public void referencesUnresolvableDependency() {
+ JavaFileObject fooComponent =
+ JavaFileObjects.forSourceLines(
+ "test.FooComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface FooComponent {",
+ " Foo foo();",
+ "}");
+
+ JavaFileObject foo =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Foo {",
+ " @Inject",
+ " Foo(Bar bar) {}",
+ "}");
+
+ JavaFileObject bar =
+ JavaFileObjects.forSourceLines(
+ "test.Bar",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Bar {",
+ " @Inject",
+ " Bar(UnresolvableDependency dep) {}",
+ "}");
+
+ Compilation compilation = daggerCompiler().compile(fooComponent, foo, bar);
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(3);
+ assertThat(compilation).hadErrorContaining(
+ "cannot find symbol"
+ + "\n symbol: class UnresolvableDependency"
+ + "\n location: class test.Bar");
+ String trace = "\n "
+ + "\n Dependency trace:"
+ + "\n => element (CLASS): test.Bar"
+ + "\n => element (CONSTRUCTOR): Bar(UnresolvableDependency)"
+ + "\n => type (EXECUTABLE constructor): (UnresolvableDependency)void"
+ + "\n => type (ERROR parameter type): UnresolvableDependency";
+ assertThat(compilation).hadErrorContaining(
+ "InjectProcessingStep was unable to process 'Bar(UnresolvableDependency)' because "
+ + "'UnresolvableDependency' could not be resolved." + trace);
+ assertThat(compilation).hadErrorContaining(
+ "ComponentProcessingStep was unable to process 'test.FooComponent' because "
+ + "'UnresolvableDependency' could not be resolved." + trace);
+
+ // Only include a minimal portion of the stacktrace to minimize breaking tests due to refactors.
+ String stacktraceErrorMessage =
+ "dagger.internal.codegen.base"
+ + ".DaggerSuperficialValidation$ValidationException$KnownErrorType";
+
+ // Check that the stacktrace is not included in the error message by default.
+ assertThat(
+ compilation.errors().stream()
+ .map(error -> error.getMessage(null))
+ .collect(joining("\n")))
+ .doesNotContain(stacktraceErrorMessage);
+
+ // Recompile with the option enabled and check that the stacktrace is now included
+ compilation =
+ compilerWithOptions("-Adagger.includeStacktraceWithDeferredErrorMessages=ENABLED")
+ .compile(fooComponent, foo, bar);
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(3);
+ assertThat(compilation).hadErrorContaining(stacktraceErrorMessage);
+ }
+
+ @Test
+ public void referencesUnresolvableAnnotationOnType() {
+ JavaFileObject fooComponent =
+ JavaFileObjects.forSourceLines(
+ "test.FooComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface FooComponent {",
+ " Foo foo();",
+ "}");
+
+ JavaFileObject foo =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Foo {",
+ " @Inject",
+ " Foo(Bar bar) {}",
+ "}");
+
+ JavaFileObject bar =
+ JavaFileObjects.forSourceLines(
+ "test.Bar",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "@UnresolvableAnnotation",
+ "class Bar {",
+ " @Inject",
+ " Bar(String dep) {}",
+ "}");
+
+ Compilation compilation = daggerCompiler().compile(fooComponent, foo, bar);
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(3);
+ assertThat(compilation).hadErrorContaining(
+ "cannot find symbol"
+ + "\n symbol: class UnresolvableAnnotation");
+ String trace = "\n "
+ + "\n Dependency trace:"
+ + "\n => element (CLASS): test.Bar"
+ + "\n => annotation: @UnresolvableAnnotation"
+ + "\n => type (ERROR annotation type): UnresolvableAnnotation";
+ assertThat(compilation).hadErrorContaining(
+ "InjectProcessingStep was unable to process 'Bar(java.lang.String)' because "
+ + "'UnresolvableAnnotation' could not be resolved." + trace);
+ assertThat(compilation).hadErrorContaining(
+ "ComponentProcessingStep was unable to process 'test.FooComponent' because "
+ + "'UnresolvableAnnotation' could not be resolved." + trace);
+ }
+
+ @Test
+ public void referencesUnresolvableAnnotationOnTypeOnParameter() {
+ JavaFileObject fooComponent =
+ JavaFileObjects.forSourceLines(
+ "test.FooComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface FooComponent {",
+ " Foo foo();",
+ "}");
+
+ JavaFileObject foo =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Foo {",
+ " @Inject",
+ " Foo(Bar bar) {}",
+ "}");
+
+ JavaFileObject bar =
+ JavaFileObjects.forSourceLines(
+ "test.Bar",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Bar {",
+ " @Inject",
+ " Bar(@UnresolvableAnnotation String dep) {}",
+ "}");
+
+ Compilation compilation = daggerCompiler().compile(fooComponent, foo, bar);
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(3);
+ assertThat(compilation).hadErrorContaining(
+ "cannot find symbol"
+ + "\n symbol: class UnresolvableAnnotation"
+ + "\n location: class test.Bar");
+ String trace = "\n "
+ + "\n Dependency trace:"
+ + "\n => element (CLASS): test.Bar"
+ + "\n => element (CONSTRUCTOR): Bar(java.lang.String)"
+ + "\n => element (PARAMETER): dep"
+ + "\n => annotation: @UnresolvableAnnotation"
+ + "\n => type (ERROR annotation type): UnresolvableAnnotation";
+ assertThat(compilation).hadErrorContaining(
+ "InjectProcessingStep was unable to process 'Bar(java.lang.String)' because "
+ + "'UnresolvableAnnotation' could not be resolved." + trace);
+ assertThat(compilation).hadErrorContaining(
+ "ComponentProcessingStep was unable to process 'test.FooComponent' because "
+ + "'UnresolvableAnnotation' could not be resolved." + trace);
+ }
+}
diff --git a/javatests/dagger/internal/codegen/ValidationReportTest.java b/javatests/dagger/internal/codegen/ValidationReportTest.java
index d1c3a2e3c..0e49d300b 100644
--- a/javatests/dagger/internal/codegen/ValidationReportTest.java
+++ b/javatests/dagger/internal/codegen/ValidationReportTest.java
@@ -18,15 +18,17 @@ package dagger.internal.codegen;
import static com.google.common.truth.Truth.assertThat;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static com.google.testing.compile.Compiler.javac;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
import dagger.internal.codegen.validation.ValidationReport;
-import dagger.internal.codegen.validation.ValidationReport.Builder;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.TypeElement;
import javax.tools.JavaFileObject;
@@ -37,45 +39,42 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class ValidationReportTest {
private static final JavaFileObject TEST_CLASS_FILE =
- JavaFileObjects.forSourceLines("test.TestClass",
+ JavaFileObjects.forSourceLines(
+ "test.TestClass",
"package test;",
"",
"final class TestClass {}");
@Test
public void basicReport() {
- Compilation compilation =
- javac()
- .withProcessors(
- new SimpleTestProcessor() {
- @Override
- void test() {
- Builder<TypeElement> reportBuilder =
- ValidationReport.about(getTypeElement("test.TestClass"));
- reportBuilder.addError("simple error");
- reportBuilder.build().printMessagesTo(processingEnv.getMessager());
- }
- })
- .compile(TEST_CLASS_FILE);
+ Processor processor =
+ new SimpleTestProcessor() {
+ @Override
+ void test() {
+ ValidationReport.about(getTypeElement("test.TestClass"))
+ .addError("simple error")
+ .build()
+ .printMessagesTo(processingEnv.getMessager());
+ }
+ };
+ Compilation compilation = daggerCompiler(processor).compile(TEST_CLASS_FILE);
assertThat(compilation).failed();
assertThat(compilation).hadErrorContaining("simple error").inFile(TEST_CLASS_FILE).onLine(3);
}
@Test
public void messageOnDifferentElement() {
- Compilation compilation =
- javac()
- .withProcessors(
- new SimpleTestProcessor() {
- @Override
- void test() {
- Builder<TypeElement> reportBuilder =
- ValidationReport.about(getTypeElement("test.TestClass"));
- reportBuilder.addError("simple error", getTypeElement(String.class));
- reportBuilder.build().printMessagesTo(processingEnv.getMessager());
- }
- })
- .compile(TEST_CLASS_FILE);
+ Processor processor =
+ new SimpleTestProcessor() {
+ @Override
+ void test() {
+ ValidationReport.about(getTypeElement("test.TestClass"))
+ .addError("simple error", getTypeElement(String.class))
+ .build()
+ .printMessagesTo(processingEnv.getMessager());
+ }
+ };
+ Compilation compilation = daggerCompiler(processor).compile(TEST_CLASS_FILE);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining("[java.lang.String] simple error")
@@ -85,29 +84,30 @@ public class ValidationReportTest {
@Test
public void subreport() {
- Compilation compilation =
- javac()
- .withProcessors(
- new SimpleTestProcessor() {
- @Override
- void test() {
- Builder<TypeElement> reportBuilder =
- ValidationReport.about(getTypeElement("test.TestClass"));
- reportBuilder.addError("simple error");
- ValidationReport<TypeElement> parentReport =
- ValidationReport.about(getTypeElement(String.class))
- .addSubreport(reportBuilder.build())
- .build();
- assertThat(parentReport.isClean()).isFalse();
- parentReport.printMessagesTo(processingEnv.getMessager());
- }
- })
- .compile(TEST_CLASS_FILE);
+ Processor processor =
+ new SimpleTestProcessor() {
+ @Override
+ void test() {
+ ValidationReport parentReport =
+ ValidationReport.about(getTypeElement(String.class))
+ .addSubreport(
+ ValidationReport.about(getTypeElement("test.TestClass"))
+ .addError("simple error")
+ .build())
+ .build();
+ assertThat(parentReport.isClean()).isFalse();
+ parentReport.printMessagesTo(processingEnv.getMessager());
+ }
+ };
+ Compilation compilation = daggerCompiler(processor).compile(TEST_CLASS_FILE);
assertThat(compilation).failed();
assertThat(compilation).hadErrorContaining("simple error").inFile(TEST_CLASS_FILE).onLine(3);
}
- private static abstract class SimpleTestProcessor extends AbstractProcessor {
+ private abstract static class SimpleTestProcessor extends AbstractProcessor {
+ @SuppressWarnings("HidingField") // Subclasses should always use the XProcessing version.
+ protected XProcessingEnv processingEnv;
+
@Override
public Set<String> getSupportedAnnotationTypes() {
return ImmutableSet.of("*");
@@ -115,16 +115,17 @@ public class ValidationReportTest {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ processingEnv = XProcessingEnv.create(super.processingEnv);
test();
return false;
}
- protected final TypeElement getTypeElement(Class<?> clazz) {
+ protected final XTypeElement getTypeElement(Class<?> clazz) {
return getTypeElement(clazz.getCanonicalName());
}
- protected final TypeElement getTypeElement(String canonicalName) {
- return processingEnv.getElementUtils().getTypeElement(canonicalName);
+ protected final XTypeElement getTypeElement(String canonicalName) {
+ return processingEnv.requireTypeElement(canonicalName);
}
abstract void test();
diff --git a/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD b/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD
index 551e09139..9e7b1a424 100644
--- a/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD
+++ b/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD
@@ -28,10 +28,10 @@ GenJavaTests(
deps = [
"//java/dagger/internal/codegen/bindinggraphvalidation",
"//javatests/dagger/internal/codegen:compilers",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/compile_testing",
+ "//third_party/java/javapoet",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/internal/codegen/bindinggraphvalidation/SetMultibindingValidationTest.java b/javatests/dagger/internal/codegen/bindinggraphvalidation/SetMultibindingValidationTest.java
new file mode 100644
index 000000000..bc8b0c6ad
--- /dev/null
+++ b/javatests/dagger/internal/codegen/bindinggraphvalidation/SetMultibindingValidationTest.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2021 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.bindinggraphvalidation;
+
+import static com.google.testing.compile.CompilationSubject.assertThat;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class SetMultibindingValidationTest {
+ private static final JavaFileObject FOO =
+ JavaFileObjects.forSourceLines(
+ "test.Foo",
+ "package test;",
+ "",
+ "public interface Foo {}");
+
+ private static final JavaFileObject FOO_IMPL =
+ JavaFileObjects.forSourceLines(
+ "test.FooImpl",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public final class FooImpl implements Foo {",
+ " @Inject FooImpl() {}",
+ "}");
+
+ @Test public void testMultipleSetBindingsToSameFoo() {
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Binds;",
+ "import dagger.multibindings.IntoSet;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "interface TestModule {",
+ " @Binds @IntoSet Foo bindFoo(FooImpl impl);",
+ "",
+ " @Binds @IntoSet Foo bindFooAgain(FooImpl impl);",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " Set<Foo> setOfFoo();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(FOO, FOO_IMPL, module, component);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "Multiple set contributions into Set<Foo> for the same contribution key: FooImpl");
+ }
+
+ @Test public void testMultipleSetBindingsToSameFooThroughMultipleBinds() {
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Binds;",
+ "import dagger.multibindings.IntoSet;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "interface TestModule {",
+ " @Binds @IntoSet Object bindObject(FooImpl impl);",
+ "",
+ " @Binds @IntoSet Object bindObjectAgain(Foo impl);",
+ "",
+ " @Binds Foo bindFoo(FooImpl impl);",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " Set<Object> setOfObject();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(FOO, FOO_IMPL, module, component);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "Multiple set contributions into Set<Object> for the same contribution key: FooImpl");
+ }
+
+ @Test public void testMultipleSetBindingsViaElementsIntoSet() {
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Binds;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.ElementsIntoSet;",
+ "import java.util.HashSet;",
+ "import java.util.Set;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Qualifier;",
+ "",
+ "@dagger.Module",
+ "interface TestModule {",
+ "",
+ " @Qualifier",
+ " @interface Internal {}",
+ "",
+ " @Provides @Internal static Set<Foo> provideSet() { return new HashSet<>(); }",
+ "",
+ " @Binds @ElementsIntoSet Set<Foo> bindSet(@Internal Set<Foo> fooSet);",
+ "",
+ " @Binds @ElementsIntoSet Set<Foo> bindSetAgain(@Internal Set<Foo> fooSet);",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " Set<Foo> setOfFoo();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(FOO, module, component);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "Multiple set contributions into Set<Foo> for the same contribution key: "
+ + "@TestModule.Internal Set<Foo>");
+ }
+
+ @Test public void testMultipleSetBindingsToSameFooSubcomponents() {
+ JavaFileObject parentModule = JavaFileObjects.forSourceLines("test.ParentModule",
+ "package test;",
+ "",
+ "import dagger.Binds;",
+ "import dagger.multibindings.IntoSet;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "interface ParentModule {",
+ " @Binds @IntoSet Foo bindFoo(FooImpl impl);",
+ "}");
+ JavaFileObject childModule = JavaFileObjects.forSourceLines("test.ChildModule",
+ "package test;",
+ "",
+ "import dagger.Binds;",
+ "import dagger.multibindings.IntoSet;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "interface ChildModule {",
+ " @Binds @IntoSet Foo bindFoo(FooImpl impl);",
+ "}");
+ JavaFileObject parentComponent = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "",
+ "@Component(modules = ParentModule.class)",
+ "interface ParentComponent {",
+ " Set<Foo> setOfFoo();",
+ " ChildComponent child();",
+ "}");
+ JavaFileObject childComponent = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent(modules = ChildModule.class)",
+ "interface ChildComponent {",
+ " Set<Foo> setOfFoo();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(
+ FOO, FOO_IMPL, parentModule, childModule, parentComponent, childComponent);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "Multiple set contributions into Set<Foo> for the same contribution key: FooImpl");
+ assertThat(compilation)
+ .hadErrorContaining(
+ "ParentComponent → ChildComponent");
+ }
+
+ @Test public void testMultipleSetBindingsToSameKeyButDifferentBindings() {
+ // Use an impl with local multibindings to create different bindings. We still want this to fail
+ // even though there are separate bindings because it is likely an unintentional error anyway.
+ JavaFileObject fooImplWithMult = JavaFileObjects.forSourceLines("test.FooImplWithMult",
+ "package test;",
+ "",
+ "import java.util.Set;",
+ "import javax.inject.Inject;",
+ "",
+ "public final class FooImplWithMult implements Foo {",
+ " @Inject FooImplWithMult(Set<Long> longSet) {}",
+ "}");
+ // Scoping the @Binds is necessary to ensure it goes to different bindings
+ JavaFileObject parentModule = JavaFileObjects.forSourceLines("test.ParentModule",
+ "package test;",
+ "",
+ "import dagger.Binds;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Singleton;",
+ "",
+ "@dagger.Module",
+ "interface ParentModule {",
+ " @Singleton",
+ " @Binds @IntoSet Foo bindFoo(FooImplWithMult impl);",
+ "",
+ " @Provides @IntoSet static Long provideLong() {",
+ " return 0L;",
+ " }",
+ "}");
+ JavaFileObject childModule = JavaFileObjects.forSourceLines("test.ChildModule",
+ "package test;",
+ "",
+ "import dagger.Binds;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "interface ChildModule {",
+ " @Binds @IntoSet Foo bindFoo(FooImplWithMult impl);",
+ "",
+ " @Provides @IntoSet static Long provideLong() {",
+ " return 1L;",
+ " }",
+ "}");
+ JavaFileObject parentComponent = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "@Component(modules = ParentModule.class)",
+ "interface ParentComponent {",
+ " Set<Foo> setOfFoo();",
+ " ChildComponent child();",
+ "}");
+ JavaFileObject childComponent = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent(modules = ChildModule.class)",
+ "interface ChildComponent {",
+ " Set<Foo> setOfFoo();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(
+ FOO, fooImplWithMult, parentModule, childModule, parentComponent, childComponent);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "Multiple set contributions into Set<Foo> for the same contribution key: "
+ + "FooImplWithMult");
+ assertThat(compilation)
+ .hadErrorContaining(
+ "ParentComponent → ChildComponent");
+ }
+}
diff --git a/javatests/dagger/internal/codegen/javapoet/BUILD b/javatests/dagger/internal/codegen/javapoet/BUILD
index 438d3779b..b108d6ee9 100644
--- a/javatests/dagger/internal/codegen/javapoet/BUILD
+++ b/javatests/dagger/internal/codegen/javapoet/BUILD
@@ -28,10 +28,10 @@ GenJavaTests(
deps = [
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/langmodel",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "@maven//:com_google_auto_auto_common",
+ "//third_party/java/auto:common",
+ "//third_party/java/compile_testing",
+ "//third_party/java/javapoet",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/internal/codegen/javapoet/ExpressionTest.java b/javatests/dagger/internal/codegen/javapoet/ExpressionTest.java
index acfa46081..8360a1bf9 100644
--- a/javatests/dagger/internal/codegen/javapoet/ExpressionTest.java
+++ b/javatests/dagger/internal/codegen/javapoet/ExpressionTest.java
@@ -18,8 +18,9 @@ package dagger.internal.codegen.javapoet;
import static com.google.common.truth.Truth.assertThat;
-import com.google.auto.common.MoreTypes;
import com.google.testing.compile.CompilationRule;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.TypeName;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
import javax.lang.model.type.PrimitiveType;
@@ -70,11 +71,10 @@ public class ExpressionTest {
Expression boxedExpression = primitiveExpression.box(types);
assertThat(boxedExpression.codeBlock().toString()).isEqualTo("(java.lang.Integer) 5");
- assertThat(MoreTypes.equivalence().equivalent(boxedExpression.type(), type(Integer.class)))
- .isTrue();
+ assertThat(TypeName.get(boxedExpression.type())).isEqualTo(TypeName.get(type(Integer.class)));
}
private TypeMirror type(Class<?> clazz) {
- return elements.getTypeElement(clazz).asType();
+ return elements.getTypeElement(ClassName.get(clazz)).asType();
}
}
diff --git a/javatests/dagger/internal/codegen/validation/BUILD b/javatests/dagger/internal/codegen/validation/BUILD
index 03fd684d1..6271768cf 100644
--- a/javatests/dagger/internal/codegen/validation/BUILD
+++ b/javatests/dagger/internal/codegen/validation/BUILD
@@ -27,7 +27,7 @@ GenJavaTests(
javacopts = DOCLINT_HTML_AND_SYNTAX,
deps = [
"//java/dagger/internal/codegen/validation",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/lint/BUILD b/javatests/dagger/lint/BUILD
index 268340d5e..a2026c91b 100644
--- a/javatests/dagger/lint/BUILD
+++ b/javatests/dagger/lint/BUILD
@@ -23,7 +23,7 @@ kt_jvm_test(
name = "DaggerKotlinIssueDetectorTest",
srcs = ["DaggerKotlinIssueDetectorTest.kt"],
deps = [
- "@google_bazel_common//third_party/java/junit",
+ "//third_party/java/junit",
"//java/dagger/lint:lint-artifact-lib",
"@maven//:com_android_tools_lint_lint_checks",
"@maven//:com_android_tools_lint_lint_tests",
diff --git a/javatests/dagger/lint/DaggerKotlinIssueDetectorTest.kt b/javatests/dagger/lint/DaggerKotlinIssueDetectorTest.kt
index f11239234..e1976998f 100644
--- a/javatests/dagger/lint/DaggerKotlinIssueDetectorTest.kt
+++ b/javatests/dagger/lint/DaggerKotlinIssueDetectorTest.kt
@@ -16,6 +16,7 @@
package dagger.lint
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestMode
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test
@@ -183,6 +184,8 @@ class DaggerKotlinIssueDetectorTest : LintDetectorTest() {
).indented()
)
.allowCompilationErrors(false)
+ // Unlikely that @JvmStatic would be aliased, so skipping these modes.
+ .skipTestModes(TestMode.TYPE_ALIAS, TestMode.IMPORT_ALIAS)
.run()
.expect(
"""
diff --git a/javatests/dagger/producers/BUILD b/javatests/dagger/producers/BUILD
index 9404d85ac..f8b098efe 100644
--- a/javatests/dagger/producers/BUILD
+++ b/javatests/dagger/producers/BUILD
@@ -31,12 +31,12 @@ GenJavaTests(
functional = 0,
javacopts = SOURCE_7_TARGET_7 + DOCLINT_REFERENCES + DOCLINT_HTML_AND_SYNTAX,
deps = [
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
"//java/dagger/producers",
- "@google_bazel_common//third_party/java/guava:testlib",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/mockito",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/guava:testlib",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/util/concurrent",
+ "//third_party/java/junit",
+ "//third_party/java/mockito",
+ "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/spi/BUILD b/javatests/dagger/spi/BUILD
index 849037b6f..ef1dca040 100644
--- a/javatests/dagger/spi/BUILD
+++ b/javatests/dagger/spi/BUILD
@@ -32,13 +32,13 @@ GenJavaTests(
deps = [
"//java/dagger:core",
"//java/dagger/internal/codegen:processor",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
"//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "//third_party/java/auto:service",
+ "//third_party/java/compile_testing",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
],
)
diff --git a/test_defs.bzl b/test_defs.bzl
index 6f2308877..cdb9f51cf 100644
--- a/test_defs.bzl
+++ b/test_defs.bzl
@@ -19,7 +19,9 @@ load("@rules_java//java:defs.bzl", "java_library", "java_test")
# Defines a set of build variants and the list of extra javacopts to build with.
# The key will be appended to the generated test names to ensure uniqueness.
BUILD_VARIANTS = {
+ "Shards": ["-Adagger.keysPerComponentShard=2"],
"FastInit": ["-Adagger.fastInit=enabled"],
+ "FastInit_Shards": ["-Adagger.fastInit=enabled", "-Adagger.keysPerComponentShard=2"],
}
# TODO(ronshapiro): convert this to use bazel_common
@@ -106,6 +108,7 @@ def _GenTests(
if functional:
for (variant_name, extra_javacopts) in BUILD_VARIANTS.items():
variant_javacopts = (javacopts or []) + extra_javacopts
+
_gen_tests(
library_rule_type,
test_rule_type,
diff --git a/third_party/java/asm/BUILD b/third_party/java/asm/BUILD
new file mode 100644
index 000000000..bebdb1216
--- /dev/null
+++ b/third_party/java/asm/BUILD
@@ -0,0 +1,32 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for http://asm.ow2.org/
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "asm",
+ actual = "@maven//:org_ow2_asm_asm",
+)
+
+alias(
+ name = "asm-tree",
+ actual = "@maven//:org_ow2_asm_asm_tree",
+)
+
+alias(
+ name = "asm-commons",
+ actual = "@maven//:org_ow2_asm_asm_commons",
+)
diff --git a/third_party/java/auto/BUILD b/third_party/java/auto/BUILD
new file mode 100644
index 000000000..7b90e287e
--- /dev/null
+++ b/third_party/java/auto/BUILD
@@ -0,0 +1,113 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/google/auto
+
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "common",
+ actual = "@maven//:com_google_auto_auto_common",
+)
+
+java_plugin(
+ name = "auto_value_processor",
+ processor_class = "com.google.auto.value.processor.AutoValueProcessor",
+ visibility = ["//visibility:private"],
+ deps = [
+ ":common",
+ ":service",
+ "//third_party/java/guava",
+ "@maven//:com_google_auto_value_auto_value",
+ ],
+)
+
+java_plugin(
+ name = "auto_annotation_processor",
+ processor_class = "com.google.auto.value.processor.AutoAnnotationProcessor",
+ visibility = ["//visibility:private"],
+ deps = [
+ ":common",
+ ":service",
+ "//third_party/java/guava",
+ "@maven//:com_google_auto_value_auto_value",
+ ],
+)
+
+java_plugin(
+ name = "auto_oneof_processor",
+ processor_class = "com.google.auto.value.processor.AutoOneOfProcessor",
+ visibility = ["//visibility:private"],
+ deps = [
+ ":common",
+ ":service",
+ "//third_party/java/guava",
+ "@maven//:com_google_auto_value_auto_value",
+ ],
+)
+
+java_library(
+ name = "value",
+ exported_plugins = [
+ ":auto_annotation_processor",
+ ":auto_oneof_processor",
+ ":auto_value_processor",
+ ],
+ tags = ["maven:compile_only"],
+ exports = [
+ "@maven//:com_google_auto_value_auto_value_annotations",
+ ],
+)
+
+java_plugin(
+ name = "auto_factory_processor",
+ generates_api = 1,
+ processor_class = "com.google.auto.factory.processor.AutoFactoryProcessor",
+ visibility = ["//visibility:private"],
+ deps = [
+ ":common",
+ ":service",
+ "//third_party/java/google_java_format",
+ "//third_party/java/guava",
+ "//third_party/java/javapoet",
+ "@maven//:com_google_auto_factory_auto_factory",
+ ],
+)
+
+java_library(
+ name = "factory",
+ exported_plugins = [":auto_factory_processor"],
+ exports = ["@maven//:com_google_auto_factory_auto_factory"],
+)
+
+java_plugin(
+ name = "auto_service_processor",
+ processor_class = "com.google.auto.service.processor.AutoServiceProcessor",
+ visibility = ["//visibility:private"],
+ deps = [
+ ":common",
+ "//third_party/java/guava",
+ "@maven//:com_google_auto_service_auto_service",
+ "@maven//:com_google_auto_service_auto_service_annotations",
+ ],
+)
+
+java_library(
+ name = "service",
+ exported_plugins = [":auto_service_processor"],
+ tags = ["maven:compile_only"],
+ exports = ["@maven//:com_google_auto_service_auto_service_annotations"],
+)
diff --git a/third_party/java/byte_buddy/BUILD b/third_party/java/byte_buddy/BUILD
new file mode 100644
index 000000000..062e3cae0
--- /dev/null
+++ b/third_party/java/byte_buddy/BUILD
@@ -0,0 +1,23 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/mockito/mockito
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "byte_buddy",
+ testonly = 1,
+ actual = "@maven//:net_bytebuddy_byte_buddy",
+)
diff --git a/third_party/java/byte_buddy_agent/BUILD b/third_party/java/byte_buddy_agent/BUILD
new file mode 100644
index 000000000..942078ccd
--- /dev/null
+++ b/third_party/java/byte_buddy_agent/BUILD
@@ -0,0 +1,23 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/mockito/mockito
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "byte_buddy_agent",
+ testonly = 1,
+ actual = "@maven//:net_bytebuddy_byte_buddy_agent",
+)
diff --git a/third_party/java/checker_framework/BUILD b/third_party/java/checker_framework/BUILD
new file mode 100644
index 000000000..01f3d7044
--- /dev/null
+++ b/third_party/java/checker_framework/BUILD
@@ -0,0 +1,28 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://checkerframework.org/
+
+load("@rules_java//java:defs.bzl", "java_library")
+
+package(default_visibility = ["//:src"])
+
+java_library(
+ name = "dataflow",
+ exports = ["@maven//:org_checkerframework_dataflow"],
+ runtime_deps = [
+ "@maven//:org_checkerframework_checker_qual",
+ "@maven//:org_checkerframework_javacutil",
+ ],
+)
diff --git a/third_party/java/checker_framework_annotations/BUILD b/third_party/java/checker_framework_annotations/BUILD
new file mode 100644
index 000000000..5fd74bbb0
--- /dev/null
+++ b/third_party/java/checker_framework_annotations/BUILD
@@ -0,0 +1,22 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://checkerframework.org/
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "checker_framework_annotations",
+ actual = "@maven//:org_checkerframework_checker_compat_qual",
+)
diff --git a/third_party/java/compile_testing/BUILD b/third_party/java/compile_testing/BUILD
new file mode 100644
index 000000000..8aff4a474
--- /dev/null
+++ b/third_party/java/compile_testing/BUILD
@@ -0,0 +1,34 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/google/compile-testing
+
+load("@rules_java//java:defs.bzl", "java_library")
+
+package(default_visibility = ["//:src"])
+
+java_library(
+ name = "compile_testing",
+ testonly = 1,
+ exports = ["@maven//:com_google_testing_compile_compile_testing"],
+ runtime_deps = [
+ "//third_party/java/auto:value",
+ "//third_party/java/error_prone:annotations",
+ "//third_party/java/guava",
+ "//third_party/java/jsr305_annotations",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ "@local_jdk//:lib/tools.jar",
+ ],
+)
diff --git a/third_party/java/diffutils/BUILD b/third_party/java/diffutils/BUILD
new file mode 100644
index 000000000..711ff69ac
--- /dev/null
+++ b/third_party/java/diffutils/BUILD
@@ -0,0 +1,22 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/google/truth
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "diffutils",
+ actual = "@maven//:com_googlecode_java_diff_utils_diffutils",
+)
diff --git a/third_party/java/error_prone/BUILD b/third_party/java/error_prone/BUILD
new file mode 100644
index 000000000..26a9682e3
--- /dev/null
+++ b/third_party/java/error_prone/BUILD
@@ -0,0 +1,47 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/google/error-prone. Note that Bazel already
+# applies the Error Prone compiler to all java compilations - this package exports
+# dependencies for Error Prone's libraries
+
+load("@rules_java//java:defs.bzl", "java_library")
+
+package(default_visibility = ["//:src"])
+
+java_library(
+ name = "annotations",
+ tags = ["maven:compile_only"],
+ exports = ["@maven//:com_google_errorprone_error_prone_annotations"],
+)
+
+alias(
+ name = "error_prone_javac",
+ actual = "@maven//:com_google_errorprone_javac_shaded",
+)
+
+java_library(
+ name = "check_api",
+ exports = [
+ "@maven//:com_google_errorprone_error_prone_annotation",
+ "@maven//:com_google_errorprone_error_prone_check_api",
+ ],
+ runtime_deps = [
+ ":annotations",
+ ":error_prone_javac",
+ "//third_party/java/checker_framework:dataflow",
+ "//third_party/java/diffutils",
+ "//third_party/java/jsr305_annotations",
+ ],
+)
diff --git a/third_party/java/google_java_format/BUILD b/third_party/java/google_java_format/BUILD
new file mode 100644
index 000000000..c2313d905
--- /dev/null
+++ b/third_party/java/google_java_format/BUILD
@@ -0,0 +1,30 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/google/google-java-format
+
+load("@rules_java//java:defs.bzl", "java_library")
+
+package(default_visibility = ["//:src"])
+
+java_library(
+ name = "google_java_format",
+ exports = [
+ "@maven//:com_google_googlejavaformat_google_java_format",
+ ],
+ runtime_deps = [
+ "//third_party/java/error_prone:error_prone_javac",
+ "//third_party/java/guava",
+ ],
+)
diff --git a/third_party/java/grpc/BUILD b/third_party/java/grpc/BUILD
new file mode 100644
index 000000000..e58da69db
--- /dev/null
+++ b/third_party/java/grpc/BUILD
@@ -0,0 +1,37 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/grpc/grpc-java
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "core",
+ actual = "@maven//:io_grpc_grpc_core",
+)
+
+alias(
+ name = "netty",
+ actual = "@maven//:io_grpc_grpc_netty",
+)
+
+alias(
+ name = "context",
+ actual = "@maven//:io_grpc_grpc_context",
+)
+
+alias(
+ name = "protobuf",
+ actual = "@maven//:io_grpc_grpc_protobuf",
+)
diff --git a/third_party/java/guava/BUILD b/third_party/java/guava/BUILD
new file mode 100644
index 000000000..bc3364b69
--- /dev/null
+++ b/third_party/java/guava/BUILD
@@ -0,0 +1,41 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/google/guava
+
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
+
+package(default_visibility = ["//:src"])
+
+java_library(
+ name = "guava",
+ exported_plugins = [":beta-checker"],
+ exports = [
+ "@maven//:com_google_guava_failureaccess",
+ "@maven//:com_google_guava_guava",
+ ],
+)
+
+java_library(
+ name = "testlib",
+ testonly = 1,
+ exports = ["@maven//:com_google_guava_guava_testlib"],
+ runtime_deps = [":guava"],
+)
+
+java_plugin(
+ name = "beta-checker",
+ visibility = ["//visibility:private"],
+ deps = ["@maven//:com_google_guava_guava_beta_checker"],
+)
diff --git a/third_party/java/guava/base/BUILD b/third_party/java/guava/base/BUILD
new file mode 100644
index 000000000..8ec4e6a6e
--- /dev/null
+++ b/third_party/java/guava/base/BUILD
@@ -0,0 +1,22 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/google/guava
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "base",
+ actual = "//third_party/java/guava",
+)
diff --git a/third_party/java/guava/cache/BUILD b/third_party/java/guava/cache/BUILD
new file mode 100644
index 000000000..8da3dfb27
--- /dev/null
+++ b/third_party/java/guava/cache/BUILD
@@ -0,0 +1,22 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/google/guava
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "cache",
+ actual = "//third_party/java/guava",
+)
diff --git a/third_party/java/guava/collect/BUILD b/third_party/java/guava/collect/BUILD
new file mode 100644
index 000000000..a90aceb30
--- /dev/null
+++ b/third_party/java/guava/collect/BUILD
@@ -0,0 +1,22 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/google/guava
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "collect",
+ actual = "//third_party/java/guava",
+)
diff --git a/third_party/java/guava/graph/BUILD b/third_party/java/guava/graph/BUILD
new file mode 100644
index 000000000..c77ca68c6
--- /dev/null
+++ b/third_party/java/guava/graph/BUILD
@@ -0,0 +1,22 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/google/guava
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "graph",
+ actual = "//third_party/java/guava",
+)
diff --git a/third_party/java/guava/io/BUILD b/third_party/java/guava/io/BUILD
new file mode 100644
index 000000000..ad6c7a25d
--- /dev/null
+++ b/third_party/java/guava/io/BUILD
@@ -0,0 +1,22 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/google/guava
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "io",
+ actual = "//third_party/java/guava",
+)
diff --git a/third_party/java/guava/util/concurrent/BUILD b/third_party/java/guava/util/concurrent/BUILD
new file mode 100644
index 000000000..00dd5ad34
--- /dev/null
+++ b/third_party/java/guava/util/concurrent/BUILD
@@ -0,0 +1,22 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/google/guava
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "concurrent",
+ actual = "//third_party/java/guava",
+)
diff --git a/third_party/java/hamcrest/BUILD b/third_party/java/hamcrest/BUILD
new file mode 100644
index 000000000..3ce9487f3
--- /dev/null
+++ b/third_party/java/hamcrest/BUILD
@@ -0,0 +1,23 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/hamcrest/JavaHamcrest
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "hamcrest",
+ testonly = 1,
+ actual = "@maven//:org_hamcrest_hamcrest_core",
+)
diff --git a/third_party/java/incap/BUILD b/third_party/java/incap/BUILD
new file mode 100644
index 000000000..7958754b3
--- /dev/null
+++ b/third_party/java/incap/BUILD
@@ -0,0 +1,35 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/tbroyer/gradle-incap-helper
+
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
+
+package(default_visibility = ["//:src"])
+
+java_library(
+ name = "incap",
+ exported_plugins = [":processor"],
+ exports = ["@maven//:net_ltgt_gradle_incap_incap"],
+)
+
+java_plugin(
+ name = "processor",
+ processor_class = "net.ltgt.gradle.incap.processor.IncrementalAnnotationProcessorProcessor",
+ visibility = ["//visibility:private"],
+ deps = [
+ "@maven//:net_ltgt_gradle_incap_incap",
+ "@maven//:net_ltgt_gradle_incap_incap_processor",
+ ],
+)
diff --git a/third_party/java/javapoet/BUILD b/third_party/java/javapoet/BUILD
new file mode 100644
index 000000000..7d056d76f
--- /dev/null
+++ b/third_party/java/javapoet/BUILD
@@ -0,0 +1,22 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/square/javapoet
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "javapoet",
+ actual = "@maven//:com_squareup_javapoet",
+)
diff --git a/third_party/java/jsr250_annotations/BUILD b/third_party/java/jsr250_annotations/BUILD
new file mode 100644
index 000000000..effdea892
--- /dev/null
+++ b/third_party/java/jsr250_annotations/BUILD
@@ -0,0 +1,22 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://en.wikipedia.org/wiki/JSR_250
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "jsr250_annotations",
+ actual = "@maven//:javax_annotation_jsr250_api",
+)
diff --git a/third_party/java/jsr305_annotations/BUILD b/third_party/java/jsr305_annotations/BUILD
new file mode 100644
index 000000000..3ae1825b0
--- /dev/null
+++ b/third_party/java/jsr305_annotations/BUILD
@@ -0,0 +1,22 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://jcp.org/en/jsr/detail?id=305
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "jsr305_annotations",
+ actual = "@maven//:com_google_code_findbugs_jsr305",
+)
diff --git a/third_party/java/jsr330_inject/BUILD b/third_party/java/jsr330_inject/BUILD
new file mode 100644
index 000000000..c8603b7d1
--- /dev/null
+++ b/third_party/java/jsr330_inject/BUILD
@@ -0,0 +1,27 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for javax.inject (https://www.jcp.org/en/jsr/detail?id=330)
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "jsr330_inject",
+ actual = "@maven//:javax_inject_javax_inject",
+)
+
+alias(
+ name = "tck",
+ actual = "@maven//:javax_inject_javax_inject_tck",
+)
diff --git a/third_party/java/junit/BUILD b/third_party/java/junit/BUILD
new file mode 100644
index 000000000..e40e2f74d
--- /dev/null
+++ b/third_party/java/junit/BUILD
@@ -0,0 +1,26 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/junit-team
+
+load("@rules_java//java:defs.bzl", "java_library")
+
+package(default_visibility = ["//:src"])
+
+java_library(
+ name = "junit",
+ testonly = 1,
+ exports = ["@maven//:junit_junit"],
+ runtime_deps = ["//third_party/java/hamcrest"],
+)
diff --git a/third_party/java/mockito/BUILD b/third_party/java/mockito/BUILD
new file mode 100644
index 000000000..d940443e5
--- /dev/null
+++ b/third_party/java/mockito/BUILD
@@ -0,0 +1,31 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/mockito/mockito
+
+load("@rules_java//java:defs.bzl", "java_library")
+
+package(default_visibility = ["//:src"])
+
+java_library(
+ name = "mockito",
+ testonly = 1,
+ exports = ["@maven//:org_mockito_mockito_core"],
+ runtime_deps = [
+ "//third_party/java/byte_buddy",
+ "//third_party/java/byte_buddy_agent",
+ "//third_party/java/hamcrest",
+ "//third_party/java/objenesis",
+ ],
+)
diff --git a/third_party/java/objenesis/BUILD b/third_party/java/objenesis/BUILD
new file mode 100644
index 000000000..68ea07d99
--- /dev/null
+++ b/third_party/java/objenesis/BUILD
@@ -0,0 +1,23 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/mockito/mockito
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "objenesis",
+ testonly = 1,
+ actual = "@maven//:org_objenesis_objenesis",
+)
diff --git a/third_party/java/protobuf/BUILD b/third_party/java/protobuf/BUILD
new file mode 100644
index 000000000..b06ee12ef
--- /dev/null
+++ b/third_party/java/protobuf/BUILD
@@ -0,0 +1,22 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/google/protobuf/tree/master/java
+
+package(default_visibility = ["//:src"])
+
+alias(
+ name = "protobuf",
+ actual = "@maven//:com_google_protobuf_protobuf_java",
+)
diff --git a/third_party/java/truth/BUILD b/third_party/java/truth/BUILD
new file mode 100644
index 000000000..73eb05f3c
--- /dev/null
+++ b/third_party/java/truth/BUILD
@@ -0,0 +1,33 @@
+# Copyright (C) 2021 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BUILD rules for https://github.com/google/truth
+
+load("@rules_java//java:defs.bzl", "java_library")
+
+package(default_visibility = ["//:src"])
+
+java_library(
+ name = "truth",
+ testonly = 1,
+ exports = [
+ "@maven//:com_google_truth_extensions_truth_java8_extension",
+ "@maven//:com_google_truth_truth",
+ ],
+ # TODO(cpovirk): This would make more sense in deps, but Bazel won't allow
+ # that unless we add dummy srcs.
+ runtime_deps = [
+ "//third_party/java/asm",
+ ],
+)
diff --git a/tools/bazel_compat.bzl b/tools/bazel_compat.bzl
new file mode 100644
index 000000000..e9354da65
--- /dev/null
+++ b/tools/bazel_compat.bzl
@@ -0,0 +1,65 @@
+# Copyright (C) 202 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Macros for building with Bazel.
+"""
+
+load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_android_library")
+
+def compat_kt_android_library(name, **kwargs):
+ bazel_kt_android_library(name, kwargs)
+
+def bazel_kt_android_library(name, kwargs):
+ """A macro that wraps Bazel's kt_android_library.
+
+ This macro wraps Bazel's kt_android_library to output the jars files
+ in the expected locations (b/203519416). It also adds a dependency on
+ kotlin_stdlib if there are kotlin sources.
+
+ Args:
+ name: the name of the library.
+ kwargs: Additional arguments of the library.
+ """
+
+ # If there are any kotlin sources, add the kotlin_stdlib, otherwise
+ # java-only projects may be missing a required runtime dependency on it.
+ if any([src.endswith(".kt") for src in kwargs.get("srcs", [])]):
+ # Add the kotlin_stdlib, otherwise it will be missing from java-only projects.
+ # We use deps rather than exports because exports isn't picked up by the pom file.
+ # See https://github.com/google/dagger/issues/3119
+ required_deps = ["@maven//:org_jetbrains_kotlin_kotlin_stdlib"]
+ kwargs["deps"] = kwargs.get("deps", []) + required_deps
+
+ # TODO(b/203519416): Bazel's kt_android_library outputs its jars under a target
+ # suffixed with "_kt". Thus, we have to do a bit of name aliasing to ensure that
+ # the jars exist at the expected targets.
+ kt_android_library(
+ name = "{}_internal".format(name),
+ **kwargs
+ )
+
+ native.alias(
+ name = name,
+ actual = ":{}_internal_kt".format(name),
+ )
+
+ native.alias(
+ name = "lib{}.jar".format(name),
+ actual = ":{}_internal_kt.jar".format(name),
+ )
+
+ native.alias(
+ name = "lib{}-src.jar".format(name),
+ actual = ":{}_internal_kt-sources.jar".format(name),
+ )
diff --git a/tools/maven.bzl b/tools/maven.bzl
index 2c648a218..f842c88ac 100644
--- a/tools/maven.bzl
+++ b/tools/maven.bzl
@@ -74,7 +74,6 @@ def gen_maven_artifact(
javadoc_exclude_packages,
javadoc_android_api_level,
shaded_deps,
- shaded_rules,
manifest,
lint_deps,
proguard_specs
@@ -96,7 +95,6 @@ def _gen_maven_artifact(
javadoc_exclude_packages,
javadoc_android_api_level,
shaded_deps,
- shaded_rules,
manifest,
lint_deps,
proguard_specs):
@@ -131,7 +129,6 @@ def _gen_maven_artifact(
javadoc_exclude_packages: The packages to exclude from the javadocs.
javadoc_android_api_level: The android api level for the javadocs.
shaded_deps: The shaded deps for the jarjar.
- shaded_rules: The shaded rules for the jarjar.
manifest: The AndroidManifest.xml to bundle in when packaing an 'aar'.
lint_deps: The lint targets to be bundled in when packaging an 'aar'.
proguard_specs: The proguard spec files to be bundled in when packaging an 'aar'
@@ -148,7 +145,6 @@ def _gen_maven_artifact(
)
shaded_deps = shaded_deps or []
- shaded_rules = shaded_rules or []
artifact_targets = [artifact_target] + (artifact_target_libs or [])
lint_deps = lint_deps or []
@@ -172,7 +168,6 @@ def _gen_maven_artifact(
name = name + "-classes",
testonly = testonly,
jars = artifact_targets + shaded_deps,
- rules = shaded_rules,
merge_meta_inf_files = merge_meta_inf_files,
)
if lint_deps:
@@ -217,7 +212,6 @@ def _gen_maven_artifact(
name = name,
testonly = testonly,
jars = artifact_targets + shaded_deps,
- rules = shaded_rules,
merge_meta_inf_files = merge_meta_inf_files,
)
diff --git a/tools/shader/build.gradle b/tools/shader/build.gradle
new file mode 100644
index 000000000..2d1bc18d0
--- /dev/null
+++ b/tools/shader/build.gradle
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.jar.Manifest;
+import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer
+import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
+import shadow.org.apache.tools.zip.ZipOutputStream
+import shadow.org.apache.tools.zip.ZipEntry
+
+plugins {
+ id 'java-library'
+ // Use shadow version >= 7.1.1 to get log4j vulnerability patches:
+ // https://github.com/johnrengelman/shadow/releases/tag/7.1.1
+ id 'com.github.johnrengelman.shadow' version '7.1.1'
+}
+
+repositories {
+ mavenCentral()
+ mavenLocal()
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+}
+
+// This transformation makes sure the input jar's MANIFEST.MF properties,
+// such as "Created-by:" get merged into the final artifact jar (although it's
+// not clear how necessary this is).
+/** A transform that merges in the MANIFEST.MF files from the inputJar. */
+class ManifestMerger implements Transformer {
+ private static final String MANIFEST_MF = "META-INF/MANIFEST.MF";
+
+ private Manifest manifest;
+
+ @Override
+ boolean canTransformResource(FileTreeElement element) {
+ return MANIFEST_MF.equalsIgnoreCase(element.relativePath.pathString);
+ }
+
+ @Override
+ void transform(TransformerContext context) {
+ if (manifest == null) {
+ manifest = new Manifest(context.is);
+ } else {
+ Manifest toMerge = new Manifest(context.is);
+ manifest.getMainAttributes()
+ .putAll(toMerge.getMainAttributes().entrySet());
+ manifest.getEntries().putAll(toMerge.getEntries().entrySet());
+ }
+ }
+
+ @Override
+ boolean hasTransformedResource() { true }
+
+ @Override
+ void modifyOutputStream(
+ ZipOutputStream os, boolean preserveFileTimestamps) {
+ os.putNextEntry(new ZipEntry(MANIFEST_MF));
+ if (manifest != null) {
+ ByteArrayOutputStream content = new ByteArrayOutputStream();
+ manifest.write(content);
+ os.write(content.toByteArray());
+ }
+ }
+}
+
+configurations {
+ shaded
+}
+
+shadowJar {
+ archiveClassifier = "" // postfix for output jar
+ configurations = [project.configurations.shaded]
+ transform(ManifestMerger.class)
+
+ // Add a 'relocate' declaration for each shaded rule.
+ // Format: "key1,value1;key2,value2;key3,value3"
+ def rules = project.getProperty("shadedRules").split(";")
+ for (def i = 0; i < rules.size(); i++) {
+ def rule = rules[i].split(",")
+ relocate "${rule[0]}", "${rule[1]}"
+ }
+}
+
+dependencies {
+ shaded files(project.getProperty("inputJar"))
+}
diff --git a/java/dagger/hilt/android/example/gradle/simple/gradle/wrapper/gradle-wrapper.jar b/tools/shader/gradle/wrapper/gradle-wrapper.jar
index 5c2d1cf01..5c2d1cf01 100644
--- a/java/dagger/hilt/android/example/gradle/simple/gradle/wrapper/gradle-wrapper.jar
+++ b/tools/shader/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/java/dagger/hilt/android/example/gradle/simple/gradle/wrapper/gradle-wrapper.properties b/tools/shader/gradle/wrapper/gradle-wrapper.properties
index 4d9ca1649..0f80bbf51 100644
--- a/java/dagger/hilt/android/example/gradle/simple/gradle/wrapper/gradle-wrapper.properties
+++ b/tools/shader/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/java/dagger/hilt/android/example/gradle/simple/gradlew b/tools/shader/gradlew
index b0d6d0ab5..b0d6d0ab5 100755
--- a/java/dagger/hilt/android/example/gradle/simple/gradlew
+++ b/tools/shader/gradlew
diff --git a/util/deploy-all.sh b/util/deploy-all.sh
new file mode 100755
index 000000000..a3febb8d0
--- /dev/null
+++ b/util/deploy-all.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -eu
+
+bash $(dirname $0)/deploy-dagger.sh "$@"
+
+bash $(dirname $0)/deploy-hilt.sh "$@"
+
+bash $(dirname $0)/deploy-hilt-gradle-plugin.sh "$@" \ No newline at end of file
diff --git a/util/deploy-dagger.sh b/util/deploy-dagger.sh
index ddf492659..2806047a3 100755
--- a/util/deploy-dagger.sh
+++ b/util/deploy-dagger.sh
@@ -14,114 +14,145 @@ readonly EXTRA_MAVEN_ARGS=("$@")
# parameter, if provided then javadoc must also be provided.
# @param {string} javadoc the java doc jar of the library. This is an optional
# parameter, if provided then srcjar must also be provided.
+# @param {string} module_name the JPMS module name to include in the jar. This
+# is an optional parameter and can only be used with jar files.
_deploy() {
- local library=$1
- local pomfile=$2
- local srcjar=$3
- local javadoc=$4
+ local shaded_rules=$1
+ local library=$2
+ local pomfile=$3
+ local srcjar=$4
+ local javadoc=$5
+ local module_name=$6
bash $(dirname $0)/deploy-library.sh \
+ "$shaded_rules" \
"$library" \
"$pomfile" \
"$srcjar" \
"$javadoc" \
+ "$module_name" \
"$MVN_GOAL" \
"$VERSION_NAME" \
"${EXTRA_MAVEN_ARGS[@]:+${EXTRA_MAVEN_ARGS[@]}}"
}
_deploy \
+ "" \
java/dagger/libcore.jar \
java/dagger/pom.xml \
java/dagger/libcore-src.jar \
- java/dagger/core-javadoc.jar
+ java/dagger/core-javadoc.jar \
+ "dagger"
_deploy \
+ "" \
gwt/libgwt.jar \
gwt/pom.xml \
gwt/libgwt.jar \
- gwt/libgwt.jar
+ gwt/libgwt.jar \
+ ""
+# This artifact uses the shaded classes from dagger-spi, so we use the same
+# shading rules so that our references to those classes are shaded the same way.
_deploy \
+ "com.google.auto.common,dagger.spi.shaded.auto.common;androidx.room.compiler.processing,dagger.spi.shaded.androidx.room.compiler.processing" \
java/dagger/internal/codegen/artifact.jar \
java/dagger/internal/codegen/pom.xml \
java/dagger/internal/codegen/artifact-src.jar \
- java/dagger/internal/codegen/artifact-javadoc.jar
+ java/dagger/internal/codegen/artifact-javadoc.jar \
+ ""
_deploy \
+ "" \
java/dagger/producers/artifact.jar \
java/dagger/producers/pom.xml \
java/dagger/producers/artifact-src.jar \
- java/dagger/producers/artifact-javadoc.jar
+ java/dagger/producers/artifact-javadoc.jar \
+ ""
_deploy \
+ "com.google.auto.common,dagger.spi.shaded.auto.common;androidx.room.compiler.processing,dagger.spi.shaded.androidx.room.compiler.processing" \
java/dagger/spi/artifact.jar \
java/dagger/spi/pom.xml \
java/dagger/spi/artifact-src.jar \
- java/dagger/spi/artifact-javadoc.jar
+ java/dagger/spi/artifact-javadoc.jar \
+ ""
_deploy \
+ "" \
java/dagger/android/android.aar \
java/dagger/android/pom.xml \
java/dagger/android/libandroid-src.jar \
- java/dagger/android/android-javadoc.jar
+ java/dagger/android/android-javadoc.jar \
+ ""
_deploy \
+ "" \
java/dagger/android/android-legacy.aar \
java/dagger/android/legacy-pom.xml \
"" \
+ "" \
""
-# b/37741866 and https://github.com/google/dagger/issues/715
-_deploy \
- java/dagger/android/libandroid.jar \
- java/dagger/android/jarimpl-pom.xml \
- java/dagger/android/libandroid-src.jar \
- java/dagger/android/android-javadoc.jar
-
_deploy \
+ "" \
java/dagger/android/support/support.aar \
java/dagger/android/support/pom.xml \
java/dagger/android/support/libsupport-src.jar \
- java/dagger/android/support/support-javadoc.jar
+ java/dagger/android/support/support-javadoc.jar \
+ ""
_deploy \
+ "" \
java/dagger/android/support/support-legacy.aar \
java/dagger/android/support/legacy-pom.xml \
"" \
+ "" \
""
_deploy \
+ "" \
shaded_android_processor.jar \
java/dagger/android/processor/pom.xml \
java/dagger/android/processor/libprocessor-src.jar \
- java/dagger/android/processor/processor-javadoc.jar
+ java/dagger/android/processor/processor-javadoc.jar \
+ ""
_deploy \
+ "" \
java/dagger/grpc/server/libserver.jar \
java/dagger/grpc/server/server-pom.xml \
java/dagger/grpc/server/libserver-src.jar \
- java/dagger/grpc/server/javadoc.jar
+ java/dagger/grpc/server/javadoc.jar \
+ ""
_deploy \
+ "" \
java/dagger/grpc/server/libannotations.jar \
java/dagger/grpc/server/annotations-pom.xml \
java/dagger/grpc/server/libannotations-src.jar \
- java/dagger/grpc/server/javadoc.jar
+ java/dagger/grpc/server/javadoc.jar \
+ ""
_deploy \
+ "" \
shaded_grpc_server_processor.jar \
java/dagger/grpc/server/processor/pom.xml \
java/dagger/grpc/server/processor/libprocessor-src.jar \
- java/dagger/grpc/server/processor/javadoc.jar
+ java/dagger/grpc/server/processor/javadoc.jar \
+ ""
_deploy \
+ "" \
java/dagger/lint/lint-artifact.jar \
java/dagger/lint/lint-pom.xml \
java/dagger/lint/lint-artifact-src.jar \
- java/dagger/lint/lint-artifact-javadoc.jar
+ java/dagger/lint/lint-artifact-javadoc.jar \
+ ""
_deploy \
+ "" \
java/dagger/lint/lint-android-artifact.aar \
java/dagger/lint/lint-android-pom.xml \
"" \
+ "" \
""
diff --git a/util/deploy-hilt-gradle-plugin.sh b/util/deploy-hilt-gradle-plugin.sh
new file mode 100755
index 000000000..203049434
--- /dev/null
+++ b/util/deploy-hilt-gradle-plugin.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+set -eu
+
+readonly MVN_GOAL="$1"
+readonly VERSION_NAME="$2"
+shift 2
+readonly EXTRA_MAVEN_ARGS=("$@")
+
+# Builds and deploy the Gradle plugin.
+_deploy_plugin() {
+ local plugindir=java/dagger/hilt/android/plugin
+ ./$plugindir/gradlew -p $plugindir --no-daemon clean \
+ publishAllPublicationsToMavenRepository -PPublishVersion="$VERSION_NAME"
+ local outdir=$plugindir/build/repo/com/google/dagger/hilt-android-gradle-plugin/$VERSION_NAME
+ local markerOutDir=$plugindir/build/repo/com/google/dagger/hilt/android/com.google.dagger.hilt.android.gradle.plugin/$VERSION_NAME
+ # When building '-SNAPSHOT' versions in gradle, the filenames replaces
+ # '-SNAPSHOT' with timestamps, so we need to disambiguate by finding each file
+ # to deploy. See: https://stackoverflow.com/questions/54182823/
+ local suffix
+ if [[ "$VERSION_NAME" == *"-SNAPSHOT" ]]; then
+ # Gets the timestamp part out of the name to be used as suffix.
+ # Timestamp format is ########.######-#.
+ suffix=$(find $outdir -name "*.pom" | grep -Eo '[0-9]{8}\.[0-9]{6}-[0-9]{1}')
+ else
+ suffix=$VERSION_NAME
+ fi
+ mvn "$MVN_GOAL" \
+ -Dfile="$(find $outdir -name "*-$suffix.jar")" \
+ -DpomFile="$(find $outdir -name "*-$suffix.pom")" \
+ -Dsources="$(find $outdir -name "*-$suffix-sources.jar")" \
+ -Djavadoc="$(find $outdir -name "*-$suffix-javadoc.jar")" \
+ "${EXTRA_MAVEN_ARGS[@]:+${EXTRA_MAVEN_ARGS[@]}}"
+ mvn "$MVN_GOAL" \
+ -Dfile="$(find $markerOutDir -name "*-$suffix.pom")" \
+ -DpomFile="$(find $markerOutDir -name "*-$suffix.pom")" \
+ "${EXTRA_MAVEN_ARGS[@]:+${EXTRA_MAVEN_ARGS[@]}}"
+}
+
+# Gradle Plugin is built with Gradle, but still deployed via Maven (mvn)
+_deploy_plugin \ No newline at end of file
diff --git a/util/deploy-hilt.sh b/util/deploy-hilt.sh
index 3c25c10b7..325ef13f2 100755
--- a/util/deploy-hilt.sh
+++ b/util/deploy-hilt.sh
@@ -14,75 +14,63 @@ readonly EXTRA_MAVEN_ARGS=("$@")
# parameter, if provided then javadoc must also be provided.
# @param {string} javadoc the java doc jar of the library. This is an optional
# parameter, if provided then srcjar must also be provided.
+# @param {string} module_name the JPMS module name to include in the jar. This
+# is an optional parameter and can only be used with jar files.
_deploy() {
- local library=$1
- local pomfile=$2
- local srcjar=$3
- local javadoc=$4
+ local shaded_rules=$1
+ local library=$2
+ local pomfile=$3
+ local srcjar=$4
+ local javadoc=$5
+ local module_name=$6
bash $(dirname $0)/deploy-library.sh \
+ "$shaded_rules" \
"$library" \
"$pomfile" \
"$srcjar" \
"$javadoc" \
+ "$module_name" \
"$MVN_GOAL" \
"$VERSION_NAME" \
"${EXTRA_MAVEN_ARGS[@]:+${EXTRA_MAVEN_ARGS[@]}}"
}
_deploy \
+ "" \
java/dagger/hilt/android/artifact.aar \
java/dagger/hilt/android/pom.xml \
java/dagger/hilt/android/artifact-src.jar \
- java/dagger/hilt/android/artifact-javadoc.jar
+ java/dagger/hilt/android/artifact-javadoc.jar \
+ ""
_deploy \
+ "" \
java/dagger/hilt/android/testing/artifact.aar \
java/dagger/hilt/android/testing/pom.xml \
java/dagger/hilt/android/testing/artifact-src.jar \
- java/dagger/hilt/android/testing/artifact-javadoc.jar
+ java/dagger/hilt/android/testing/artifact-javadoc.jar \
+ ""
_deploy \
+ "com.google.auto.common,dagger.hilt.android.shaded.auto.common" \
java/dagger/hilt/processor/artifact.jar \
java/dagger/hilt/processor/pom.xml \
java/dagger/hilt/processor/artifact-src.jar \
- java/dagger/hilt/processor/artifact-javadoc.jar
+ java/dagger/hilt/processor/artifact-javadoc.jar \
+ ""
_deploy \
+ "com.google.auto.common,dagger.hilt.android.shaded.auto.common" \
java/dagger/hilt/android/processor/artifact.jar \
java/dagger/hilt/android/processor/pom.xml \
java/dagger/hilt/android/processor/artifact-src.jar \
- java/dagger/hilt/android/processor/artifact-javadoc.jar
+ java/dagger/hilt/android/processor/artifact-javadoc.jar \
+ ""
_deploy \
+ "" \
java/dagger/hilt/artifact-core.jar \
java/dagger/hilt/pom.xml \
java/dagger/hilt/artifact-core-src.jar \
- java/dagger/hilt/artifact-core-javadoc.jar
-
-# Builds and deploy the Gradle plugin.
-_deploy_plugin() {
- local plugindir=java/dagger/hilt/android/plugin
- ./$plugindir/gradlew -p $plugindir --no-daemon clean \
- publishAllPublicationsToMavenRepository -PPublishVersion="$VERSION_NAME"
- local outdir=$plugindir/build/repo/com/google/dagger/hilt-android-gradle-plugin/$VERSION_NAME
- # When building '-SNAPSHOT' versions in gradle, the filenames replaces
- # '-SNAPSHOT' with timestamps, so we need to disambiguate by finding each file
- # to deploy. See: https://stackoverflow.com/questions/54182823/
- local suffix
- if [[ "$VERSION_NAME" == *"-SNAPSHOT" ]]; then
- # Gets the timestamp part out of the name to be used as suffix.
- # Timestamp format is ########.######-#.
- suffix=$(find $outdir -name "*.pom" | grep -Eo '[0-9]{8}\.[0-9]{6}-[0-9]{1}')
- else
- suffix=$VERSION_NAME
- fi
- mvn "$MVN_GOAL" \
- -Dfile="$(find $outdir -name "*-$suffix.jar")" \
- -DpomFile="$(find $outdir -name "*-$suffix.pom")" \
- -Dsources="$(find $outdir -name "*-$suffix-sources.jar")" \
- -Djavadoc="$(find $outdir -name "*-$suffix-javadoc.jar")" \
- "${EXTRA_MAVEN_ARGS[@]:+${EXTRA_MAVEN_ARGS[@]}}"
-}
-
-# Gradle Plugin is built with Gradle, but still deployed via Maven (mvn)
-_deploy_plugin
+ java/dagger/hilt/artifact-core-javadoc.jar \
+ ""
diff --git a/util/deploy-library.sh b/util/deploy-library.sh
index a744402ba..02962946d 100755
--- a/util/deploy-library.sh
+++ b/util/deploy-library.sh
@@ -9,18 +9,29 @@ set -eu
# parameter, if provided then javadoc must also be provided.
# @param {string} javadoc the java doc jar of the library. This is an optional
# parameter, if provided then srcjar must also be provided.
+# @param {string} module_name the JPMS module name to include in the jar. This
+# is an optional parameter and can only be used with jar files.
deploy_library() {
- local library=$1
- local pomfile=$2
- local srcjar=$3
- local javadoc=$4
- local mvn_goal=$5
- local version_name=$6
- shift 6
+ local shaded_rules=$1
+ local library=$2
+ local pomfile=$3
+ local srcjar=$4
+ local javadoc=$5
+ local module_name=$6
+ local mvn_goal=$7
+ local version_name=$8
+ shift 8
local extra_maven_args=("$@")
- bazel build --define=pom_version="$version_name" \
- $library $pomfile
+ bazel build --define=pom_version="$version_name" $library $pomfile
+
+ # Shade the library if shaded_rules exist
+ if [[ ! -z "$shaded_rules" ]]; then
+ bash $(dirname $0)/shade-library.sh \
+ $(bazel_output_file $library) $shaded_rules
+ # The output jar name is the same as the input library appended with -shaded
+ library="${library%.*}-shaded.${library##*.}"
+ fi
# TODO(bcorso): Consider moving this into the "gen_maven_artifact" macro, this
# requires having the version checked-in for the build system.
@@ -29,6 +40,12 @@ deploy_library() {
$(bazel_output_file $pomfile) \
$version_name
+ # TODO(bcorso): Consider moving this into the "gen_maven_artifact" macro once
+ # all our targets are using gen_maven_artifact
+ add_automatic_module_name_manifest_entry \
+ $(bazel_output_file $library) \
+ "${module_name}"
+
if [ -n "$srcjar" ] && [ -n "$javadoc" ] ; then
bazel build --define=pom_version="$version_name" \
$srcjar $javadoc
@@ -81,6 +98,22 @@ add_tracking_version() {
fi
}
+add_automatic_module_name_manifest_entry() {
+ local library=$1
+ local module_name=$2
+ if [ -n "$module_name" ] ; then
+ if [[ $library =~ \.jar$ ]]; then
+ local temp_dir=$(mktemp -d)
+ echo "Automatic-Module-Name: ${module_name}" > $temp_dir/module_name_file
+ # The "m" flag is specifically for adding manifest entries.
+ jar ufm $library $temp_dir/module_name_file
+ else
+ echo "Could not add module name to $library"
+ exit 1
+ fi
+ fi
+}
+
find_pom_value() {
local pomfile=$1
local attribute=$2
diff --git a/util/deploy-to-maven-central.sh b/util/deploy-to-maven-central.sh
index 1a71f5fed..0bf4b64cc 100755
--- a/util/deploy-to-maven-central.sh
+++ b/util/deploy-to-maven-central.sh
@@ -10,26 +10,22 @@ readonly KEY=$1
readonly VERSION_NAME=$2
shift 2
-if [[ ! "$VERSION_NAME" =~ ^2\. ]]; then
- echo 'Version name must begin with "2."'
- exit 2
+$(dirname $0)/validate-dagger-version.sh "$VERSION_NAME"
+
+BAZEL_VERSION=$(bazel --version)
+if [[ $BAZEL_VERSION != *"4.2.1"* ]]; then
+ echo "Must use Bazel version 4.2.1"
+ exit 4
fi
-if [[ "$VERSION_NAME" =~ " " ]]; then
- echo "Version name must not have any spaces"
- exit 3
+if [[ -z "${ANDROID_HOME}" ]]; then
+ echo "ANDROID_HOME environment variable must be set"
+ exit 5
fi
bash $(dirname $0)/run-local-tests.sh
-bash $(dirname $0)/deploy-dagger.sh \
- "gpg:sign-and-deploy-file" \
- "$VERSION_NAME" \
- "-DrepositoryId=sonatype-nexus-staging" \
- "-Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/" \
- "-Dgpg.keyname=${KEY}"
-
-bash $(dirname $0)/deploy-hilt.sh \
+bash $(dirname $0)/deploy-all.sh \
"gpg:sign-and-deploy-file" \
"$VERSION_NAME" \
"-DrepositoryId=sonatype-nexus-staging" \
@@ -39,30 +35,8 @@ bash $(dirname $0)/deploy-hilt.sh \
# Note: we detach from head before making any sed changes to avoid commiting
# a particular version to master.
git checkout --detach
-
-# Set the version string that is used as a tag in all of our libraries. If
-# another repo depends on a versioned tag of Dagger, their java_library.tags
-# should match the versioned release.
-sed -i s/'${project.version}'/"${VERSION_NAME}"/g build_defs.bzl
-
-# Note: We avoid commiting until after deploying in case deploying fails and
-# we need to run the script again.
-git commit -m "${VERSION_NAME} release" build_defs.bzl
-git tag -a -m "Dagger ${VERSION_NAME}" dagger-"${VERSION_NAME}"
-git push origin tag dagger-"${VERSION_NAME}"
-
+bash $(dirname $0)/publish-tagged-release.sh $VERSION_NAME
# Switch back to the original HEAD
git checkout -
-# Publish javadocs to gh-pages
-bazel build //:user-docs.jar
-git clone --quiet --branch gh-pages \
- https://github.com/google/dagger gh-pages > /dev/null
-cd gh-pages
-unzip ../bazel-bin/user-docs.jar -d api/$VERSION_NAME
-rm -rf api/$VERSION_NAME/META-INF/
-git add api/$VERSION_NAME
-git commit -m "$VERSION_NAME docs"
-git push origin gh-pages
-cd ..
-rm -rf gh-pages
+bash $(dirname $0)/publish-tagged-docs.sh $VERSION_NAME
diff --git a/util/install-local-snapshot.sh b/util/install-local-snapshot.sh
index be6030c74..2225e51d6 100755
--- a/util/install-local-snapshot.sh
+++ b/util/install-local-snapshot.sh
@@ -4,11 +4,7 @@ set -eu
echo -e "Installing maven snapshot locally...\n"
-bash $(dirname $0)/deploy-dagger.sh \
- "install:install-file" \
- "LOCAL-SNAPSHOT"
-
-bash $(dirname $0)/deploy-hilt.sh \
+bash $(dirname $0)/deploy-all.sh \
"install:install-file" \
"LOCAL-SNAPSHOT"
diff --git a/util/latest-dagger-version.sh b/util/latest-dagger-version.sh
new file mode 100755
index 000000000..55b3efde8
--- /dev/null
+++ b/util/latest-dagger-version.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+set -eu
+
+function github-rest-api {
+ local GITHUB_REST_API=$1
+
+ local GITHUB_API_HEADER_ACCEPT="Accept: application/vnd.github.v3+json"
+
+ curl -s $GITHUB_REST_API -H $GITHUB_API_HEADER_ACCEPT
+}
+
+function github-latest-release-tag {
+ local REPO_NAME=$1
+
+ # Grab the last two latest releases:
+ # (We skip the latest release if we haven't set release notes yet).
+ local RELEASE_API="https://api.github.com/repos/$REPO_NAME/releases?per_page=2"
+
+ # This gets the latest release info (as json) from github.
+ local RELEASE_JSON=$(github-rest-api $RELEASE_API)
+
+ # This pulls out the "body" from the json (i.e. the release notes)
+ local RELEASE_NOTES=$(echo $RELEASE_JSON | jq '.[0].body')
+
+ if [ "$RELEASE_NOTES" ]
+ then
+ # Return the latest release tag
+ echo $RELEASE_JSON | jq '.[0].tag_name'
+ else
+ # If there are no release notes in the latest release then we use the
+ # 2nd most latest version since we don't want to update the version until
+ # the release notes are set.
+ echo "Ignoring the latest release since the release notes have not been set."
+ echo "Using the previous release's version as latest."
+
+ # Return the 2nd most recent release tag
+ echo $RELEASE_JSON | jq '.[1].tag_name'
+ fi
+}
+
+function dagger-latest-release {
+ # Get the latest Dagger release tag, e.g. "dagger-2.31.2" or "dagger-2.32"
+ local DAGGER_RELEASE_TAG=$(github-latest-release-tag "google/dagger")
+
+ # Converts the "tag_name" to a version, e.g. "dagger-2.32" => "2.32"
+ echo $DAGGER_RELEASE_TAG | grep -oP "(?<=dagger-)\d+\.\d+(\.\d+)?"
+}
+
+type jq >/dev/null 2>&1 || {
+ echo >&2 "jq is not installed. Try 'sudo apt-get install jq'.";
+ exit 1;
+}
+
+dagger-latest-release
diff --git a/util/publish-snapshot-on-commit.sh b/util/publish-snapshot-on-commit.sh
deleted file mode 100755
index 63cc3eaa1..000000000
--- a/util/publish-snapshot-on-commit.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-# see https://coderwall.com/p/9b_lfq
-
-set -eux
-
-if [ "$GITHUB_REPOSITORY" == "google/dagger" ] && \
- [ "$GITHUB_EVENT_NAME" == "push" ] && \
- [ "$GITHUB_REF" == "refs/heads/master" ]; then
- echo -e "Publishing maven snapshot...\n"
-
- bash $(dirname $0)/deploy-dagger.sh \
- "deploy:deploy-file" \
- "HEAD-SNAPSHOT" \
- "-DrepositoryId=sonatype-nexus-snapshots" \
- "-Durl=https://oss.sonatype.org/content/repositories/snapshots" \
- "--settings=$(dirname $0)/settings.xml"
-
- bash $(dirname $0)/deploy-hilt.sh \
- "deploy:deploy-file" \
- "HEAD-SNAPSHOT" \
- "-DrepositoryId=sonatype-nexus-snapshots" \
- "-Durl=https://oss.sonatype.org/content/repositories/snapshots" \
- "--settings=$(dirname $0)/settings.xml"
-
- echo -e "Published maven snapshot"
-else
- echo -e "Not publishing snapshot for branch=${$GITHUB_REF}"
-fi
diff --git a/util/publish-tagged-docs.sh b/util/publish-tagged-docs.sh
new file mode 100755
index 000000000..8c5cddfa0
--- /dev/null
+++ b/util/publish-tagged-docs.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# TODO(bcorso): Consider sharing this script with utils/generate-latest-docs.sh
+
+set -eux
+
+if [ $# -lt 1 ]; then
+ echo "usage $0 <version-name>"
+ exit 1;
+fi
+readonly VERSION_NAME=$1
+shift 1
+
+$(dirname $0)/validate-dagger-version.sh "$VERSION_NAME"
+
+# Publish javadocs to gh-pages
+bazel build //:user-docs.jar
+
+# If a token exists, then use the token to clone the repo. This allows our
+# automated workflows to commit without manually authenticating.
+if [[ ! -z "$GH_TOKEN" ]]; then
+ git clone --quiet --branch=gh-pages https://x-access-token:${GH_TOKEN}@github.com/google/dagger gh-pages > /dev/null
+else
+ git clone --quiet --branch=gh-pages https://github.com/google/dagger gh-pages > /dev/null
+fi
+
+cd gh-pages
+unzip ../bazel-bin/user-docs.jar -d api/$VERSION_NAME
+rm -rf api/$VERSION_NAME/META-INF/
+git add api/$VERSION_NAME
+git commit -m "$VERSION_NAME docs"
+git push origin gh-pages
+cd ..
+rm -rf gh-pages
diff --git a/util/publish-tagged-release.sh b/util/publish-tagged-release.sh
new file mode 100755
index 000000000..11a131f50
--- /dev/null
+++ b/util/publish-tagged-release.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+set -eux
+
+if [ $# -lt 1 ]; then
+ echo "usage $0 <version-name>"
+ exit 1;
+fi
+readonly VERSION_NAME=$1
+shift 1
+
+$(dirname $0)/validate-dagger-version.sh "$VERSION_NAME"
+
+# Set the version string that is used as a tag in all of our libraries. If
+# another repo depends on a versioned tag of Dagger, their java_library.tags
+# should match the versioned release.
+sed -i s/'${project.version}'/"${VERSION_NAME}"/g build_defs.bzl
+
+# Note: We avoid commiting until after deploying in case deploying fails and
+# we need to run the script again.
+git commit -m "${VERSION_NAME} release" build_defs.bzl
+git tag -a -m "Dagger ${VERSION_NAME}" dagger-"${VERSION_NAME}"
+git push origin tag dagger-"${VERSION_NAME}"
diff --git a/util/run-local-emulator-tests.sh b/util/run-local-emulator-tests.sh
index 347a632af..30b31bedb 100755
--- a/util/run-local-emulator-tests.sh
+++ b/util/run-local-emulator-tests.sh
@@ -11,14 +11,8 @@ readonly GRADLE_PROJECTS=(
)
for project in "${GRADLE_PROJECTS[@]}"; do
echo "Running gradle Android emulator tests for $project"
- ./$project/gradlew -p $project connectedAndroidTest --continue --no-daemon --stacktrace
+ ./$project/gradlew -p $project connectedAndroidTest --continue --no-daemon --stacktrace --configuration-cache
done
-# Run emulator tests in a project with configuration cache enabled
-# TODO(danysantiago): Once AGP 4.2.0 is stable, remove these project and enable
-# config cache in the other test projects.
-readonly CONFIG_CACHE_PROJECT="javatests/artifacts/hilt-android/gradleConfigCache"
-./$CONFIG_CACHE_PROJECT/gradlew -p $CONFIG_CACHE_PROJECT connectedAndroidTest --continue --no-daemon --stacktrace --configuration-cache
-
# Close logcat
if [ -n "$LOGCAT_PID" ] ; then kill $LOGCAT_PID; fi
diff --git a/util/run-local-gradle-android-tests.sh b/util/run-local-gradle-android-tests.sh
index a9418a589..6ff9220a1 100755
--- a/util/run-local-gradle-android-tests.sh
+++ b/util/run-local-gradle-android-tests.sh
@@ -4,19 +4,20 @@ set -ex
readonly AGP_VERSION_INPUT=$1
readonly ANDROID_GRADLE_PROJECTS=(
- "java/dagger/example/gradle/android/simple"
"javatests/artifacts/dagger-android/simple"
"javatests/artifacts/hilt-android/simple"
"javatests/artifacts/hilt-android/simpleKotlin"
)
for project in "${ANDROID_GRADLE_PROJECTS[@]}"; do
echo "Running gradle tests for $project with AGP $AGP_VERSION_INPUT"
- AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project buildDebug --no-daemon --stacktrace
- AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project testDebug --continue --no-daemon --stacktrace
+ # Enable config cache if AGP is 4.2.0 or greater.
+ # Note that this is a lexicographical comparison.
+ if [[ "$AGP_VERSION_INPUT" > "4.1.0" ]]
+ then
+ CONFIG_CACHE_ARG="--configuration-cache"
+ else
+ CONFIG_CACHE_ARG=""
+ fi
+ AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project buildDebug --no-daemon --stacktrace $CONFIG_CACHE_ARG
+ AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project testDebug --continue --no-daemon --stacktrace $CONFIG_CACHE_ARG
done
-
-# Run gradle tests in a project with configuration cache enabled
-# TODO(danysantiago): Once AGP 4.2.0 is stable, remove these project and enable
-# config cache in the other test projects.
-readonly CONFIG_CACHE_PROJECT="javatests/artifacts/hilt-android/gradleConfigCache"
-./$CONFIG_CACHE_PROJECT/gradlew -p $CONFIG_CACHE_PROJECT assembleDebug --no-daemon --stacktrace --configuration-cache
diff --git a/util/run-local-gradle-tests.sh b/util/run-local-gradle-tests.sh
index 479158d8f..ecbbd352b 100755
--- a/util/run-local-gradle-tests.sh
+++ b/util/run-local-gradle-tests.sh
@@ -3,9 +3,8 @@
set -ex
readonly GRADLE_PROJECTS=(
- "java/dagger/example/gradle/simple"
- "java/dagger/hilt/android/plugin"
- "javatests/artifacts/dagger/simple"
+ "javatests/artifacts/dagger"
+ "javatests/artifacts/hilt-android/pluginMarker"
)
for project in "${GRADLE_PROJECTS[@]}"; do
echo "Running gradle tests for $project"
diff --git a/util/run-local-tests.sh b/util/run-local-tests.sh
index ea78671fe..3d7ba90ea 100755
--- a/util/run-local-tests.sh
+++ b/util/run-local-tests.sh
@@ -17,5 +17,7 @@ pushd examples/maven && mvn compile && popd
# Run local gradle tests
util/run-local-gradle-tests.sh
util/run-local-gradle-android-tests.sh "4.1.0"
-util/run-local-gradle-android-tests.sh "4.2.0-beta04"
+util/run-local-gradle-android-tests.sh "4.2.0"
+util/run-local-gradle-android-tests.sh "7.0.0"
+
diff --git a/util/settings.xml b/util/settings.xml
deleted file mode 100644
index 91f444b22..000000000
--- a/util/settings.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<settings>
- <servers>
- <server>
- <id>sonatype-nexus-snapshots</id>
- <username>${env.CI_DEPLOY_USERNAME}</username>
- <password>${env.CI_DEPLOY_PASSWORD}</password>
- </server>
- </servers>
-</settings>
diff --git a/util/shade-library.sh b/util/shade-library.sh
new file mode 100644
index 000000000..73767d63a
--- /dev/null
+++ b/util/shade-library.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+set -eux
+
+readonly INPUT_JAR=$1
+readonly SHADE_RULES=$2
+
+_shade_libary() {
+ local shader=$(dirname $0)/../tools/shader
+ local output="${INPUT_JAR%.*}-shaded.${INPUT_JAR##*.}"
+
+ ./$shader/gradlew -p $shader shadowJar \
+ -PinputJar="../../$INPUT_JAR" \
+ -PshadedRules=$SHADE_RULES
+
+ # Copy the shaded jar to the specified output
+ cp $shader/build/libs/shader.jar $output
+}
+
+_shade_libary
diff --git a/util/shasum.sh b/util/shasum.sh
new file mode 100755
index 000000000..a71c29878
--- /dev/null
+++ b/util/shasum.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -eu
+
+if [ $# -lt 1 ]; then
+ echo "usage $0 <version-name>"
+ exit 1;
+fi
+readonly VERSION_NAME=$1
+shift 1
+
+$(dirname $0)/validate-dagger-version.sh "$VERSION_NAME"
+
+pushd $(mktemp -d)
+wget https://github.com/google/dagger/archive/dagger-$VERSION_NAME.zip -P .
+OUTPUT=$(shasum -a 256 dagger-$VERSION_NAME.zip)
+echo "SHA sum: $OUTPUT"
+popd
diff --git a/util/validate-dagger-version.sh b/util/validate-dagger-version.sh
new file mode 100755
index 000000000..a595aba2a
--- /dev/null
+++ b/util/validate-dagger-version.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+set -eu
+
+if [ $# -lt 1 ]; then
+ echo "usage $0 <version-name>"
+ exit 1;
+fi
+readonly VERSION_NAME=$1
+shift 1
+
+if [[ ! "$VERSION_NAME" =~ ^2\. ]]; then
+ echo 'Version name must begin with "2."'
+ exit 2
+fi
+
+if [[ "$VERSION_NAME" =~ " " ]]; then
+ echo "Version name must not have any spaces"
+ exit 3
+fi
diff --git a/workspace_defs.bzl b/workspace_defs.bzl
index 2a63e433f..922978201 100644
--- a/workspace_defs.bzl
+++ b/workspace_defs.bzl
@@ -16,36 +16,43 @@
load("//:build_defs.bzl", "POM_VERSION")
-_DAGGER_VERSION = POM_VERSION
-_HILT_VERSION = POM_VERSION
+# For tagged releases, the POM_VERSION will be set to the version of the release.
+# However, for CI testing the POM_VERSION will not be set, so we use the
+# HEAD-SNAPSHOT artifacts instead.
+# TODO(bcorso): Ideally, we would use the LOCAL-SNAPSHOT artifacts for CI testing;
+# however, maven_install doesn't work with local maven repositories
+# (See issue: https://github.com/bazelbuild/rules_jvm_external/issues/305).
+_VERSION = POM_VERSION if POM_VERSION != "${project.version}" else "HEAD-SNAPSHOT"
DAGGER_ARTIFACTS = [
- "com.google.dagger:dagger:" + _DAGGER_VERSION,
- "com.google.dagger:dagger-compiler:" + _DAGGER_VERSION,
- "com.google.dagger:dagger-producers:" + _DAGGER_VERSION,
- "com.google.dagger:dagger-spi:" + _DAGGER_VERSION,
+ "com.google.dagger:dagger:" + _VERSION,
+ "com.google.dagger:dagger-compiler:" + _VERSION,
+ "com.google.dagger:dagger-producers:" + _VERSION,
+ "com.google.dagger:dagger-spi:" + _VERSION,
]
DAGGER_ANDROID_ARTIFACTS = [
- "com.google.dagger:dagger-android-processor:" + _DAGGER_VERSION,
- "com.google.dagger:dagger-android-support:" + _DAGGER_VERSION,
- "com.google.dagger:dagger-android:" + _DAGGER_VERSION,
+ "com.google.dagger:dagger-android-processor:" + _VERSION,
+ "com.google.dagger:dagger-android-support:" + _VERSION,
+ "com.google.dagger:dagger-android:" + _VERSION,
]
HILT_ANDROID_ARTIFACTS = [
"androidx.test:core:1.1.0", # Export for ApplicationProvider
"javax.annotation:jsr250-api:1.0", # Export for @Generated
"androidx.annotation:annotation:1.1.0", # Export for @CallSuper/@Nullable
- "com.google.dagger:dagger:" + _DAGGER_VERSION,
- "com.google.dagger:dagger-compiler:" + _DAGGER_VERSION,
- "com.google.dagger:hilt-android:" + _HILT_VERSION,
- "com.google.dagger:hilt-android-testing:" + _HILT_VERSION,
- "com.google.dagger:hilt-android-compiler:" + _HILT_VERSION,
+ "com.google.dagger:dagger:" + _VERSION,
+ "com.google.dagger:dagger-compiler:" + _VERSION,
+ "com.google.dagger:hilt-android:" + _VERSION,
+ "com.google.dagger:hilt-android-testing:" + _VERSION,
+ "com.google.dagger:hilt-android-compiler:" + _VERSION,
+ "com.google.dagger:hilt-core:" + _VERSION,
]
DAGGER_REPOSITORIES = [
"https://maven.google.com",
"https://repo1.maven.org/maven2",
+ "https://oss.sonatype.org/content/repositories/snapshots",
]
DAGGER_ANDROID_REPOSITORIES = DAGGER_REPOSITORIES
@@ -162,9 +169,11 @@ def hilt_android_rules(repo_name = "@maven"):
":hilt_aggregated_deps_processor",
":hilt_alias_of_processor",
":hilt_define_component_processor",
+ ":hilt_early_entry_points_processor",
":hilt_generates_root_input_processor",
":hilt_originating_element_processor",
":hilt_root_processor",
+ ":hilt_component_tree_deps_processor",
":hilt_view_model_processor",
],
visibility = ["//visibility:public"],
@@ -173,6 +182,7 @@ def hilt_android_rules(repo_name = "@maven"):
"%s//:javax_inject_javax_inject" % repo_name, # For @Inject
"%s//:androidx_annotation_annotation" % repo_name, # For @CallSuper
"%s//:com_google_dagger_hilt_android" % repo_name,
+ "%s//:com_google_dagger_hilt_core" % repo_name,
"%s//:javax_annotation_jsr250_api" % repo_name, # For @Generated
],
)
@@ -217,6 +227,13 @@ def hilt_android_rules(repo_name = "@maven"):
)
native.java_plugin(
+ name = "hilt_early_entry_points_processor",
+ generates_api = 1,
+ processor_class = "dagger.hilt.processor.internal.earlyentrypoint.EarlyEntryPointProcessor",
+ deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
+ )
+
+ native.java_plugin(
name = "hilt_generates_root_input_processor",
generates_api = 1,
processor_class = "dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputProcessor",
@@ -238,6 +255,13 @@ def hilt_android_rules(repo_name = "@maven"):
)
native.java_plugin(
+ name = "hilt_component_tree_deps_processor",
+ generates_api = 1,
+ processor_class = "dagger.hilt.processor.internal.root.ComponentTreeDepsProcessor",
+ deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
+ )
+
+ native.java_plugin(
name = "hilt_view_model_processor",
generates_api = 1,
processor_class = "dagger.hilt.android.processor.internal.viewmodel.ViewModelProcessor",
@@ -252,7 +276,6 @@ def hilt_android_rules(repo_name = "@maven"):
exported_plugins = [
":hilt_bind_value_processor",
":hilt_custom_test_application_processor",
- ":hilt_testroot_processor",
":hilt_uninstall_modules_processor",
],
visibility = ["//visibility:public"],
@@ -278,15 +301,8 @@ def hilt_android_rules(repo_name = "@maven"):
)
native.java_plugin(
- name = "hilt_testroot_processor",
- generates_api = 1,
- processor_class = "dagger.hilt.android.processor.internal.testroot.TestRootProcessor",
- deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
- )
-
- native.java_plugin(
name = "hilt_uninstall_modules_processor",
generates_api = 1,
- processor_class = "dagger.hilt.android.processor.internal.uninstallmodules.UninstallModulesProcessor",
+ processor_class = "dagger.hilt.processor.internal.uninstallmodules.UninstallModulesProcessor",
deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
)