aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Duffin <paulduffin@google.com>2015-11-23 13:25:38 +0000
committerPaul Duffin <paulduffin@google.com>2015-11-23 13:25:38 +0000
commit5d3207ac2713386ed61c6ca8f0356e8f093a62e1 (patch)
treeead40943ce4e8bab9226a970fe8d41084a811b85
parenta8fc7fd876069b857b985f63d491e1a8f22d0365 (diff)
downloaddagger2-5d3207ac2713386ed61c6ca8f0356e8f093a62e1.tar.gz
Added initial version of dagger2 from upstream
Bug: 24848946 Change-Id: I1b359bbbf8b07de1f84f3b7dfd263a58f0fd439b
-rw-r--r--.gitignore4
-rw-r--r--Android.mk88
-rw-r--r--CHANGELOG.md40
-rw-r--r--CONTRIBUTING.md37
-rw-r--r--LICENSE.txt202
-rw-r--r--MODULE_LICENSE_APACHE20
-rw-r--r--README.android8
-rw-r--r--README.md134
-rw-r--r--checkstyle.xml137
-rw-r--r--compiler/dependency-reduced-pom.xml204
-rw-r--r--compiler/pom.xml196
-rw-r--r--compiler/src/it/functional-tests/pom.xml98
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/A.java22
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/AbstractMembersInjectingBaseClass.java23
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/AbstractMiddleClassWithoutMembers.java20
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/B.java22
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/BasicAbstractClassComponent.java29
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/BasicComponent.java81
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/BooleanKey.java23
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/BoundedGenericComponent.java30
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/BoundedGenericModule.java81
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/BoundedGenerics.java41
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/ByteKey.java23
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/CharKey.java23
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/ChildDoubleModule.java21
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/ChildIntegerModule.java21
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/ComplexGenerics.java54
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/ComponentDependsOnGeneratedCode.java23
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/ComponentSupertypeDependsOnGeneratedCode.java22
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/ComponentSupertypeDependsOnGeneratedCodeInterface.java20
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/Generic.java26
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/Generic2.java26
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/GenericChild.java33
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/GenericComponent.java39
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/GenericDoubleReferences.java32
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/GenericNoDeps.java24
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/GenericParent.java37
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/InjectedThing.java229
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/Injector.java32
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/MultibindingComponent.java52
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/MultibindingDependency.java20
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/MultibindingModule.java169
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/NeedsFactory.java27
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/NestedAnnotationContainer.java26
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/NonComponentDependencyComponent.java47
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/NumberClassKey.java23
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/OuterClassBar.java25
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/OuterClassFoo.java25
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/ParentModule.java18
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/PrimitivesModule.java93
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/ReferencesGeneric.java26
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/ScopedGeneric.java12
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/ShortKey.java23
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/SingletonGenericComponent.java13
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/Thing.java23
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/TypeWithInheritedMembersInjection.java23
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/UnwrappedAnnotationKey.java24
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/WrappedAnnotationKey.java28
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/ByteModule.java30
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/DepComponent.java22
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/DoubleModule.java27
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/FloatModule.java27
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/GenericParent.java20
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/Grandchild.java30
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/IntModuleIncludingDoubleAndFloat.java33
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/LongModule.java27
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/MiddleChild.java32
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/MiddleScope.java27
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/OtherMiddleChild.java33
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/ParentComponent.java29
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/ParentOfGenericComponent.java23
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/StringModule.java33
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/TestChildComponentWithBuilderAbstractClass.java47
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/TestChildComponentWithBuilderInterface.java47
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithBuilderAbstractClass.java65
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithBuilderInterface.java46
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithGenericBuilderAbstractClass.java48
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithGenericBuilderInterface.java47
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/cycle/Cycles.java162
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/cycle/LongCycle.java132
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfArrayOfParentOfStringArray.java20
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfPrimitiveIntArray.java20
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfStringArray.java20
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectComponent.java27
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectGenericParent.java24
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectModule.java31
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/membersinject/NonRequestedChild.java27
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/multipackage/FooComponent.java42
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/multipackage/MembersInjectionVisibilityComponent.java34
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AGrandchild.java50
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AModule.java29
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/multipackage/a/APackagePrivateObject.java24
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AParent.java38
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/multipackage/a/APublicObject.java24
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BChild.java45
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BModule.java29
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BPackagePrivateObject.java24
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/multipackage/c/CModule.java30
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/multipackage/d/DModule.java30
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/multipackage/foo/Foo.java28
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/multipackage/grandsub/FooGrandchildComponent.java26
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/multipackage/sub/FooChildComponent.java30
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/nullables/NullComponent.java29
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/nullables/NullComponentWithDependency.java28
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/nullables/NullFoo.java56
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/nullables/NullModule.java35
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/nullables/Nullable.java3
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/staticprovides/AllStaticModule.java35
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/staticprovides/SomeStaticModule.java32
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/staticprovides/StaticTestComponent.java28
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/staticprovides/StaticTestComponentWithBuilder.java31
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/sub/ContributionsModule.java41
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/sub/Exposed.java19
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/sub/OtherThing.java22
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/sub/PackagePrivate.java7
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/sub/PackagePrivateContainer.java9
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/sub/PublicSubclass.java10
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/sub/PublicSubclass2.java10
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/AnInterface.java19
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/BoundAsSingleton.java27
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildAbstractClassComponent.java22
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponent.java31
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponentRequiringModules.java26
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponentWithMultibindings.java23
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModule.java32
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithParameters.java26
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithState.java32
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildMultibindingModule.java38
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/GenericParentComponent.java20
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/GrandchildComponent.java31
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/GrandchildModule.java40
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ImplementsAnInterface.java23
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/NeedsAnInterface.java20
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponent.java31
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponentWithMultibindings.java23
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponentWithoutMultibindings.java23
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentGetters.java26
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentModule.java46
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentMultibindingModule.java55
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentOfGenericComponent.java24
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultibindingsInChild.java30
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultibindingsInParent.java47
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultiboundObjects.java39
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultiboundStrings.java39
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresSingletons.java37
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/SingletonType.java24
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/UnscopedType.java22
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/ChildComponent.java26
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/ParentComponent.java28
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/a/CommonModuleName.java26
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/a/CommonName.java31
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/b/CommonModuleName.java26
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/b/CommonName.java31
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/OnlyUsedInChild.java5
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/OnlyUsedInParent.java5
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/ParentComponent.java39
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/RepeatedModule.java51
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/SubcomponentWithRepeatedModule.java37
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/SubcomponentWithoutRepeatedModule.java23
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/tck/CarModule.java29
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/tck/CarShop.java35
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/tck/EngineModule.java34
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/tck/FuelTankModule.java28
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/tck/SeatModule.java31
-rw-r--r--compiler/src/it/functional-tests/src/main/java/test/tck/TireModule.java31
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/BasicTest.java116
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/DependsOnGeneratedCodeTest.java29
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/GenericTest.java148
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/MultibindingTest.java165
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/NestedTest.java35
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/NonComponentDependencyTest.java34
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/builder/BuilderTest.java225
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/cycle/CycleTest.java91
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/cycle/LongCycleTest.java47
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/membersinject/MembersInjectTest.java95
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/nullables/NullabilityTest.java110
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/staticprovides/StaticProvidesTest.java71
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentMultibindingsTest.java89
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentTest.java115
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/subcomponent/hiding/SubcomponentHidingTest.java32
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/subcomponent/repeat/RepeatedModuleTest.java82
-rw-r--r--compiler/src/it/functional-tests/src/test/java/test/tck/TckTest.java33
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/A.classbin0 -> 302 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/A_Factory.classbin0 -> 1229 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/AbstractMembersInjectingBaseClass.classbin0 -> 429 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/AbstractMembersInjectingBaseClass_MembersInjector.classbin0 -> 1974 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/AbstractMiddleClassWithoutMembers.classbin0 -> 356 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestStringKey$NestedWrappedKeyCreator_createNestedWrappedKey.classbin0 -> 1951 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestUnwrappedAnnotationKeyCreator_createTestStringKey.classbin0 -> 2540 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestStringKey.classbin0 -> 2534 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey.classbin0 -> 3508 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/B.classbin0 -> 302 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/B_Factory.classbin0 -> 1229 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/BasicAbstractClassComponent.classbin0 -> 620 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/BasicComponent.classbin0 -> 3082 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/BoundedGenericComponent.classbin0 -> 733 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule.classbin0 -> 2752 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideArrayListOfComparableStringFactory.classbin0 -> 1963 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideArrayListStringFactory.classbin0 -> 1812 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideDoubleFactory.classbin0 -> 1580 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideIntegerFactory.classbin0 -> 1589 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideLinkedListCharSeqFactory.classbin0 -> 1851 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideLinkedListStringFactory.classbin0 -> 1823 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideListOfIntegerFactory.classbin0 -> 1773 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideSetOfDoubleFactory.classbin0 -> 1754 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/BoundedGenerics.classbin0 -> 1157 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/BoundedGenerics_Factory.classbin0 -> 3185 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/ChildDoubleModule.classbin0 -> 1078 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/ChildDoubleModule_ProvideDoubleFactory.classbin0 -> 1556 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/ChildDoubleModule_ProvideListOfDoubleFactory.classbin0 -> 1741 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/ChildIntegerModule.classbin0 -> 1068 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/ChildIntegerModule_ProvideIntegerFactory.classbin0 -> 1573 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/ChildIntegerModule_ProvideListOfIntegerFactory.classbin0 -> 1757 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/ComplexGenerics.classbin0 -> 2115 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/ComplexGenerics_Factory.classbin0 -> 3359 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/ComponentDependsOnGeneratedCode.classbin0 -> 256 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerBasicAbstractClassComponent$1.classbin0 -> 260 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerBasicAbstractClassComponent$Builder.classbin0 -> 1292 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerBasicAbstractClassComponent.classbin0 -> 12374 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerBasicComponent$1.classbin0 -> 221 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerBasicComponent$Builder.classbin0 -> 1149 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerBasicComponent.classbin0 -> 12216 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerBoundedGenericComponent$1.classbin0 -> 248 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerBoundedGenericComponent$Builder.classbin0 -> 1414 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerBoundedGenericComponent.classbin0 -> 4832 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerComponentDependsOnGeneratedCode$1.classbin0 -> 272 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerComponentDependsOnGeneratedCode$Builder.classbin0 -> 929 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerComponentDependsOnGeneratedCode.classbin0 -> 2141 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerGenericComponent$1.classbin0 -> 227 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerGenericComponent$Builder.classbin0 -> 1762 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerGenericComponent.classbin0 -> 9699 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerMultibindingComponent$1.classbin0 -> 1650 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerMultibindingComponent$Builder.classbin0 -> 2378 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerMultibindingComponent.classbin0 -> 14618 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerNonComponentDependencyComponent$1.classbin0 -> 1800 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerNonComponentDependencyComponent$Builder.classbin0 -> 1743 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerNonComponentDependencyComponent.classbin0 -> 2929 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassBar_NestedComponent$1.classbin0 -> 266 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassBar_NestedComponent$Builder.classbin0 -> 1404 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassBar_NestedComponent.classbin0 -> 4561 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassFoo_NestedComponent$1.classbin0 -> 266 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassFoo_NestedComponent$Builder.classbin0 -> 1404 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassFoo_NestedComponent.classbin0 -> 2267 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerSingletonGenericComponent$1.classbin0 -> 254 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerSingletonGenericComponent$Builder.classbin0 -> 869 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/DaggerSingletonGenericComponent.classbin0 -> 2471 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/Generic.classbin0 -> 579 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/Generic2.classbin0 -> 583 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/Generic2_Factory.classbin0 -> 1598 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/GenericChild.classbin0 -> 944 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/GenericChild_Factory.classbin0 -> 1812 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/GenericChild_MembersInjector.classbin0 -> 2773 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/GenericComponent.classbin0 -> 1137 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/GenericDoubleReferences.classbin0 -> 871 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/GenericDoubleReferences_Factory.classbin0 -> 2108 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/GenericNoDeps.classbin0 -> 472 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/GenericNoDeps_Factory.classbin0 -> 1388 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/GenericParent.classbin0 -> 1173 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/GenericParent_Factory.classbin0 -> 1890 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/GenericParent_MembersInjector.classbin0 -> 2752 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/Generic_Factory.classbin0 -> 1589 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/InjectedThing.classbin0 -> 14609 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/InjectedThing_Factory.classbin0 -> 8816 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/InjectedThing_MembersInjector.classbin0 -> 11805 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/Injector.classbin0 -> 630 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingComponent.classbin0 -> 1983 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingDependency.classbin0 -> 163 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule.classbin0 -> 4514 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideBarKeyFactory.classbin0 -> 1564 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideFiveToSetFactory.classbin0 -> 1587 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideFooKeyFactory.classbin0 -> 2108 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideMapKeysFactory.classbin0 -> 2383 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideMapValuesFactory.classbin0 -> 2372 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideSixToSetFactory.classbin0 -> 1583 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100ByteFactory.classbin0 -> 1572 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100IntFactory.classbin0 -> 1568 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100LongFactory.classbin0 -> 1572 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100ShortFactory.classbin0 -> 1576 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForAFactory.classbin0 -> 1548 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForClassIntegerFactory.classbin0 -> 1592 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForClassLongFactory.classbin0 -> 1580 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForIntegerFactory.classbin0 -> 1572 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForLongFactory.classbin0 -> 1560 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForNewlineFactory.classbin0 -> 1572 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForNumberClassBigDecimalFactory.classbin0 -> 1628 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForNumberClassBigIntegerFactory.classbin0 -> 1628 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForTrueFactory.classbin0 -> 1560 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForUnwrappedAnnotationKeyFooFactory.classbin0 -> 1644 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForWrappedAnnotationKeyFooFactory.classbin0 -> 1636 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/NeedsFactory$Something.classbin0 -> 439 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/NeedsFactory.classbin0 -> 521 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/NeedsFactory_Factory.classbin0 -> 1637 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/NeedsFactory_SomethingFactory.classbin0 -> 601 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/NeedsFactory_SomethingFactory_Factory.classbin0 -> 1537 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingComponent.classbin0 -> 286 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingComponentImpl.classbin0 -> 736 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingTwo.classbin0 -> 886 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingTwo_Factory.classbin0 -> 2775 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent.classbin0 -> 624 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/OuterClassBar$NestedComponent.classbin0 -> 355 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/OuterClassBar.classbin0 -> 367 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/OuterClassFoo$NestedComponent.classbin0 -> 339 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/OuterClassFoo.classbin0 -> 367 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/ParentModule.classbin0 -> 1415 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/ParentModule_ProvideIterableOfAWithCFactory.classbin0 -> 2787 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule.classbin0 -> 2588 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_BoundDoubleArrayFactory.classbin0 -> 1677 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_BoundDoubleFactory.classbin0 -> 1766 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideBooleanArrayFactory.classbin0 -> 1701 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideBooleanFactory.classbin0 -> 1796 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideByteArrayFactory.classbin0 -> 1677 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideByteFactory.classbin0 -> 1754 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideCharArrayFactory.classbin0 -> 1677 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideCharFactory.classbin0 -> 1784 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideFloatArrayFactory.classbin0 -> 1685 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideFloatFactory.classbin0 -> 1768 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideIntArrayFactory.classbin0 -> 1669 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideIntFactory.classbin0 -> 1764 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideLongArrayFactory.classbin0 -> 1677 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideLongFactory.classbin0 -> 1754 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideShortArrayFactory.classbin0 -> 1685 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideShortFactory.classbin0 -> 1768 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/ReferencesGeneric.classbin0 -> 567 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/ReferencesGeneric_Factory.classbin0 -> 1584 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/ScopedGeneric.classbin0 -> 642 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/ScopedGeneric_Factory.classbin0 -> 1643 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/SingletonGenericComponent.classbin0 -> 401 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TestBooleanKey.classbin0 -> 257 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TestByteKey.classbin0 -> 251 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TestCharKey.classbin0 -> 251 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TestClassKey.classbin0 -> 314 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TestIntKey.classbin0 -> 249 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TestLongKey.classbin0 -> 255 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TestNumberClassKey.classbin0 -> 344 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TestShortKey.classbin0 -> 253 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TestStringKey$NestedWrappedKey.classbin0 -> 407 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TestStringKey$NestedWrappedKeyCreator.classbin0 -> 905 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TestStringKey.classbin0 -> 363 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TestUnwrappedAnnotationKey.classbin0 -> 300 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TestUnwrappedAnnotationKeyCreator.classbin0 -> 606 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TestWrappedAnnotationKey.classbin0 -> 474 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TestWrappedAnnotationKeyCreator.classbin0 -> 1318 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/Thing.classbin0 -> 384 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/Thing_Factory.classbin0 -> 1503 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TypeWithInheritedMembersInjection.classbin0 -> 420 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/TypeWithInheritedMembersInjection_Factory.classbin0 -> 1819 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/ByteModule.classbin0 -> 494 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/ByteModule_BFactory.classbin0 -> 1552 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerDepComponent$1.classbin0 -> 231 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerDepComponent$Builder.classbin0 -> 811 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerDepComponent.classbin0 -> 1353 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$1.classbin0 -> 240 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$Builder.classbin0 -> 841 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildBuilder.classbin0 -> 2026 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildImpl$GrandchildBuilder.classbin0 -> 2625 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildImpl$GrandchildImpl.classbin0 -> 2703 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildImpl.classbin0 -> 2827 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildBuilder.classbin0 -> 2371 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildImpl$GrandchildBuilder.classbin0 -> 2685 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildImpl$GrandchildImpl.classbin0 -> 2773 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildImpl.classbin0 -> 3340 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderAbstractClassBuilder.classbin0 -> 5591 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderAbstractClassImpl.classbin0 -> 4918 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderInterfaceBuilder.classbin0 -> 5531 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderInterfaceImpl.classbin0 -> 4858 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent.classbin0 -> 3428 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$1.classbin0 -> 267 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$Builder.classbin0 -> 1541 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$GrandchildBuilder.classbin0 -> 2526 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$GrandchildImpl.classbin0 -> 2580 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent.classbin0 -> 2598 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderAbstractClass$1.classbin0 -> 306 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderAbstractClass$Builder.classbin0 -> 4282 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderAbstractClass.classbin0 -> 4146 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderInterface$1.classbin0 -> 294 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderInterface$Builder.classbin0 -> 4222 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderInterface.classbin0 -> 4094 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass$1.classbin0 -> 327 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass$Builder.classbin0 -> 5032 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass.classbin0 -> 4303 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderInterface$1.classbin0 -> 315 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderInterface$Builder.classbin0 -> 4966 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderInterface.classbin0 -> 4227 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DepComponent.classbin0 -> 179 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DoubleModule.classbin0 -> 456 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/DoubleModule_DFactory.classbin0 -> 1580 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/FloatModule.classbin0 -> 448 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/FloatModule_FFactory.classbin0 -> 1566 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/GenericParent.classbin0 -> 252 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/Grandchild$Builder.classbin0 -> 477 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/Grandchild.classbin0 -> 379 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/IntModuleIncludingDoubleAndFloat.classbin0 -> 647 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/IntModuleIncludingDoubleAndFloat_IntegerFactory.classbin0 -> 1770 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/LongModule.classbin0 -> 450 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/LongModule_LFactory.classbin0 -> 1552 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/MiddleChild$Builder.classbin0 -> 462 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/MiddleChild.classbin0 -> 553 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/MiddleScope.classbin0 -> 323 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/OtherMiddleChild$Builder.classbin0 -> 487 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/OtherMiddleChild.classbin0 -> 617 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/ParentComponent.classbin0 -> 1013 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/ParentOfGenericComponent.classbin0 -> 527 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/StringModule.classbin0 -> 556 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/StringModule_StringFactory.classbin0 -> 1544 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderAbstractClass$Builder.classbin0 -> 1487 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderAbstractClass$SharedBuilder.classbin0 -> 1408 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderAbstractClass.classbin0 -> 741 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderInterface$Builder.classbin0 -> 1034 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderInterface$SharedBuilder.classbin0 -> 1034 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderInterface.classbin0 -> 725 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderAbstractClass$Builder.classbin0 -> 1508 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderAbstractClass$SharedBuilder.classbin0 -> 920 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderAbstractClass.classbin0 -> 1107 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderInterface$Builder.classbin0 -> 904 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderInterface$SharedBuilder.classbin0 -> 385 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderInterface.classbin0 -> 704 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderAbstractClass$Builder.classbin0 -> 1516 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderAbstractClass$SharedBuilder.classbin0 -> 1442 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderAbstractClass.classbin0 -> 748 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderInterface$Builder.classbin0 -> 1059 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderInterface$SharedBuilder.classbin0 -> 1055 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderInterface.classbin0 -> 732 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/ApiComponent.classbin0 -> 346 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/CloudContactDataStore.classbin0 -> 614 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/ContactDataStore.classbin0 -> 602 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/ContactDataStore_MembersInjector.classbin0 -> 2227 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/DaggerApiComponent$1.classbin0 -> 273 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/DaggerApiComponent$Builder.classbin0 -> 1000 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/DaggerApiComponent.classbin0 -> 2937 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/RestClient.classbin0 -> 391 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/RestClient_Factory.classbin0 -> 1618 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerOneComponent$1.classbin0 -> 271 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerOneComponent$Builder.classbin0 -> 1598 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerOneComponent.classbin0 -> 2651 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerTwoComponent$1.classbin0 -> 271 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerTwoComponent$Builder.classbin0 -> 1598 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerTwoComponent.classbin0 -> 2651 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/Packager.classbin0 -> 475 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/PackagerOneComponent.classbin0 -> 318 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/PackagerTwoComponent.classbin0 -> 318 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/Packager_Factory.classbin0 -> 1666 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/Product.classbin0 -> 116 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOne.classbin0 -> 401 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOneModule.classbin0 -> 607 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOneModule_ProvideProductFactory.classbin0 -> 2347 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOne_Factory.classbin0 -> 1488 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwo.classbin0 -> 401 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwoModule.classbin0 -> 607 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwoModule_ProvideProductFactory.classbin0 -> 2347 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwo_Factory.classbin0 -> 1488 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent$1.classbin0 -> 260 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent$Builder.classbin0 -> 1626 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent$SubComponentImpl.classbin0 -> 1352 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent.classbin0 -> 2630 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/ModuleWithParameter.classbin0 -> 620 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/ModuleWithParameter_ProvidesStringFactory.classbin0 -> 1723 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/RootComponent.classbin0 -> 373 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/SubComponent.classbin0 -> 237 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/membersinject/ChildOfArrayOfParentOfStringArray.classbin0 -> 532 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/membersinject/ChildOfPrimitiveIntArray.classbin0 -> 438 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/membersinject/ChildOfStringArray.classbin0 -> 437 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/membersinject/DaggerMembersInjectComponent$1.classbin0 -> 273 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/membersinject/DaggerMembersInjectComponent$Builder.classbin0 -> 1607 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/membersinject/DaggerMembersInjectComponent.classbin0 -> 4503 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectComponent.classbin0 -> 455 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectGenericParent.classbin0 -> 613 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectGenericParent_MembersInjector.classbin0 -> 2249 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule.classbin0 -> 940 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule_ProvideFooArrayOfStringArrayFactory.classbin0 -> 2070 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule_ProvideIntArrayFactory.classbin0 -> 1595 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule_ProvideStringArrayFactory.classbin0 -> 1675 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$1.classbin0 -> 241 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$Builder.classbin0 -> 1420 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$FooChildComponentImpl$FooGrandchildComponentImpl.classbin0 -> 2693 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$FooChildComponentImpl.classbin0 -> 3171 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent.classbin0 -> 2784 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/FooComponent.classbin0 -> 410 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/a/AModule.classbin0 -> 611 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/a/AModule_ProvideStringFactory.classbin0 -> 1535 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/b/BModule.classbin0 -> 611 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/b/BModule_ProvideStringFactory.classbin0 -> 1535 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/c/CModule.classbin0 -> 611 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/c/CModule_ProvideStringFactory.classbin0 -> 1535 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/d/DModule.classbin0 -> 611 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/d/DModule_ProvideStringFactory.classbin0 -> 1535 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/foo/Foo.classbin0 -> 678 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/foo/Foo_Factory.classbin0 -> 1810 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/grandsub/FooGrandchildComponent.classbin0 -> 419 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/multipackage/sub/FooChildComponent.classbin0 -> 518 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponent$1.classbin0 -> 238 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponent$Builder.classbin0 -> 1394 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponent.classbin0 -> 3331 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency$1.classbin0 -> 1560 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency$2.classbin0 -> 1744 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency$Builder.classbin0 -> 1610 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency.classbin0 -> 2574 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/NullComponent.classbin0 -> 630 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/NullComponentWithDependency.classbin0 -> 619 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/NullFoo.classbin0 -> 1744 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/NullFoo_Factory.classbin0 -> 2462 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/NullFoo_MembersInjector.classbin0 -> 2568 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/NullModule.classbin0 -> 724 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/NullModule_ProvideNullableStringFactory.classbin0 -> 1434 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/NullModule_ProvideNumberFactory.classbin0 -> 1570 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/nullables/Nullable.classbin0 -> 151 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/staticprovides/AllStaticModule.classbin0 -> 1065 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/staticprovides/AllStaticModule_ContibuteEmptyIntegerSetFactory.classbin0 -> 2079 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/staticprovides/AllStaticModule_ContributeStringFactory.classbin0 -> 1795 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/staticprovides/DaggerStaticTestComponent$1.classbin0 -> 266 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/staticprovides/DaggerStaticTestComponent$Builder.classbin0 -> 1928 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/staticprovides/DaggerStaticTestComponent.classbin0 -> 3293 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/staticprovides/SomeStaticModule.classbin0 -> 1051 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/staticprovides/SomeStaticModule_ContributeStringFromAStaticMethodFactory.classbin0 -> 1939 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/staticprovides/SomeStaticModule_ContributeStringFromAnInstanceMethodFactory.classbin0 -> 1699 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/staticprovides/StaticTestComponent.classbin0 -> 494 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule.classbin0 -> 1283 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule_ContributeAnIntFactory.classbin0 -> 2145 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule_ContributeAnotherIntFactory.classbin0 -> 1639 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule_ContributeSomeIntsFactory.classbin0 -> 1778 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/DaggerGenericComponent_PackageProxy.classbin0 -> 991 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/Exposed.classbin0 -> 1125 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/Exposed_Factory.classbin0 -> 2658 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/Exposed_MembersInjector.classbin0 -> 2505 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/OtherThing.classbin0 -> 362 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/OtherThing_Factory.classbin0 -> 1559 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivate.classbin0 -> 349 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivateContainer$PublicEnclosed.classbin0 -> 492 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivateContainer$PublicEnclosed_Factory.classbin0 -> 1762 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivateContainer.classbin0 -> 417 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivate_Factory.classbin0 -> 1412 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass.classbin0 -> 506 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass2.classbin0 -> 720 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass2_Factory.classbin0 -> 2324 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass_Factory.classbin0 -> 2107 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/AnInterface.classbin0 -> 121 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/BoundAsSingleton.classbin0 -> 382 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildAbstractClassComponent.classbin0 -> 500 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildComponent.classbin0 -> 625 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildComponentRequiringModules.classbin0 -> 397 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModule$1.classbin0 -> 666 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModule.classbin0 -> 721 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModuleWithParameters.classbin0 -> 460 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModuleWithState.classbin0 -> 533 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModuleWithState_ProvideIntFactory.classbin0 -> 1721 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModule_ProvideUnscopedObjectFactory.classbin0 -> 1562 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$1.classbin0 -> 250 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$Builder.classbin0 -> 1473 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildAbstractClassComponentImpl$GrandchildComponentImpl.classbin0 -> 3709 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildAbstractClassComponentImpl.classbin0 -> 3382 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildComponentImpl$GrandchildComponentImpl.classbin0 -> 3605 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildComponentImpl.classbin0 -> 3315 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildComponentRequiringModulesImpl.classbin0 -> 2689 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent.classbin0 -> 5260 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$1.classbin0 -> 277 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$Builder.classbin0 -> 1581 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$ChildComponentImpl$GrandchildComponentImpl.classbin0 -> 3730 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$ChildComponentImpl.classbin0 -> 3449 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent.classbin0 -> 4526 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/GenericParentComponent.classbin0 -> 268 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildComponent.classbin0 -> 631 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule$1.classbin0 -> 701 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule.classbin0 -> 1312 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule_ProvideAnInterfaceFactory.classbin0 -> 2396 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule_ProvideNeedsAnInterfaceFactory.classbin0 -> 2386 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule_ProvideUnscopedObjectFactory.classbin0 -> 1602 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ImplementsAnInterface.classbin0 -> 425 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ImplementsAnInterface_Factory.classbin0 -> 1579 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/NeedsAnInterface.classbin0 -> 404 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentComponent.classbin0 -> 657 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentGetters.classbin0 -> 357 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule$1.classbin0 -> 673 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule$2.classbin0 -> 665 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule.classbin0 -> 1201 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule_ProvideSingletonObjectFactory.classbin0 -> 1574 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule_ProvideUnscopedObjectFactory.classbin0 -> 1570 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule_ProvideUnscopedTypeBoundAsSingletonFactory.classbin0 -> 2347 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentOfGenericComponent.classbin0 -> 531 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/RequiresSingletons.classbin0 -> 934 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/RequiresSingletons_Factory.classbin0 -> 2180 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/SingletonType.classbin0 -> 403 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/SingletonType_Factory.classbin0 -> 1491 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/UnscopedType.classbin0 -> 462 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/UnscopedType_Factory.classbin0 -> 1697 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/ChildComponent.classbin0 -> 398 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent$1.classbin0 -> 264 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent$Builder.classbin0 -> 1606 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent$ChildComponentImpl.classbin0 -> 2299 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent.classbin0 -> 3058 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/ParentComponent.classbin0 -> 434 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonModuleName.classbin0 -> 522 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonModuleName_ProvideStringFactory.classbin0 -> 1702 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonName.classbin0 -> 558 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonName_Factory.classbin0 -> 1650 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonModuleName.classbin0 -> 497 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonModuleName_ProvideStringFactory.classbin0 -> 1764 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonName.classbin0 -> 584 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonName_Factory.classbin0 -> 1667 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/ChildComponent.classbin0 -> 492 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent$1.classbin0 -> 264 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent$Builder.classbin0 -> 1411 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent$ChildComponentImpl.classbin0 -> 2606 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent.classbin0 -> 3788 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/OnlyUsedInChild.classbin0 -> 320 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/OnlyUsedInParent.classbin0 -> 323 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/ParentComponent$Builder.classbin0 -> 425 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/ParentComponent.classbin0 -> 660 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule$1.classbin0 -> 655 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule$2.classbin0 -> 652 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule.classbin0 -> 1237 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ContributeStringFactory.classbin0 -> 1638 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInChildFactory.classbin0 -> 1828 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInParentFactory.classbin0 -> 1837 bytes
-rw-r--r--compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ProvideStringFactory.classbin0 -> 1672 bytes
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/A_Factory.java19
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/AbstractMembersInjectingBaseClass_MembersInjector.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestStringKey$NestedWrappedKeyCreator_createNestedWrappedKey.java55
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestUnwrappedAnnotationKeyCreator_createTestStringKey.java90
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestStringKey.java90
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey.java120
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/B_Factory.java19
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideArrayListOfComparableStringFactory.java29
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideArrayListStringFactory.java29
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideDoubleFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideIntegerFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideLinkedListCharSeqFactory.java29
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideLinkedListStringFactory.java29
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideListOfIntegerFactory.java29
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideSetOfDoubleFactory.java29
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenerics_Factory.java38
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildDoubleModule_ProvideDoubleFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildDoubleModule_ProvideListOfDoubleFactory.java29
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildIntegerModule_ProvideIntegerFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildIntegerModule_ProvideListOfIntegerFactory.java29
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/ComplexGenerics_Factory.java38
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerBasicAbstractClassComponent.java341
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerBasicComponent.java341
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerBoundedGenericComponent.java81
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerComponentDependsOnGeneratedCode.java41
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerGenericComponent.java193
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerMultibindingComponent.java299
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerNonComponentDependencyComponent.java69
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerOuterClassBar_NestedComponent.java65
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerOuterClassFoo_NestedComponent.java59
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerSingletonGenericComponent.java49
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/Generic2_Factory.java25
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericChild_Factory.java27
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericChild_MembersInjector.java38
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericDoubleReferences_Factory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericNoDeps_Factory.java21
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericParent_Factory.java27
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericParent_MembersInjector.java39
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/Generic_Factory.java25
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/InjectedThing_Factory.java83
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/InjectedThing_MembersInjector.java199
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideBarKeyFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideFiveToSetFactory.java26
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideFooKeyFactory.java32
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideMapKeysFactory.java34
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideMapValuesFactory.java34
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideSixToSetFactory.java26
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100ByteFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100IntFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100LongFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100ShortFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForAFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForClassIntegerFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForClassLongFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForIntegerFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForLongFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForNewlineFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForNumberClassBigDecimalFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForNumberClassBigIntegerFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForTrueFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForUnwrappedAnnotationKeyFooFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForWrappedAnnotationKeyFooFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/NeedsFactory_Factory.java25
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/NeedsFactory_SomethingFactory.java13
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/NeedsFactory_SomethingFactory_Factory.java19
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/NonComponentDependencyComponent$ThingTwo_Factory.java33
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/ParentModule_ProvideIterableOfAWithCFactory.java35
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_BoundDoubleArrayFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_BoundDoubleFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideBooleanArrayFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideBooleanFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideByteArrayFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideByteFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideCharArrayFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideCharFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideFloatArrayFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideFloatFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideIntArrayFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideIntFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideLongArrayFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideLongFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideShortArrayFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideShortFactory.java23
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/ReferencesGeneric_Factory.java25
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/ScopedGeneric_Factory.java25
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/TestStringKey$NestedWrappedKeyCreator.java13
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/TestUnwrappedAnnotationKeyCreator.java12
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/TestWrappedAnnotationKeyCreator.java17
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/Thing_Factory.java26
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/TypeWithInheritedMembersInjection_Factory.java27
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/ByteModule_BFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerDepComponent.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerParentComponent.java519
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerParentOfGenericComponent.java104
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithBuilderAbstractClass.java124
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithBuilderInterface.java124
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass.java133
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithGenericBuilderInterface.java133
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DoubleModule_DFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/FloatModule_FFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/IntModuleIncludingDoubleAndFloat_IntegerFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/LongModule_LFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/StringModule_StringFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/abstractinjectmethod/ContactDataStore_MembersInjector.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/abstractinjectmethod/DaggerApiComponent.java49
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/abstractinjectmethod/RestClient_Factory.java19
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ContactDataStore_MembersInjector.java30
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/DaggerApiComponent.java43
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/DaggerPackagerOneComponent.java56
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/DaggerPackagerTwoComponent.java56
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/Packager_Factory.java25
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductOneModule_ProvideProductFactory.java32
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductOne_Factory.java19
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductTwoModule_ProvideProductFactory.java32
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductTwo_Factory.java19
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/RestClient_Factory.java20
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/subcomponent/DaggerRootComponent.java69
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/subcomponent/DaggerSubComponent.java50
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/subcomponent/ModuleWithParameter_ProvidesStringFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/DaggerMembersInjectComponent.java82
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectGenericParent_MembersInjector.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectModule_ProvideFooArrayOfStringArrayFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectModule_ProvideIntArrayFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectModule_ProvideStringArrayFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/DaggerFooComponent.java130
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/a/AModule_ProvideStringFactory.java26
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/b/BModule_ProvideStringFactory.java26
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/c/CModule_ProvideStringFactory.java26
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/d/DModule_ProvideStringFactory.java26
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/foo/Foo_Factory.java26
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/DaggerNullComponent.java81
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/DaggerNullComponentWithDependency.java82
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullFoo_Factory.java34
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullFoo_MembersInjector.java35
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullModule_ProvideNullableStringFactory.java25
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullModule_ProvideNumberFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/AllStaticModule_ContibuteEmptyIntegerSetFactory.java24
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/AllStaticModule_ContributeStringFactory.java21
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/DaggerStaticTestComponent.java83
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/SomeStaticModule_ContributeStringFromAStaticMethodFactory.java21
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/SomeStaticModule_ContributeStringFromAnInstanceMethodFactory.java26
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/ContributionsModule_ContributeAnIntFactory.java30
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/ContributionsModule_ContributeAnotherIntFactory.java26
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/ContributionsModule_ContributeSomeIntsFactory.java29
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/DaggerGenericComponent_PackageProxy.java16
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/Exposed_Factory.java36
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/Exposed_MembersInjector.java34
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/OtherThing_Factory.java25
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PackagePrivateContainer$PublicEnclosed_Factory.java20
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PackagePrivate_Factory.java19
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PublicSubclass2_Factory.java32
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PublicSubclass_Factory.java31
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ChildModuleWithState_ProvideIntFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ChildModule_ProvideUnscopedObjectFactory.java26
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/DaggerParentComponent.java274
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/DaggerParentOfGenericComponent.java155
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/GrandchildModule_ProvideAnInterfaceFactory.java32
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/GrandchildModule_ProvideNeedsAnInterfaceFactory.java32
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/GrandchildModule_ProvideUnscopedObjectFactory.java26
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ImplementsAnInterface_Factory.java19
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ParentModule_ProvideSingletonObjectFactory.java26
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ParentModule_ProvideUnscopedObjectFactory.java26
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ParentModule_ProvideUnscopedTypeBoundAsSingletonFactory.java32
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/RequiresSingletons_Factory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/SingletonType_Factory.java19
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/UnscopedType_Factory.java25
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/DaggerParentComponent.java91
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/a/CommonModuleName_ProvideStringFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/a/CommonName_Factory.java25
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/b/CommonModuleName_ProvideStringFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/b/CommonName_Factory.java25
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/DaggerParentComponent.java102
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ContributeStringFactory.java26
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInChildFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInParentFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ProvideStringFactory.java28
-rw-r--r--compiler/src/it/functional-tests/target/generated-test-sources/test-annotations/test/AutoAnnotation_MultibindingTest_nestedWrappedKey.java55
-rw-r--r--compiler/src/it/functional-tests/target/generated-test-sources/test-annotations/test/AutoAnnotation_MultibindingTest_testStringKey.java90
-rw-r--r--compiler/src/it/functional-tests/target/generated-test-sources/test-annotations/test/AutoAnnotation_MultibindingTest_testWrappedAnnotationKey.java120
-rw-r--r--compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest$1$1.classbin0 -> 869 bytes
-rw-r--r--compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest$1$2.classbin0 -> 869 bytes
-rw-r--r--compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest$1.classbin0 -> 1321 bytes
-rw-r--r--compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest.classbin0 -> 4533 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/pom.xml98
-rw-r--r--compiler/src/it/producers-functional-tests/src/main/java/test/DependedComponent.java25
-rw-r--r--compiler/src/it/producers-functional-tests/src/main/java/test/DependedModule.java27
-rw-r--r--compiler/src/it/producers-functional-tests/src/main/java/test/DependedProducerModule.java34
-rw-r--r--compiler/src/it/producers-functional-tests/src/main/java/test/DependedProductionComponent.java25
-rw-r--r--compiler/src/it/producers-functional-tests/src/main/java/test/DependentComponent.java28
-rw-r--r--compiler/src/it/producers-functional-tests/src/main/java/test/DependentProducerModule.java35
-rw-r--r--compiler/src/it/producers-functional-tests/src/main/java/test/MultibindingComponent.java26
-rw-r--r--compiler/src/it/producers-functional-tests/src/main/java/test/MultibindingProducerModule.java49
-rw-r--r--compiler/src/it/producers-functional-tests/src/main/java/test/Request.java31
-rw-r--r--compiler/src/it/producers-functional-tests/src/main/java/test/Response.java28
-rw-r--r--compiler/src/it/producers-functional-tests/src/main/java/test/ResponseModule.java27
-rw-r--r--compiler/src/it/producers-functional-tests/src/main/java/test/ResponseProducerModule.java34
-rw-r--r--compiler/src/it/producers-functional-tests/src/main/java/test/SimpleComponent.java24
-rw-r--r--compiler/src/it/producers-functional-tests/src/main/java/test/SimpleProducerModule.java219
-rw-r--r--compiler/src/it/producers-functional-tests/src/test/java/test/DependentTest.java74
-rw-r--r--compiler/src/it/producers-functional-tests/src/test/java/test/MultibindingTest.java35
-rw-r--r--compiler/src/it/producers-functional-tests/src/test/java/test/ProducerFactoryTest.java195
-rw-r--r--compiler/src/it/producers-functional-tests/src/test/java/test/SimpleTest.java35
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedComponent$1.classbin0 -> 230 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedComponent$Builder.classbin0 -> 1312 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedComponent.classbin0 -> 1959 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedProductionComponent$1.classbin0 -> 260 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedProductionComponent$Builder.classbin0 -> 1982 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedProductionComponent.classbin0 -> 2238 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent$1.classbin0 -> 1354 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent$2.classbin0 -> 1536 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent$Builder.classbin0 -> 2805 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent.classbin0 -> 2691 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerMultibindingComponent$1.classbin0 -> 242 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerMultibindingComponent$Builder.classbin0 -> 1918 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerMultibindingComponent.classbin0 -> 3247 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerSimpleComponent$1.classbin0 -> 224 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerSimpleComponent$Builder.classbin0 -> 1814 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DaggerSimpleComponent.classbin0 -> 2525 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DependedComponent.classbin0 -> 268 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DependedModule.classbin0 -> 485 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DependedModule_ProvideGreetingFactory.classbin0 -> 1540 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DependedProducerModule.classbin0 -> 512 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DependedProducerModule_ProduceNumberOfGreetingsFactory$1.classbin0 -> 1398 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DependedProducerModule_ProduceNumberOfGreetingsFactory.classbin0 -> 2081 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DependedProductionComponent.classbin0 -> 451 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DependentComponent.classbin0 -> 538 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DependentProducerModule.classbin0 -> 1452 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DependentProducerModule_GreetingsFactory$1.classbin0 -> 1917 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/DependentProducerModule_GreetingsFactory.classbin0 -> 3088 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/MultibindingComponent.classbin0 -> 556 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule.classbin0 -> 1955 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrFactory$1.classbin0 -> 1575 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrFactory.classbin0 -> 2316 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrsFactory$1.classbin0 -> 1393 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrsFactory.classbin0 -> 2322 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrCountFactory$1.classbin0 -> 1868 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrCountFactory.classbin0 -> 2551 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrFactory$1.classbin0 -> 1397 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrFactory.classbin0 -> 2043 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrsFactory$1.classbin0 -> 1257 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrsFactory.classbin0 -> 2049 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/Request.classbin0 -> 477 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/Request_Factory.classbin0 -> 1295 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/Response.classbin0 -> 436 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule.classbin0 -> 1295 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_GreetingFactory$1.classbin0 -> 1307 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_GreetingFactory.classbin0 -> 2219 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_ResponseFactory$1.classbin0 -> 1889 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_ResponseFactory.classbin0 -> 3004 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/SimpleComponent.classbin0 -> 419 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule.classbin0 -> 987 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_LenFactory$1.classbin0 -> 1670 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_LenFactory.classbin0 -> 2402 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_StrFactory$1.classbin0 -> 1249 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_StrFactory.classbin0 -> 2169 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerDependedComponent.java54
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerDependedProductionComponent.java64
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerDependentComponent.java110
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerMultibindingComponent.java81
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerSimpleComponent.java67
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DependedModule_ProvideGreetingFactory.java28
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DependedProducerModule_ProduceNumberOfGreetingsFactory.java32
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DependentProducerModule_GreetingsFactory.java42
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_FutureStrFactory.java34
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_FutureStrsFactory.java34
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_StrCountFactory.java37
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_StrFactory.java34
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_StrsFactory.java33
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/Request_Factory.java19
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/ResponseProducerModule_GreetingFactory.java33
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/ResponseProducerModule_ResponseFactory.java42
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/SimpleProducerModule_LenFactory.java36
-rw-r--r--compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/SimpleProducerModule_StrFactory.java33
-rw-r--r--compiler/src/it/producers-functional-tests/target/test-classes/test/DependentTest$1.classbin0 -> 633 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/test-classes/test/DependentTest$2.classbin0 -> 979 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/test-classes/test/DependentTest.classbin0 -> 2964 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/test-classes/test/MultibindingTest.classbin0 -> 1909 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/test-classes/test/ProducerFactoryTest$1.classbin0 -> 945 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/test-classes/test/ProducerFactoryTest.classbin0 -> 3311 bytes
-rw-r--r--compiler/src/it/producers-functional-tests/target/test-classes/test/SimpleTest.classbin0 -> 1685 bytes
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/AbstractComponentProcessingStep.java117
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/AbstractComponentWriter.java1150
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/Binding.java206
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/BindingGraph.java642
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java1165
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/BindingKey.java40
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/BuilderValidator.java203
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java450
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java137
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ComponentHierarchyValidator.java115
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ComponentProcessingStep.java173
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java289
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ComponentValidator.java370
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ComponentWriter.java118
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java241
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ContributionBinding.java160
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/DependencyRequest.java318
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/DependencyRequestFormatter.java151
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/DependencyRequestMapper.java97
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/DependencyVariableNamer.java64
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ErrorMessages.java425
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/FactoryGenerator.java278
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/Formatter.java48
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/FrameworkField.java169
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/InjectBindingRegistry.java262
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/InjectConstructorValidator.java112
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/InjectFieldValidator.java76
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/InjectMethodValidator.java83
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/InjectProcessingStep.java146
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/InjectionAnnotations.java72
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/Key.java354
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/KeyFormatter.java35
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/KeyVariableNamer.java66
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/MapKeyGenerator.java176
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/MapKeyProcessingStep.java98
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/MapKeyValidator.java52
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/MapKeys.java335
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/MembersInjectionBinding.java314
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/MembersInjectorGenerator.java398
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/MethodSignature.java33
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/MethodSignatureFormatter.java115
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/MissingBindingSuggestions.java55
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ModuleDescriptor.java122
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ModuleProcessingStep.java136
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ModuleValidator.java338
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ProducerFactoryGenerator.java434
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ProducerModuleProcessingStep.java141
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ProducesMethodValidator.java206
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ProductionBinding.java188
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ProductionBindingFormatter.java49
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ProductionComponentProcessingStep.java75
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ProductionComponentValidator.java85
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ProvidesMethodValidator.java185
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ProvisionBinding.java323
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ProvisionBindingFormatter.java48
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ResolvedBindings.java125
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/Scope.java145
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/SourceFileGenerationException.java81
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/SourceFileGenerator.java100
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/SourceFiles.java295
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/SubcomponentWriter.java214
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/Util.java180
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ValidationReport.java223
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/ValidationType.java40
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/AnnotationWriter.java70
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/ArrayTypeName.java53
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/BlockWriter.java66
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/ClassName.java273
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/ClassWriter.java153
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/ConstructorWriter.java96
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/EnumWriter.java174
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/FieldWriter.java66
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/HasClassReferences.java31
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/HasTypeName.java20
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/IndentingAppendable.java92
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/InterfaceWriter.java87
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/JavaWriter.java260
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/MethodWriter.java121
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/Modifiable.java68
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/NullName.java39
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/ParameterizedTypeName.java107
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/PrimitiveName.java92
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/Snippet.java186
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/StringLiteral.java105
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/TypeName.java19
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/TypeNames.java108
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/TypeVariableName.java115
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/TypeWriter.java108
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/VariableWriter.java58
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/VoidName.java39
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/WildcardName.java67
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/Writable.java28
-rw-r--r--compiler/src/main/java/dagger/internal/codegen/writer/Writables.java83
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/BindingFieldTest.java94
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/ComponentBuilderTest.java938
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/ComponentProcessorTest.java2016
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/DependencyRequestMapperTest.java147
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/ErrorMessagesTest.java30
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/GraphValidationScopingTest.java348
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/GraphValidationTest.java1123
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java1128
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/KeyTest.java281
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/MapBindingComponentProcessorTest.java901
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/MapKeyProcessorTest.java473
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/MembersInjectionTest.java875
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/MethodSignatureFormatterTest.java66
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/MissingBindingSuggestionsTest.java163
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/ModuleFactoryGeneratorTest.java1070
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/MultipleRequestTest.java119
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/PackageProxyTest.java242
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/ProducerModuleFactoryGeneratorTest.java564
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/ProductionComponentProcessorTest.java223
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/ProductionGraphValidationTest.java164
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/RepeatedModuleValidationTest.java121
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/SubcomponentBuilderValidationTest.java742
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/SubcomponentValidationTest.java440
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/ValidationReportTest.java129
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/writer/ClassNameTest.java128
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/writer/JavaWriterTest.java33
-rw-r--r--compiler/src/test/java/dagger/internal/codegen/writer/TypeNamesTest.java106
-rw-r--r--compiler/src/test/java/dagger/tests/integration/operation/PrimitiveInjectionTest.java142
-rw-r--r--core/pom.xml95
-rw-r--r--core/src/main/java/dagger/Component.java258
-rw-r--r--core/src/main/java/dagger/Lazy.java155
-rw-r--r--core/src/main/java/dagger/MapKey.java114
-rw-r--r--core/src/main/java/dagger/MembersInjector.java44
-rw-r--r--core/src/main/java/dagger/Module.java36
-rw-r--r--core/src/main/java/dagger/Provides.java73
-rw-r--r--core/src/main/java/dagger/Subcomponent.java51
-rw-r--r--core/src/main/java/dagger/internal/Beta.java33
-rw-r--r--core/src/main/java/dagger/internal/Collections.java58
-rw-r--r--core/src/main/java/dagger/internal/DelegateFactory.java46
-rw-r--r--core/src/main/java/dagger/internal/DoubleCheckLazy.java72
-rw-r--r--core/src/main/java/dagger/internal/Factory.java37
-rw-r--r--core/src/main/java/dagger/internal/InstanceFactory.java48
-rw-r--r--core/src/main/java/dagger/internal/MapFactory.java60
-rw-r--r--core/src/main/java/dagger/internal/MapProviderFactory.java90
-rw-r--r--core/src/main/java/dagger/internal/MembersInjectors.java63
-rw-r--r--core/src/main/java/dagger/internal/ScopedProvider.java61
-rw-r--r--core/src/main/java/dagger/internal/SetFactory.java122
-rw-r--r--core/src/main/java/dagger/mapkeys/ClassKey.java35
-rw-r--r--core/src/main/java/dagger/mapkeys/IntKey.java30
-rw-r--r--core/src/main/java/dagger/mapkeys/LongKey.java30
-rw-r--r--core/src/main/java/dagger/mapkeys/StringKey.java30
-rw-r--r--core/src/main/java/dagger/package-info.java34
-rw-r--r--core/src/test/java/dagger/internal/DoubleCheckLazyTest.java100
-rw-r--r--core/src/test/java/dagger/internal/InstanceFactoryTest.java42
-rw-r--r--core/src/test/java/dagger/internal/MapProviderFactoryTest.java86
-rw-r--r--core/src/test/java/dagger/internal/ScopedProviderTest.java65
-rw-r--r--core/src/test/java/dagger/internal/SetFactoryTest.java134
-rwxr-xr-xdeploy_website.sh49
-rw-r--r--examples/android-activity-graphs/AndroidManifest.xml23
-rw-r--r--examples/android-activity-graphs/README.md24
-rw-r--r--examples/android-activity-graphs/pom.xml63
-rw-r--r--examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/AbstractActivityComponent.java30
-rw-r--r--examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ActivityModule.java39
-rw-r--r--examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ApplicationComponent.java35
-rw-r--r--examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/DemoApplication.java39
-rw-r--r--examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/DemoApplicationModule.java48
-rw-r--r--examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/PerActivity.java31
-rw-r--r--examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/ActivityTitleController.java41
-rw-r--r--examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeActivity.java51
-rw-r--r--examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeComponent.java29
-rw-r--r--examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeFragment.java51
-rw-r--r--examples/android-activity-graphs/target/generated-sources/r/com/example/dagger/activitygraphs/BuildConfig.java8
-rw-r--r--examples/android-activity-graphs/target/generated-sources/r/com/example/dagger/activitygraphs/Manifest.java7
-rw-r--r--examples/android-activity-graphs/target/generated-sources/r/com/example/dagger/activitygraphs/R.java7
-rw-r--r--examples/android-simple/AndroidManifest.xml23
-rw-r--r--examples/android-simple/README.md17
-rw-r--r--examples/android-simple/pom.xml59
-rw-r--r--examples/android-simple/src/main/java/com/example/dagger/simple/AndroidModule.java49
-rw-r--r--examples/android-simple/src/main/java/com/example/dagger/simple/DemoActivity.java27
-rw-r--r--examples/android-simple/src/main/java/com/example/dagger/simple/DemoApplication.java52
-rw-r--r--examples/android-simple/src/main/java/com/example/dagger/simple/ForApplication.java25
-rw-r--r--examples/android-simple/src/main/java/com/example/dagger/simple/ui/HomeActivity.java35
-rw-r--r--examples/android-simple/target/generated-sources/r/com/example/dagger/simple/BuildConfig.java8
-rw-r--r--examples/android-simple/target/generated-sources/r/com/example/dagger/simple/Manifest.java7
-rw-r--r--examples/android-simple/target/generated-sources/r/com/example/dagger/simple/R.java7
-rw-r--r--examples/pom.xml77
-rw-r--r--examples/simple/pom.xml42
-rw-r--r--examples/simple/src/main/java/coffee/CoffeeApp.java17
-rw-r--r--examples/simple/src/main/java/coffee/CoffeeMaker.java21
-rw-r--r--examples/simple/src/main/java/coffee/DripCoffeeModule.java12
-rw-r--r--examples/simple/src/main/java/coffee/ElectricHeater.java18
-rw-r--r--examples/simple/src/main/java/coffee/Heater.java7
-rw-r--r--examples/simple/src/main/java/coffee/Pump.java5
-rw-r--r--examples/simple/src/main/java/coffee/PumpModule.java11
-rw-r--r--examples/simple/src/main/java/coffee/Thermosiphon.java18
-rw-r--r--lib/auto-common-1.0-20151022.071545-39-sources.jarbin0 -> 24916 bytes
-rw-r--r--lib/auto-common-1.0-20151022.071545-39.jarbin0 -> 70596 bytes
-rw-r--r--lib/auto-common-1.0-20151022.071545-39.jar.txt203
-rw-r--r--lib/auto-factory-1.0-20150915.183854-35-sources.jarbin0 -> 25388 bytes
-rw-r--r--lib/auto-factory-1.0-20150915.183854-35.jarbin0 -> 58447 bytes
-rw-r--r--lib/auto-factory-1.0-20150915.183854-35.jar.txt203
-rw-r--r--lib/auto-service-1.0-rc2-sources.jarbin0 -> 7849 bytes
-rw-r--r--lib/auto-service-1.0-rc2.jarbin0 -> 10370 bytes
-rw-r--r--lib/auto-service-1.0-rc2.jar.txt203
-rw-r--r--lib/auto-value-1.0-sources.jarbin0 -> 54600 bytes
-rw-r--r--lib/auto-value-1.0.jarbin0 -> 1787111 bytes
-rw-r--r--lib/auto-value-1.0.jar.txt203
-rw-r--r--lib/google-java-format-0.1-20151017.042846-2.jarbin0 -> 11093476 bytes
-rw-r--r--lib/google-java-format-0.1-20151017.042846-2.jar.txtbin0 -> 173590 bytes
-rw-r--r--lib/javax-inject-src.jarbin0 -> 11049 bytes
-rw-r--r--lib/javax-inject.jarbin0 -> 2497 bytes
-rw-r--r--lib/javax-inject.jar.txt203
-rw-r--r--pom.xml229
-rw-r--r--producers/pom.xml58
-rw-r--r--producers/src/main/java/dagger/producers/Produced.java133
-rw-r--r--producers/src/main/java/dagger/producers/Producer.java104
-rw-r--r--producers/src/main/java/dagger/producers/ProducerModule.java40
-rw-r--r--producers/src/main/java/dagger/producers/Produces.java70
-rw-r--r--producers/src/main/java/dagger/producers/ProductionComponent.java83
-rw-r--r--producers/src/main/java/dagger/producers/internal/AbstractProducer.java78
-rw-r--r--producers/src/main/java/dagger/producers/internal/Producers.java130
-rw-r--r--producers/src/main/java/dagger/producers/internal/SetProducer.java85
-rw-r--r--producers/src/main/java/dagger/producers/monitoring/ProducerMonitor.java77
-rw-r--r--producers/src/main/java/dagger/producers/monitoring/ProducerToken.java62
-rw-r--r--producers/src/main/java/dagger/producers/monitoring/ProductionComponentMonitor.java53
-rw-r--r--producers/src/main/java/dagger/producers/monitoring/package-info.java23
-rw-r--r--producers/src/test/java/dagger/producers/ProducedTest.java60
-rw-r--r--producers/src/test/java/dagger/producers/internal/AbstractProducerTest.java127
-rw-r--r--producers/src/test/java/dagger/producers/internal/ProducersTest.java123
-rw-r--r--producers/src/test/java/dagger/producers/internal/SetProducerTest.java82
-rwxr-xr-xutil/generate-latest-docs.sh25
-rwxr-xr-xutil/mvn-deploy.sh21
-rwxr-xr-xutil/publish-snapshot-on-commit.sh12
-rw-r--r--util/settings.xml9
1120 files changed, 53522 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..0c4de1d78
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.iml
+*.ipr
+*.iws
+.idea
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 000000000..08b6af514
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,88 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+# build dagger2 host jar
+# ============================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := dagger2-host
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_SRC_FILES := $(call all-java-files-under, core/src/main/java/)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ dagger2-inject-host \
+ guavalib
+
+#LOCAL_JACK_ENABLED := disabled
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# build dagger2 producers host jar
+# ============================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := dagger2-producers-host
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_SRC_FILES := $(call all-java-files-under, producers/src/main/java/)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ dagger2-host \
+ dagger2-inject-host \
+ guavalib
+
+#LOCAL_JACK_ENABLED := disabled
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# build dagger2 compiler host jar
+# ============================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := dagger2-compiler-host
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_SRC_FILES := $(call all-java-files-under, compiler/src/main/java/)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ dagger2-host \
+ dagger2-auto-common-host \
+ dagger2-auto-factory-host \
+ dagger2-auto-service-host \
+ dagger2-auto-value-host \
+ dagger2-google-java-format \
+ dagger2-inject-host \
+ dagger2-producers-host \
+ guavalib
+
+#LOCAL_JACK_ENABLED := disabled
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# Build host dependencies.
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_PREBUILT_JAVA_LIBRARIES := \
+ dagger2-auto-common-host:lib/auto-common-1.0-20151022.071545-39$(COMMON_JAVA_PACKAGE_SUFFIX) \
+ dagger2-auto-factory-host:lib/auto-factory-1.0-20150915.183854-35$(COMMON_JAVA_PACKAGE_SUFFIX) \
+ dagger2-auto-service-host:lib/auto-service-1.0-rc2$(COMMON_JAVA_PACKAGE_SUFFIX) \
+ dagger2-auto-value-host:lib/auto-value-1.0$(COMMON_JAVA_PACKAGE_SUFFIX) \
+ dagger2-google-java-format:lib/google-java-format-0.1-20151017.042846-2$(COMMON_JAVA_PACKAGE_SUFFIX) \
+ dagger2-inject-host:lib/javax-inject$(COMMON_JAVA_PACKAGE_SUFFIX) \
+
+include $(BUILD_HOST_PREBUILT)
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 000000000..957840eca
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,40 @@
+Change Log
+==========
+
+Version 1.2.0 *(2013-12-13)*
+----------------------------
+
+ * Numerous performance improvements in both the compiler and runtime.
+ * Use more efficient `String` concatenation.
+ * Module adapters are now stateless.
+ * Use read/write locks over global locks.
+ * Reflective constructor invocation is now cached with `Class.newInstance`.
+ * Avoid re-linking all bindings when calling `.plus()`.
+ * Set bindings are now unioned when calling `.plus()`.
+ * Fix: Tolerate missing type information during compilation by deferring writing
+ module adapters.
+
+
+Version 1.1.0 *(2013-08-05)*
+----------------------------
+
+ * Module loading now requires code generation via the 'dagger-compiler' artifact.
+ * Allow multiple contributions to Set binding via `Provides.Type.SET_VALUES`.
+ * Request classloading from the classloader of the requesting object, not the current thread's
+ context classloader.
+ * Cache class loading at the root injector to reduce costs of loading adapters.
+ * Fix: Primitive array types are no longer incorrectly changed to their boxed type.
+ * Update JavaWriter to 2.1.1.
+
+
+Version 1.0.1 *(2013-06-03)*
+----------------------------
+
+ * Explicitly forbid declaring `@Inject` on a class type (e.g., `@Inject class Foo {}`).
+ * Update JavaWriter to 1.0.5.
+
+
+Version 1.0.0 *(2013-05-07)*
+----------------------------
+
+Initial release.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..087af22cd
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,37 @@
+Contributing
+============
+
+If you would like to contribute code to Dagger you can do so through GitHub by
+forking the repository and sending a pull request.
+
+When submitting code, please make every effort to follow existing conventions
+and style in order to keep the code as readable as possible.
+
+Where appropriate, please provide unit tests or integration tests. Unit tests
+should be JUnit based tests and can use either standard JUnit assertions or
+FEST assertions and be added to `<project>/src/test/java`. Changes to build-time
+behaviour (such as changes to code generation or graph validation) should go into
+small maven projects using the `maven-invoker-plugin`. Examples of this are in
+`core/src/it` and can include bean-shell verification scripts and other
+facilities provided by `maven-invoker-plugin`.
+
+Please make sure your code compiles by running `mvn clean verify` which will
+execute both unit and integration test phases. Additionally, consider using
+http://travis-ci.org to validate your branches before you even put them into
+pull requests. All pull requests will be validated by Travis-ci in any case
+and must pass before being merged.
+
+If you are adding or modifying files you may add your own copyright line, but
+please ensure that the form is consistent with the existing files, and please
+note that a Square, Inc. copyright line must appear in every copyright notice.
+All files are released with the Apache 2.0 license.
+
+Checkstyle failures during compilation indicate errors in your style and will
+be displayed in the console output of the build (including in Travis-CI output),
+or can be viewed in the `checkstyle-result.xml` file.
+
+Before your code can be accepted into the project you must sign the
+[Individual Contributor License Agreement (CLA)][1].
+
+
+ [1]: https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ 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/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/README.android b/README.android
new file mode 100644
index 000000000..94ed4714c
--- /dev/null
+++ b/README.android
@@ -0,0 +1,8 @@
+URL: https://github.com/google/dagger.git
+License: Apache 2
+Description: "Dagger 2 - A fast dependency injector for Android and Java"
+
+Version: fdf1a9e905782dd2885799c6b34d9f1da842a7e1
+
+Local Patches:
+ None
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..3c0e8bc13
--- /dev/null
+++ b/README.md
@@ -0,0 +1,134 @@
+Dagger 2
+========
+
+A fast dependency injector for Android and Java.
+
+About Google's Fork
+-------------
+
+Dagger 2 is a compile-time evolution approach to dependency injection. Taking the approach
+started in Dagger 1.x to its ultimate conclusion, Dagger 2.0 eliminates all reflection, and
+improves code clarity by removing the traditional ObjectGraph/Injector in favor of
+user-specified @Component interfaces.
+
+This github project represents the Dagger 2 development stream. The earlier
+[project page][square] (Square, Inc's repository) represents the earlier 1.0 development stream.
+Both versions have benefitted from strong involvement from Square, Google, and other contributors.
+
+## [Dagger 2's main documentation website can be found here.][website]
+
+Status
+------
+
+ - ***Release Version:* 2.0.1**
+ - ***Snapshot Version:* 2.1-SNAPSHOT**
+
+Dagger is currently in active development, primarily internally at Google, with regular pushes
+to the open-source community. Snapshot releases are auto-deployed to sonatype's central maven
+repository on a clean build with the version `2.1-SNAPSHOT`.
+
+Documentation
+-------------
+
+You can [find the dagger documentation here][website] which has extended usage
+instructions and other useful information. Substantial usage information can be
+found in the [API documentation][20api].
+
+You can also learn more from [the original proposal][proposal],
+[this talk by Greg Kick][gaktalk], and on the dagger-discuss@googlegroups.com
+mailing list.
+
+Installation
+--------
+
+You will need to include the `dagger-2.0.1.jar` in your application's runtime.
+In order to activate code generation and generate implementations to manage
+your graph you will need to include `dagger-compiler-2.0.1.jar` in your build
+at compile time.
+
+In a Maven project, include the `dagger` artifact in the dependencies section
+of your `pom.xml` and the `dagger-compiler` artifact as either an `optional` or
+`provided` dependency:
+
+```xml
+<dependencies>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger</artifactId>
+ <version>2.0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-compiler</artifactId>
+ <version>2.0.1</version>
+ <optional>true</optional>
+ </dependency>
+</dependencies>
+```
+
+If you use the beta `dagger-producers` extension (which supplies parallelizable execution graphs),
+then add this to your maven configuration:
+
+```xml
+<dependencies>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-producers</artifactId>
+ <version>2.0-beta</version>
+ </dependency>
+</dependencies>
+```
+
+
+### Download
+
+ * 2.x (google/dagger)
+ * [Dagger 2.0 Documentation][website]
+ * [Dagger 2.0 Javadocs][20api]
+ * [Dagger development Javadocs][latestapi] (from the `master` branch on GitHub)
+ * [Google's Dagger project site on GitHub][project]
+ * <a href="https://plus.google.com/118328287768685565185" rel="publisher">Google+ Dagger Project Page</a>
+ * [Google+ Dagger Users Community][community]
+ * 1.x (square/dagger)
+ * [Square's original Dagger project site on GitHub][square]
+ * [Square Open Source Community][squarecommunity]
+
+
+If you do not use maven, gradle, ivy, or other build systems that consume maven-style binary
+artifacts, they can be downloaded directly via the [Maven Central Repository][mavensearch].
+
+Developer snapshots are available from [Sonatype's snapshot repository][dagger-snap], and
+are built on a clean build of the GitHub project's master branch.
+
+License
+-------
+
+ Copyright 2012 Square, Inc.
+ Copyright 2012 Google, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+
+ [mavensearch]: http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.google.dagger%22
+ [dagger-snap]: https://oss.sonatype.org/content/repositories/snapshots/com/google/dagger/
+ [website]: http://google.github.io/dagger
+ [latestapi]: http://google.github.io/dagger/api/latest/
+ [20api]: http://google.github.io/dagger/api/2.0/
+ [gaktalk]: https://www.youtube.com/watch?v=oK_XtfXPkqw
+ [proposal]: https://github.com/square/dagger/issues/366
+ [project]: http://github.com/google/dagger/
+ [community]: https://plus.google.com/communities/111933036769103367883
+ [square]: http://github.com/square/dagger/
+ [squarecommunity]: https://plus.google.com/communities/109244258569782858265
+
diff --git a/checkstyle.xml b/checkstyle.xml
new file mode 100644
index 000000000..e7ffbc0d5
--- /dev/null
+++ b/checkstyle.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0"?>
+<!DOCTYPE module PUBLIC
+ "-//Puppy Crawl//DTD Check Configuration 1.2//EN"
+ "http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
+
+<module name="Checker">
+ <!--module name="NewlineAtEndOfFile"/-->
+ <module name="FileLength"/>
+ <module name="FileTabCharacter"/>
+
+ <!-- Trailing spaces -->
+ <module name="RegexpSingleline">
+ <property name="format" value="\s+$"/>
+ <property name="message" value="Line has trailing spaces."/>
+ </module>
+
+ <!-- Space after 'for' and 'if' -->
+ <module name="RegexpSingleline">
+ <property name="format" value="^\s*(for|if)[^ ]"/>
+ <property name="message" value="Space needed before opening parenthesis."/>
+ </module>
+
+ <!-- For each spacing -->
+ <module name="RegexpSingleline">
+ <property name="format" value="^\s*for \(.*?([^ ]:|:[^ ])"/>
+ <property name="message" value="Space needed around ':' character."/>
+ </module>
+
+ <module name="TreeWalker">
+ <property name="cacheFile" value="${checkstyle.cache.file}"/>
+
+ <!-- Checks for Javadoc comments. -->
+ <!-- See http://checkstyle.sf.net/config_javadoc.html -->
+ <!--module name="JavadocMethod"/-->
+ <!--module name="JavadocType"/-->
+ <!--module name="JavadocVariable"/-->
+ <!--module name="JavadocStyle"/-->
+
+
+ <!-- Checks for Naming Conventions. -->
+ <!-- See http://checkstyle.sf.net/config_naming.html -->
+ <!--<module name="ConstantName"/>-->
+ <module name="LocalFinalVariableName"/>
+ <module name="LocalVariableName"/>
+ <module name="MemberName"/>
+ <module name="MethodName"/>
+ <module name="PackageName"/>
+ <module name="ParameterName"/>
+ <module name="StaticVariableName"/>
+ <module name="TypeName"/>
+
+
+ <!-- Checks for imports -->
+ <!-- See http://checkstyle.sf.net/config_import.html -->
+ <module name="AvoidStarImport"/>
+ <module name="IllegalImport"/> <!-- defaults to sun.* packages -->
+ <module name="RedundantImport"/>
+ <module name="UnusedImports">
+ <property name="processJavadoc" value="true"/>
+ </module>
+
+ <!-- Checks for Size Violations. -->
+ <!-- See http://checkstyle.sf.net/config_sizes.html -->
+ <module name="LineLength">
+ <property name="max" value="100"/>
+ </module>
+ <module name="MethodLength">
+ <property name="max" value="200"/>
+ </module>
+ <!--module name="ParameterNumber"/-->
+
+
+ <!-- Checks for whitespace -->
+ <!-- See http://checkstyle.sf.net/config_whitespace.html -->
+ <module name="GenericWhitespace"/>
+ <module name="EmptyForIteratorPad"/>
+ <module name="MethodParamPad"/>
+ <module name="NoWhitespaceAfter"/>
+ <module name="NoWhitespaceBefore"/>
+ <module name="OperatorWrap"/>
+ <module name="ParenPad"/>
+ <module name="TypecastParenPad"/>
+ <module name="WhitespaceAfter"/>
+ <module name="WhitespaceAround">
+ <property name="allowEmptyConstructors" value="true" />
+ <property name="allowEmptyMethods" value="true" />
+ </module>
+
+
+ <!-- Modifier Checks -->
+ <!-- See http://checkstyle.sf.net/config_modifiers.html -->
+ <!--module name="ModifierOrder"/-->
+ <module name="RedundantModifier"/>
+
+
+ <!-- Checks for blocks. You know, those {}'s -->
+ <!-- See http://checkstyle.sf.net/config_blocks.html -->
+ <!--module name="AvoidNestedBlocks"/-->
+ <!--module name="EmptyBlock"/-->
+ <module name="LeftCurly"/>
+ <!--module name="NeedBraces"/-->
+ <module name="RightCurly"/>
+
+
+ <!-- Checks for common coding problems -->
+ <!-- See http://checkstyle.sf.net/config_coding.html -->
+ <!--module name="AvoidInlineConditionals"/-->
+ <module name="CovariantEquals"/>
+ <module name="EmptyStatement"/>
+ <!--<module name="EqualsAvoidNull"/>-->
+ <module name="EqualsHashCode"/>
+ <!--module name="HiddenField"/-->
+ <module name="IllegalInstantiation"/>
+ <!--<module name="InnerAssignment"/>-->
+ <!--module name="MagicNumber"/-->
+ <module name="MissingSwitchDefault"/>
+ <module name="RedundantThrows"/>
+ <module name="SimplifyBooleanExpression"/>
+ <module name="SimplifyBooleanReturn"/>
+
+ <!-- Checks for class design -->
+ <!-- See http://checkstyle.sf.net/config_design.html -->
+ <!--module name="DesignForExtension"/-->
+ <!--module name="FinalClass"/-->
+ <!--module name="HideUtilityClassConstructor"/-->
+ <!--module name="InterfaceIsType"/-->
+ <!--module name="VisibilityModifier"/-->
+
+
+ <!-- Miscellaneous other checks. -->
+ <!-- See http://checkstyle.sf.net/config_misc.html -->
+ <!--module name="ArrayTypeStyle"/-->
+ <!--module name="FinalParameters"/-->
+ <!--module name="TodoComment"/-->
+ <module name="UpperEll"/>
+ </module>
+</module>
diff --git a/compiler/dependency-reduced-pom.xml b/compiler/dependency-reduced-pom.xml
new file mode 100644
index 000000000..504f9ffa7
--- /dev/null
+++ b/compiler/dependency-reduced-pom.xml
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>dagger-parent</artifactId>
+ <groupId>com.google.dagger</groupId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>dagger-compiler</artifactId>
+ <name>Dagger Compiler</name>
+ <description>Tools to generate Dagger injection and module adapters from annotated code and validate them.</description>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-compile</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <annotationProcessors>
+ <annotationProcessor>com.google.auto.value.processor.AutoValueProcessor</annotationProcessor>
+ <annotationProcessor>com.google.auto.service.processor.AutoServiceProcessor</annotationProcessor>
+ </annotationProcessors>
+ </configuration>
+ </execution>
+ <execution>
+ <id>default-test-compile</id>
+ <goals>
+ <goal>testCompile</goal>
+ </goals>
+ <configuration>
+ <annotationProcessors>
+ <annotationProcessor>dagger.internal.codegen.ComponentProcessor</annotationProcessor>
+ </annotationProcessors>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>integration-test</id>
+ <goals>
+ <goal>install</goal>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <addTestClassPath>true</addTestClassPath>
+ <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
+ <cloneClean>true</cloneClean>
+ <profiles>
+ <profile>!sonatype-oss-release</profile>
+ </profiles>
+ <pomIncludes>
+ <pomInclude>*/pom.xml</pomInclude>
+ </pomIncludes>
+ <localRepositoryPath>${project.build.directory}/it-repo</localRepositoryPath>
+ <filterProperties>
+ <dagger.version>${project.version}</dagger.version>
+ <dagger.groupId>${project.groupId}</dagger.groupId>
+ </filterProperties>
+ <streamLogs>true</streamLogs>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>2.3</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <minimizeJar>true</minimizeJar>
+ <artifactSet>
+ <excludes>
+ <exclude>com.google.guava</exclude>
+ <exclude>com.google.auto.service</exclude>
+ <exclude>com.google.auto.value</exclude>
+ <exclude>com.google.dagger:dagger</exclude>
+ <exclude>com.google.dagger:dagger-producers</exclude>
+ <exclude>javax.inject</exclude>
+ </excludes>
+ </artifactSet>
+ <relocations>
+ <relocation>
+ <pattern>com.google.auto.common</pattern>
+ <shadedPattern>dagger.shaded.auto.common</shadedPattern>
+ </relocation>
+ </relocations>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-producers</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto.service</groupId>
+ <artifactId>auto-service</artifactId>
+ <version>1.0-rc2</version>
+ <scope>compile</scope>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>18.0</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto.value</groupId>
+ <artifactId>auto-value</artifactId>
+ <version>1.0</version>
+ <scope>compile</scope>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <artifactId>hamcrest-core</artifactId>
+ <groupId>org.hamcrest</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.testing.compile</groupId>
+ <artifactId>compile-testing</artifactId>
+ <version>0.7</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <artifactId>tools</artifactId>
+ <groupId>com.sun</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava-testlib</artifactId>
+ <version>18.0</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <artifactId>jsr305</artifactId>
+ <groupId>com.google.code.findbugs</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <artifactId>objenesis</artifactId>
+ <groupId>org.objenesis</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>hamcrest-core</artifactId>
+ <groupId>org.hamcrest</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <version>0.26</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
+
diff --git a/compiler/pom.xml b/compiler/pom.xml
new file mode 100644
index 000000000..40e0fa27d
--- /dev/null
+++ b/compiler/pom.xml
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2012 Square, Inc.
+ Copyright (C) 2012 Google, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-parent</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>dagger-compiler</artifactId>
+ <name>Dagger Compiler</name>
+ <description>
+ Tools to generate Dagger injection and module adapters from annotated code and validate them.
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>dagger</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>dagger-producers</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto</groupId>
+ <artifactId>auto-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto.service</groupId>
+ <artifactId>auto-service</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <!-- TODO(gak): Restore this presumably as javapoet when appropriate.
+ <dependency>
+ <groupId>com.squareup</groupId>
+ <artifactId>javawriter</artifactId>
+ </dependency>
+ -->
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.auto.value</groupId>
+ <artifactId>auto-value</artifactId>
+ <optional>true</optional>
+ <version>1.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>dagger</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <classifier>tests</classifier>
+ </dependency>
+ <dependency>
+ <groupId>com.google.testing.compile</groupId>
+ <artifactId>compile-testing</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava-testlib</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-compile</id>
+ <goals><goal>compile</goal></goals>
+ <configuration>
+ <annotationProcessors>
+ <annotationProcessor>com.google.auto.value.processor.AutoValueProcessor</annotationProcessor>
+ <annotationProcessor>com.google.auto.service.processor.AutoServiceProcessor</annotationProcessor>
+ </annotationProcessors>
+ </configuration>
+ </execution>
+ <execution>
+ <id>default-test-compile</id>
+ <goals><goal>testCompile</goal></goals>
+ <configuration>
+ <annotationProcessors>
+ <annotationProcessor>dagger.internal.codegen.ComponentProcessor</annotationProcessor>
+ </annotationProcessors>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <configuration>
+ <addTestClassPath>true</addTestClassPath>
+ <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
+ <cloneClean>true</cloneClean>
+ <profiles>
+ <profile>!sonatype-oss-release</profile>
+ </profiles>
+ <pomIncludes>
+ <pomInclude>*/pom.xml</pomInclude>
+ </pomIncludes>
+ <localRepositoryPath>${project.build.directory}/it-repo</localRepositoryPath>
+ <filterProperties>
+ <dagger.version>${project.version}</dagger.version>
+ <dagger.groupId>${project.groupId}</dagger.groupId>
+ </filterProperties>
+ <streamLogs>true</streamLogs>
+ </configuration>
+ <executions>
+ <execution>
+ <id>integration-test</id>
+ <goals>
+ <goal>install</goal>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>2.3</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <minimizeJar>true</minimizeJar>
+ <artifactSet>
+ <excludes>
+ <!-- guava which has a consistent API and whose public types we vend in producers -->
+ <exclude>com.google.guava</exclude>
+ <!-- annotation processors dagger uses to be built, not to operate -->
+ <exclude>com.google.auto.service</exclude>
+ <exclude>com.google.auto.value</exclude>
+ <!-- projects should depend on api projects directly -->
+ <exclude>com.google.dagger:dagger</exclude>
+ <exclude>com.google.dagger:dagger-producers</exclude>
+ <exclude>javax.inject</exclude>
+ </excludes>
+ </artifactSet>
+ <relocations>
+ <relocation>
+ <pattern>com.google.auto.common</pattern>
+ <shadedPattern>dagger.shaded.auto.common</shadedPattern>
+ </relocation>
+ </relocations>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/compiler/src/it/functional-tests/pom.xml b/compiler/src/it/functional-tests/pom.xml
new file mode 100644
index 000000000..1eca20c14
--- /dev/null
+++ b/compiler/src/it/functional-tests/pom.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2014 Google, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-parent</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+ <groupId>dagger.tests</groupId>
+ <artifactId>functional-tests</artifactId>
+ <name>Functional Tests</name>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-compiler</artifactId>
+ <version>${project.version}</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <!-- For map-bindings -->
+ <groupId>com.google.auto.value</groupId>
+ <artifactId>auto-value</artifactId>
+ <version>${auto.value.version}</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <!-- For map-bindings -->
+ <groupId>com.google.auto.factory</groupId>
+ <artifactId>auto-factory</artifactId>
+ <version>${auto.factory.version}</version>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ <configuration>
+ <source>1.7</source>
+ <target>1.7</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <failsOnError>false</failsOnError>
+ <consoleOutput>true</consoleOutput>
+ <configLocation>../../../../checkstyle.xml</configLocation>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>compile</phase>
+ <goals>
+ <goal>checkstyle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/compiler/src/it/functional-tests/src/main/java/test/A.java b/compiler/src/it/functional-tests/src/main/java/test/A.java
new file mode 100644
index 000000000..030f8556c
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/A.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import javax.inject.Inject;
+
+class A {
+ @Inject A() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/AbstractMembersInjectingBaseClass.java b/compiler/src/it/functional-tests/src/main/java/test/AbstractMembersInjectingBaseClass.java
new file mode 100644
index 000000000..4fb0f7832
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/AbstractMembersInjectingBaseClass.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import javax.inject.Inject;
+
+abstract class AbstractMembersInjectingBaseClass {
+ @Inject Thing thing;
+}
+
diff --git a/compiler/src/it/functional-tests/src/main/java/test/AbstractMiddleClassWithoutMembers.java b/compiler/src/it/functional-tests/src/main/java/test/AbstractMiddleClassWithoutMembers.java
new file mode 100644
index 000000000..89e94bd2f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/AbstractMiddleClassWithoutMembers.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+abstract class AbstractMiddleClassWithoutMembers extends AbstractMembersInjectingBaseClass {
+}
+
diff --git a/compiler/src/it/functional-tests/src/main/java/test/B.java b/compiler/src/it/functional-tests/src/main/java/test/B.java
new file mode 100644
index 000000000..dec8e2e58
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/B.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import javax.inject.Inject;
+
+class B {
+ @Inject B() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/BasicAbstractClassComponent.java b/compiler/src/it/functional-tests/src/main/java/test/BasicAbstractClassComponent.java
new file mode 100644
index 000000000..78f77dfb8
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/BasicAbstractClassComponent.java
@@ -0,0 +1,29 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import dagger.Component;
+
+/**
+ * This component tests behavior equivalent to {@link BasicComponent}, but as an abstract class
+ * rather than an interface.
+ */
+@Component(modules = PrimitivesModule.class)
+abstract class BasicAbstractClassComponent implements BasicComponent {
+ void throwAParty() {
+ throw new RuntimeException("Paaarrrrrtaaaaaaaay!");
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/BasicComponent.java b/compiler/src/it/functional-tests/src/main/java/test/BasicComponent.java
new file mode 100644
index 000000000..a04607dd4
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/BasicComponent.java
@@ -0,0 +1,81 @@
+/*
+* Copyright (C) 2014 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import dagger.Component;
+import dagger.Lazy;
+import dagger.MembersInjector;
+import javax.inject.Provider;
+
+@Component(modules = PrimitivesModule.class)
+interface BasicComponent extends Injector<Thing> {
+ byte getByte();
+ char getChar();
+ short getShort();
+ int getInt();
+ long getLong();
+ boolean getBoolean();
+ float getFloat();
+ double getDouble();
+
+ Byte getBoxedByte();
+ Character getBoxedChar();
+ Short getBoxedShort();
+ Integer getBoxedInt();
+ Long getBoxedLong();
+ Boolean getBoxedBoolean();
+ Float getBoxedFloat();
+ Double getBoxedDouble();
+
+ Provider<Byte> getByteProvider();
+ Provider<Character> getCharProvider();
+ Provider<Short> getShortProvider();
+ Provider<Integer> getIntProvider();
+ Provider<Long> getLongProvider();
+ Provider<Boolean> getBooleanProvider();
+ Provider<Float> getFloatProvider();
+ Provider<Double> getDoubleProvider();
+
+ byte[] getByteArray();
+ char[] getCharArray();
+ short[] getShortArray();
+ int[] getIntArray();
+ long[] getLongArray();
+ boolean[] getBooleanArray();
+ float[] getFloatArray();
+ double[] getDoubleArray();
+
+ Provider<byte[]> getByteArrayProvider();
+ Provider<char[]> getCharArrayProvider();
+ Provider<short[]> getShortArrayProvider();
+ Provider<int[]> getIntArrayProvider();
+ Provider<long[]> getLongArrayProvider();
+ Provider<boolean[]> getBooleanArrayProvider();
+ Provider<float[]> getFloatArrayProvider();
+ Provider<double[]> getDoubleArrayProvider();
+
+ Object noOpMembersInjection(Object obviouslyDoesNotHaveMembersToInject);
+
+ Thing thing();
+ InjectedThing injectedThing();
+ Provider<InjectedThing> injectedThingProvider();
+ Lazy<InjectedThing> lazyInjectedThing();
+ MembersInjector<InjectedThing> injectedThingMembersInjector();
+
+ TypeWithInheritedMembersInjection typeWithInheritedMembersInjection();
+ MembersInjector<TypeWithInheritedMembersInjection>
+ typeWithInheritedMembersInjectionMembersInjector();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/BooleanKey.java b/compiler/src/it/functional-tests/src/main/java/test/BooleanKey.java
new file mode 100644
index 000000000..4cef79e02
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/BooleanKey.java
@@ -0,0 +1,23 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import dagger.MapKey;
+
+@MapKey(unwrapValue = true)
+@interface BooleanKey {
+ boolean value();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/BoundedGenericComponent.java b/compiler/src/it/functional-tests/src/main/java/test/BoundedGenericComponent.java
new file mode 100644
index 000000000..b30522f57
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/BoundedGenericComponent.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import dagger.Component;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+@Component(modules = BoundedGenericModule.class)
+interface BoundedGenericComponent {
+ BoundedGenerics<Integer, ArrayList<String>, LinkedList<CharSequence>, Integer, List<Integer>>
+ bounds1();
+ BoundedGenerics<Double, LinkedList<String>, LinkedList<Comparable<String>>, Double, Set<Double>>
+ bounds2();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/BoundedGenericModule.java b/compiler/src/it/functional-tests/src/main/java/test/BoundedGenericModule.java
new file mode 100644
index 000000000..6bd7be4fb
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/BoundedGenericModule.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+@Module
+class BoundedGenericModule {
+
+ @Provides
+ Integer provideInteger() {
+ return 1;
+ }
+
+ @Provides
+ Double provideDouble() {
+ return 2d;
+ }
+
+ @Provides
+ ArrayList<String> provideArrayListString() {
+ ArrayList<String> list = new ArrayList<>();
+ list.add("arrayListOfString");
+ return list;
+ }
+
+ @Provides
+ LinkedList<String> provideLinkedListString() {
+ LinkedList<String> list = new LinkedList<>();
+ list.add("linkedListOfString");
+ return list;
+ }
+
+ @Provides
+ LinkedList<CharSequence> provideLinkedListCharSeq() {
+ LinkedList<CharSequence> list = new LinkedList<>();
+ list.add("linkedListOfCharSeq");
+ return list;
+ }
+
+ @Provides
+ @SuppressWarnings("unchecked")
+ LinkedList<Comparable<String>> provideArrayListOfComparableString() {
+ LinkedList<Comparable<String>> list = new LinkedList<>();
+ list.add("arrayListOfComparableOfString");
+ return list;
+ }
+
+ @Provides
+ List<Integer> provideListOfInteger() {
+ LinkedList<Integer> list = new LinkedList<>();
+ list.add(3);
+ return list;
+ }
+
+ @Provides
+ Set<Double> provideSetOfDouble() {
+ Set<Double> set = new HashSet<>();
+ set.add(4d);
+ return set;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/BoundedGenerics.java b/compiler/src/it/functional-tests/src/main/java/test/BoundedGenerics.java
new file mode 100644
index 000000000..e26d64351
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/BoundedGenerics.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import java.util.List;
+import javax.inject.Inject;
+
+class BoundedGenerics<A extends Number & Comparable<? super A>,
+ B extends List<? extends CharSequence>,
+ C extends List<? super String>,
+ D extends A,
+ E extends Iterable<D>> {
+
+ final A a;
+ final B b;
+ final C c;
+ final D d;
+ final E e;
+
+ @Inject BoundedGenerics(A a, B b, C c, D d, E e) {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ this.d = d;
+ this.e = e;
+ }
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ByteKey.java b/compiler/src/it/functional-tests/src/main/java/test/ByteKey.java
new file mode 100644
index 000000000..8e739bd4a
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ByteKey.java
@@ -0,0 +1,23 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import dagger.MapKey;
+
+@MapKey(unwrapValue = true)
+@interface ByteKey {
+ byte value();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/CharKey.java b/compiler/src/it/functional-tests/src/main/java/test/CharKey.java
new file mode 100644
index 000000000..a4f4e29c8
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/CharKey.java
@@ -0,0 +1,23 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import dagger.MapKey;
+
+@MapKey(unwrapValue = true)
+@interface CharKey {
+ char value();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ChildDoubleModule.java b/compiler/src/it/functional-tests/src/main/java/test/ChildDoubleModule.java
new file mode 100644
index 000000000..09a1e6b72
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ChildDoubleModule.java
@@ -0,0 +1,21 @@
+package test;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.ArrayList;
+import java.util.List;
+
+@Module
+class ChildDoubleModule extends ParentModule<Double, String, List<Double>> {
+
+ @Provides Double provideDouble() {
+ return 3d;
+ }
+
+ @Provides List<Double> provideListOfDouble() {
+ List<Double> list = new ArrayList<>();
+ list.add(4d);
+ return list;
+ }
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ChildIntegerModule.java b/compiler/src/it/functional-tests/src/main/java/test/ChildIntegerModule.java
new file mode 100644
index 000000000..ac9c61207
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ChildIntegerModule.java
@@ -0,0 +1,21 @@
+package test;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.ArrayList;
+import java.util.List;
+
+@Module
+class ChildIntegerModule extends ParentModule<Integer, String, List<Integer>> {
+
+ @Provides Integer provideInteger() {
+ return 1;
+ }
+
+ @Provides List<Integer> provideListOfInteger() {
+ List<Integer> list = new ArrayList<>();
+ list.add(2);
+ return list;
+ }
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ComplexGenerics.java b/compiler/src/it/functional-tests/src/main/java/test/ComplexGenerics.java
new file mode 100644
index 000000000..e2e327494
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ComplexGenerics.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import dagger.Lazy;
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+class ComplexGenerics {
+
+ final Generic2<Generic<A>> g2ga;
+ final Lazy<Generic2<Generic<A>>> g2gaLazy;
+ final Provider<Generic2<Generic<A>>> g2gaProvider;
+ final Generic2<Generic<B>> g2gb;
+ final Lazy<Generic2<Generic<B>>> g2gbLazy;
+ final Provider<Generic2<Generic<B>>> g2gbProvider;
+ final Generic2<A> g2a;
+ final Generic<Generic2<A>> gg2a;
+ final Generic<Generic2<B>> gg2b;
+
+ @Inject ComplexGenerics(
+ Generic2<Generic<A>> g2ga,
+ Lazy<Generic2<Generic<A>>> g2gaLazy,
+ Provider<Generic2<Generic<A>>> g2gaProvider,
+ Generic2<Generic<B>> g2gb,
+ Lazy<Generic2<Generic<B>>> g2gbLazy,
+ Provider<Generic2<Generic<B>>> g2gbProvider,
+ Generic2<A> g2a,
+ Generic<Generic2<A>> gg2a,
+ Generic<Generic2<B>> gg2b) {
+ this.g2ga = g2ga;
+ this.g2gaLazy = g2gaLazy;
+ this.g2gaProvider = g2gaProvider;
+ this.g2gb = g2gb;
+ this.g2gbLazy = g2gbLazy;
+ this.g2gbProvider = g2gbProvider;
+ this.g2a = g2a;
+ this.gg2a = gg2a;
+ this.gg2b = gg2b;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ComponentDependsOnGeneratedCode.java b/compiler/src/it/functional-tests/src/main/java/test/ComponentDependsOnGeneratedCode.java
new file mode 100644
index 000000000..6ffe1e07d
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ComponentDependsOnGeneratedCode.java
@@ -0,0 +1,23 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import dagger.Component;
+
+@Component
+interface ComponentDependsOnGeneratedCode {
+ NeedsFactory needsFactory();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ComponentSupertypeDependsOnGeneratedCode.java b/compiler/src/it/functional-tests/src/main/java/test/ComponentSupertypeDependsOnGeneratedCode.java
new file mode 100644
index 000000000..f7460c989
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ComponentSupertypeDependsOnGeneratedCode.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import dagger.Component;
+
+@Component
+interface ComponentSupertypeDependsOnGeneratedCode
+ extends ComponentSupertypeDependsOnGeneratedCodeInterface {}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ComponentSupertypeDependsOnGeneratedCodeInterface.java b/compiler/src/it/functional-tests/src/main/java/test/ComponentSupertypeDependsOnGeneratedCodeInterface.java
new file mode 100644
index 000000000..fca90e0f3
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ComponentSupertypeDependsOnGeneratedCodeInterface.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+interface ComponentSupertypeDependsOnGeneratedCodeInterface {
+ NeedsFactory_SomethingFactory somethingFactory();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/Generic.java b/compiler/src/it/functional-tests/src/main/java/test/Generic.java
new file mode 100644
index 000000000..ee1aa0992
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/Generic.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import javax.inject.Inject;
+
+public class Generic<T> {
+ final T t;
+
+ @Inject public Generic(T t) {
+ this.t = t;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/Generic2.java b/compiler/src/it/functional-tests/src/main/java/test/Generic2.java
new file mode 100644
index 000000000..4a56df3ec
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/Generic2.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import javax.inject.Inject;
+
+public class Generic2<T> {
+ final T t;
+
+ @Inject Generic2(T t) {
+ this.t = t;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/GenericChild.java b/compiler/src/it/functional-tests/src/main/java/test/GenericChild.java
new file mode 100644
index 000000000..5c65dc03e
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/GenericChild.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import javax.inject.Inject;
+
+class GenericChild<T> extends GenericParent<T, B> {
+
+ A registeredA;
+ T registeredT;
+
+ @Inject GenericChild() {}
+
+ @Inject A a;
+ @Inject T t;
+
+ @Inject void registerA(A a) { this.registeredA = a; }
+ @Inject void registerT(T t) { this.registeredT = t; }
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/GenericComponent.java b/compiler/src/it/functional-tests/src/main/java/test/GenericComponent.java
new file mode 100644
index 000000000..da5b9b530
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/GenericComponent.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import dagger.Component;
+import test.sub.Exposed;
+import test.sub.PublicSubclass;
+
+@Component(modules = {ChildDoubleModule.class, ChildIntegerModule.class})
+interface GenericComponent {
+ ReferencesGeneric referencesGeneric();
+ GenericDoubleReferences<A> doubleGenericA();
+ GenericDoubleReferences<B> doubleGenericB();
+ ComplexGenerics complexGenerics();
+ GenericNoDeps<A> noDepsA();
+ GenericNoDeps<B> noDepsB();
+
+ void injectA(GenericChild<A> childA);
+ void injectB(GenericChild<B> childB);
+
+ Exposed exposed();
+ PublicSubclass publicSubclass();
+
+ Iterable<Integer> iterableInt();
+ Iterable<Double> iterableDouble();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/GenericDoubleReferences.java b/compiler/src/it/functional-tests/src/main/java/test/GenericDoubleReferences.java
new file mode 100644
index 000000000..6785c7c5f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/GenericDoubleReferences.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import javax.inject.Inject;
+
+class GenericDoubleReferences<T> {
+ final T t;
+ final T t2;
+ final Thing a;
+ final Thing a2;
+
+ @Inject GenericDoubleReferences(T t, Thing a, T t2, Thing a2) {
+ this.t = t;
+ this.a = a;
+ this.t2 = t2;
+ this.a2 = a2;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/GenericNoDeps.java b/compiler/src/it/functional-tests/src/main/java/test/GenericNoDeps.java
new file mode 100644
index 000000000..e065f7926
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/GenericNoDeps.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import javax.inject.Inject;
+
+class GenericNoDeps<T> {
+
+ @Inject GenericNoDeps() {}
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/GenericParent.java b/compiler/src/it/functional-tests/src/main/java/test/GenericParent.java
new file mode 100644
index 000000000..0e01f5f7e
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/GenericParent.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import javax.inject.Inject;
+
+class GenericParent<X, Y> {
+
+ X registeredX;
+ Y registeredY;
+ B registeredB;
+
+
+ @Inject GenericParent() {}
+
+ @Inject X x;
+ @Inject Y y;
+ @Inject B b;
+
+ @Inject void registerX(X x) { this.registeredX = x; }
+ @Inject void registerY(Y y) { this.registeredY = y; }
+ @Inject void registerB(B b) { this.registeredB = b; }
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/InjectedThing.java b/compiler/src/it/functional-tests/src/main/java/test/InjectedThing.java
new file mode 100644
index 000000000..73a46e8aa
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/InjectedThing.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import dagger.Lazy;
+import dagger.MembersInjector;
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+@SuppressWarnings("unused")
+final class InjectedThing {
+ @Inject byte primitiveByte;
+ @Inject char primitiveChar;
+ @Inject short primitiveShort;
+ @Inject int primitiveInt;
+ @Inject long primitiveLong;
+ @Inject boolean primitiveBoolean;
+ @Inject float primitiveFloat;
+ @Inject double primitiveDouble;
+
+ @Inject Provider<Byte> byteProvider;
+ @Inject Provider<Character> charProvider;
+ @Inject Provider<Short> shortProvider;
+ @Inject Provider<Integer> intProvider;
+ @Inject Provider<Long> longProvider;
+ @Inject Provider<Boolean> booleanProvider;
+ @Inject Provider<Float> floatProvider;
+ @Inject Provider<Double> doubleProvider;
+
+ @Inject Lazy<Byte> lazyByte;
+ @Inject Lazy<Character> lazyChar;
+ @Inject Lazy<Short> lazyShort;
+ @Inject Lazy<Integer> lazyInt;
+ @Inject Lazy<Long> lazyLong;
+ @Inject Lazy<Boolean> lazyBoolean;
+ @Inject Lazy<Float> lazyFloat;
+ @Inject Lazy<Double> lazyDouble;
+
+ @Inject Byte boxedBype;
+ @Inject Character boxedChar;
+ @Inject Short boxedShort;
+ @Inject Integer boxedInt;
+ @Inject Long boxedLong;
+ @Inject Boolean boxedBoolean;
+ @Inject Float boxedFloat;
+ @Inject Double boxedDouble;
+
+ @Inject byte[] byteArray;
+ @Inject char[] charArray;
+ @Inject short[] shortArray;
+ @Inject int[] intArray;
+ @Inject long[] longArray;
+ @Inject boolean[] booleanArray;
+ @Inject float[] floatArray;
+ @Inject double[] doubleArray;
+
+ @Inject Provider<byte[]> byteArrayProvider;
+ @Inject Provider<char[]> charArrayProvider;
+ @Inject Provider<short[]> shortArrayProvider;
+ @Inject Provider<int[]> intArrayProvider;
+ @Inject Provider<long[]> longArrayProvider;
+ @Inject Provider<boolean[]> booleanArrayProvider;
+ @Inject Provider<float[]> floatArrayProvider;
+ @Inject Provider<double[]> doubleArrayProvider;
+
+ @Inject Lazy<byte[]> lazyByteArray;
+ @Inject Lazy<char[]> lazyCharArray;
+ @Inject Lazy<short[]> lazyShortArray;
+ @Inject Lazy<int[]> lazyIntArray;
+ @Inject Lazy<long[]> lazyLongArray;
+ @Inject Lazy<boolean[]> lazyBooleanArray;
+ @Inject Lazy<float[]> lazy;
+ @Inject Lazy<double[]> lazyDoubleArray;
+
+ @Inject Thing thing;
+ @Inject Provider<Thing> thingProvider;
+ @Inject Lazy<Thing> lazyThing;
+ @Inject MembersInjector<Thing> thingMembersInjector;
+
+ @Inject InjectedThing(
+ byte primitiveByte,
+ char primitiveChar,
+ short primitiveShort,
+ int primitiveInt,
+ long primitiveLong,
+ boolean primitiveBoolean,
+ float primitiveFloat,
+ double primitiveDouble,
+
+ Provider<Byte> byteProvider,
+ Provider<Character> charProvider,
+ Provider<Short> shortProvider,
+ Provider<Integer> intProvider,
+ Provider<Long> longProvider,
+ Provider<Boolean> booleanProvider,
+ Provider<Float> floatProvider,
+ Provider<Double> doubleProvider,
+
+ Lazy<Byte> lazyByte,
+ Lazy<Character> lazyChar,
+ Lazy<Short> lazyShort,
+ Lazy<Integer> lazyInt,
+ Lazy<Long> lazyLong,
+ Lazy<Boolean> lazyBoolean,
+ Lazy<Float> lazyFloat,
+ Lazy<Double> lazyDouble,
+
+ Byte boxedBype,
+ Character boxedChar,
+ Short boxedShort,
+ Integer boxedInt,
+ Long boxedLong,
+ Boolean boxedBoolean,
+ Float boxedFloat,
+ Double boxedDouble,
+
+ byte[] byteArray,
+ char[] charArray,
+ short[] shortArray,
+ int[] intArray,
+ long[] longArray,
+ boolean[] booleanArray,
+ float[] floatArray,
+ double[] doubleArray,
+
+ Provider<byte[]> byteArrayProvider,
+ Provider<char[]> charArrayProvider,
+ Provider<short[]> shortArrayProvider,
+ Provider<int[]> intArrayProvider,
+ Provider<long[]> longArrayProvider,
+ Provider<boolean[]> booleanArrayProvider,
+ Provider<float[]> floatArrayProvider,
+ Provider<double[]> doubleArrayProvider,
+
+ Lazy<byte[]> lazyByteArray,
+ Lazy<char[]> lazyCharArray,
+ Lazy<short[]> lazyShortArray,
+ Lazy<int[]> lazyIntArray,
+ Lazy<long[]> lazyLongArray,
+ Lazy<boolean[]> lazyBooleanArray,
+ Lazy<float[]> lazy,
+ Lazy<double[]> lazyDoubleArray,
+
+ Thing thing,
+ Provider<Thing> thingProvider,
+ Lazy<Thing> lazyThing,
+ MembersInjector<Thing> thingMembersInjector) {}
+
+ @Inject void primitiveByte(byte primitiveByte) {}
+ @Inject void primitiveChar(char primitiveChar) {}
+ @Inject void primitiveShort(short primitiveShort) {}
+ @Inject void primitiveInt(int primitiveInt) {}
+ @Inject void primitiveLong(long primitiveLong) {}
+ @Inject void primitiveBoolean(boolean primitiveBoolean) {}
+ @Inject void primitiveFloat(float primitiveFloat) {}
+ @Inject void primitiveDouble(double primitiveDouble) {}
+
+ @Inject void byteProvider(Provider<Byte> byteProvider) {}
+ @Inject void charProvider(Provider<Character> charProvider) {}
+ @Inject void shortProvider(Provider<Short> shortProvider) {}
+ @Inject void intProvider(Provider<Integer> intProvider) {}
+ @Inject void longProvider(Provider<Long> longProvider) {}
+ @Inject void booleanProvider(Provider<Boolean> booleanProvider) {}
+ @Inject void floatProvider(Provider<Float> floatProvider) {}
+ @Inject void doubleProvider(Provider<Double> doubleProvider) {}
+
+ @Inject void lazyByte(Lazy<Byte> lazyByte) {}
+ @Inject void lazyChar(Lazy<Character> lazyChar) {}
+ @Inject void lazyShort(Lazy<Short> lazyShort) {}
+ @Inject void lazyInt(Lazy<Integer> lazyInt) {}
+ @Inject void lazyLong(Lazy<Long> lazyLong) {}
+ @Inject void lazyBoolean(Lazy<Boolean> lazyBoolean) {}
+ @Inject void lazyFloat(Lazy<Float> lazyFloat) {}
+ @Inject void lazyDouble(Lazy<Double> lazyDouble) {}
+
+ @Inject void boxedBype(Byte boxedBype) {}
+ @Inject void boxedChar(Character boxedChar) {}
+ @Inject void boxedShort(Short boxedShort) {}
+ @Inject void boxedInt(Integer boxedInt) {}
+ @Inject void boxedLong(Long boxedLong) {}
+ @Inject void boxedBoolean(Boolean boxedBoolean) {}
+ @Inject void boxedFloat(Float boxedFloat) {}
+ @Inject void boxedDouble(Double boxedDouble) {}
+
+ @Inject void byteArray(byte[] byteArray) {}
+ @Inject void charArray(char[] charArray) {}
+ @Inject void shortArray(short[] shortArray) {}
+ @Inject void intArray(int[] intArray) {}
+ @Inject void longArray(long[] longArray) {}
+ @Inject void booleanArray(boolean[] booleanArray) {}
+ @Inject void floatArray(float[] floatArray) {}
+ @Inject void doubleArray(double[] doubleArray) {}
+
+ @Inject void byteArrayProvider(Provider<byte[]> byteArrayProvider) {}
+ @Inject void charArrayProvider(Provider<char[]> charArrayProvider) {}
+ @Inject void shortArrayProvider(Provider<short[]> shortArrayProvider) {}
+ @Inject void intArrayProvider(Provider<int[]> intArrayProvider) {}
+ @Inject void longArrayProvider(Provider<long[]> longArrayProvider) {}
+ @Inject void booleanArrayProvider(Provider<boolean[]> booleanArrayProvider) {}
+ @Inject void floatArrayProvider(Provider<float[]> floatArrayProvider) {}
+ @Inject void doubleArrayProvider(Provider<double[]> doubleArrayProvider) {}
+
+ @Inject void lazyByteArray(Lazy<byte[]> lazyByteArray) {}
+ @Inject void lazyCharArray(Lazy<char[]> lazyCharArray) {}
+ @Inject void lazyShortArray(Lazy<short[]> lazyShortArray) {}
+ @Inject void lazyIntArray(Lazy<int[]> lazyIntArray) {}
+ @Inject void lazyLongArray(Lazy<long[]> lazyLongArray) {}
+ @Inject void lazyBooleanArray(Lazy<boolean[]> lazyBooleanArray) {}
+ @Inject void lazy(Lazy<float[]> lazy) {}
+ @Inject void lazyDoubleArray(Lazy<double[]> lazyDoubleArray) {}
+
+ @Inject void thing(Thing thing) {}
+ @Inject void thingProvider(Provider<Thing> thingProvider) {}
+ @Inject void lazyThing(Lazy<Thing> lazyThing) {}
+ @Inject void thingMembersInjector(MembersInjector<Thing> thingMembersInjector) {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/Injector.java b/compiler/src/it/functional-tests/src/main/java/test/Injector.java
new file mode 100644
index 000000000..2a5798a03
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/Injector.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import dagger.Lazy;
+import dagger.MembersInjector;
+import javax.inject.Provider;
+
+/**
+ * A simple interface that exercises all forms of injection for a given type.
+ */
+interface Injector<T> {
+ T instance();
+ Provider<T> provider();
+ Lazy<T> lazy();
+ MembersInjector<T> membersInjector();
+ void injectMembers(T t);
+ T injectMembersAndReturn(T t);
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/MultibindingComponent.java b/compiler/src/it/functional-tests/src/main/java/test/MultibindingComponent.java
new file mode 100644
index 000000000..7cad3bd1a
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/MultibindingComponent.java
@@ -0,0 +1,52 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import dagger.Component;
+import dagger.mapkeys.StringKey;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Named;
+import javax.inject.Provider;
+import test.sub.ContributionsModule;
+
+@Component(
+ modules = {
+ MultibindingModule.class,
+ ContributionsModule.class
+ },
+ dependencies = MultibindingDependency.class
+)
+interface MultibindingComponent {
+ Map<String, String> map();
+ Map<String, Provider<String>> mapOfProviders();
+ Set<String> mapKeys();
+ Collection<String> mapValues();
+ Set<Integer> set();
+ Map<NestedAnnotationContainer.NestedWrappedKey, String> nestedKeyMap();
+ Map<Class<? extends Number>, String> numberClassKeyMap();
+ Map<Class<?>, String> classKeyMap();
+ Map<Long, String> longKeyMap();
+ Map<Integer, String> integerKeyMap();
+ Map<Short, String> shortKeyMap();
+ Map<Byte, String> byteKeyMap();
+ Map<Boolean, String> booleanKeyMap();
+ Map<Character, String> characterKeyMap();
+ Map<StringKey, String> unwrappedAnnotationKeyMap();
+ Map<WrappedAnnotationKey, String> wrappedAnnotationKeyMap();
+ @Named("complexQualifier") Set<String> complexQualifierStringSet();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/MultibindingDependency.java b/compiler/src/it/functional-tests/src/main/java/test/MultibindingDependency.java
new file mode 100644
index 000000000..a92e029e2
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/MultibindingDependency.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+interface MultibindingDependency {
+ double doubleDependency();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/MultibindingModule.java b/compiler/src/it/functional-tests/src/main/java/test/MultibindingModule.java
new file mode 100644
index 000000000..f356850b3
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/MultibindingModule.java
@@ -0,0 +1,169 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.mapkeys.ClassKey;
+import dagger.mapkeys.IntKey;
+import dagger.mapkeys.LongKey;
+import dagger.mapkeys.StringKey;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Named;
+import javax.inject.Provider;
+
+import static dagger.Provides.Type.MAP;
+import static dagger.Provides.Type.SET;
+
+@Module
+class MultibindingModule {
+ @Provides(type = MAP)
+ @StringKey("foo")
+ static String provideFooKey(double doubleDependency) {
+ return "foo value";
+ }
+
+ @Provides(type = MAP)
+ @StringKey("bar")
+ static String provideBarKey() {
+ return "bar value";
+ }
+
+ @Provides(type = SET)
+ static int provideFiveToSet() {
+ return 5;
+ }
+
+ @Provides(type = SET)
+ static int provideSixToSet() {
+ return 6;
+ }
+
+ @Provides
+ static Set<String> provideMapKeys(Map<String, Provider<String>> map) {
+ return map.keySet();
+ }
+
+ @Provides
+ static Collection<String> provideMapValues(Map<String, String> map) {
+ return map.values();
+ }
+
+ @Provides(type = MAP)
+ @NestedAnnotationContainer.NestedWrappedKey(Integer.class)
+ static String valueForInteger() {
+ return "integer";
+ }
+
+ @Provides(type = MAP)
+ @NestedAnnotationContainer.NestedWrappedKey(Long.class)
+ static String valueForLong() {
+ return "long";
+ }
+
+ @Provides(type = MAP)
+ @ClassKey(Integer.class)
+ static String valueForClassInteger() {
+ return "integer";
+ }
+
+ @Provides(type = MAP)
+ @ClassKey(Long.class)
+ static String valueForClassLong() {
+ return "long";
+ }
+
+ @Provides(type = MAP)
+ @NumberClassKey(BigDecimal.class)
+ static String valueForNumberClassBigDecimal() {
+ return "bigdecimal";
+ }
+
+ @Provides(type = MAP)
+ @NumberClassKey(BigInteger.class)
+ static String valueForNumberClassBigInteger() {
+ return "biginteger";
+ }
+
+ @Provides(type = MAP)
+ @LongKey(100)
+ static String valueFor100Long() {
+ return "100 long";
+ }
+
+ @Provides(type = MAP)
+ @IntKey(100)
+ static String valueFor100Int() {
+ return "100 int";
+ }
+
+ @Provides(type = MAP)
+ @ShortKey(100)
+ static String valueFor100Short() {
+ return "100 short";
+ }
+
+ @Provides(type = MAP)
+ @ByteKey(100)
+ static String valueFor100Byte() {
+ return "100 byte";
+ }
+
+ @Provides(type = MAP)
+ @BooleanKey(true)
+ static String valueForTrue() {
+ return "true";
+ }
+
+ @Provides(type = MAP)
+ @CharKey('a')
+ static String valueForA() {
+ return "a char";
+ }
+
+ @Provides(type = MAP)
+ @CharKey('\n')
+ static String valueForNewline() {
+ return "newline char";
+ }
+
+ @Provides(type = MAP)
+ @UnwrappedAnnotationKey(@StringKey("foo\n"))
+ static String valueForUnwrappedAnnotationKeyFoo() {
+ return "foo annotation";
+ }
+
+ @Provides(type = MAP)
+ @WrappedAnnotationKey(
+ value = @StringKey("foo"),
+ integers = {1, 2, 3},
+ annotations = {},
+ classes = {Long.class, Integer.class}
+ )
+ static String valueForWrappedAnnotationKeyFoo() {
+ return "wrapped foo annotation";
+ }
+
+ @Provides(type = SET)
+ @Named("complexQualifier")
+ static String valueForComplexQualifierSet() {
+ return "foo";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/NeedsFactory.java b/compiler/src/it/functional-tests/src/main/java/test/NeedsFactory.java
new file mode 100644
index 000000000..b78907382
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/NeedsFactory.java
@@ -0,0 +1,27 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import com.google.auto.factory.AutoFactory;
+import javax.inject.Inject;
+
+class NeedsFactory {
+ @Inject NeedsFactory(NeedsFactory_SomethingFactory somethingFactory) {}
+
+ @AutoFactory
+ static class Something {}
+}
+
diff --git a/compiler/src/it/functional-tests/src/main/java/test/NestedAnnotationContainer.java b/compiler/src/it/functional-tests/src/main/java/test/NestedAnnotationContainer.java
new file mode 100644
index 000000000..c57b4ecf4
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/NestedAnnotationContainer.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import dagger.MapKey;
+
+public final class NestedAnnotationContainer {
+
+ @MapKey(unwrapValue = false)
+ @interface NestedWrappedKey {
+ Class<?> value();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/NonComponentDependencyComponent.java b/compiler/src/it/functional-tests/src/main/java/test/NonComponentDependencyComponent.java
new file mode 100644
index 000000000..43a088cdc
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/NonComponentDependencyComponent.java
@@ -0,0 +1,47 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import dagger.Component;
+import javax.inject.Inject;
+import test.sub.OtherThing;
+
+@Component(dependencies = {NonComponentDependencyComponent.ThingComponent.class})
+interface NonComponentDependencyComponent {
+ ThingTwo thingTwo();
+
+ static class ThingTwo {
+ @SuppressWarnings("unused")
+ @Inject
+ ThingTwo(
+ Thing thing,
+ NonComponentDependencyComponent nonComponentDependencyComponent,
+ NonComponentDependencyComponent.ThingComponent thingComponent) {}
+ }
+
+ // A non-component interface which this interface depends upon.
+ interface ThingComponent {
+ Thing thing();
+ }
+
+ // The implementation for that interface.
+ static class ThingComponentImpl implements ThingComponent {
+ @Override
+ public Thing thing() {
+ return new Thing(new OtherThing(1));
+ }
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/NumberClassKey.java b/compiler/src/it/functional-tests/src/main/java/test/NumberClassKey.java
new file mode 100644
index 000000000..4164ae5cc
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/NumberClassKey.java
@@ -0,0 +1,23 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import dagger.MapKey;
+
+@MapKey(unwrapValue = true)
+@interface NumberClassKey {
+ Class<? extends Number> value();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/OuterClassBar.java b/compiler/src/it/functional-tests/src/main/java/test/OuterClassBar.java
new file mode 100644
index 000000000..c7fabdb2b
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/OuterClassBar.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import dagger.Component;
+
+final class OuterClassBar {
+ @Component(modules = PrimitivesModule.class)
+ interface NestedComponent {
+ InjectedThing injectedThing();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/OuterClassFoo.java b/compiler/src/it/functional-tests/src/main/java/test/OuterClassFoo.java
new file mode 100644
index 000000000..86f963f5c
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/OuterClassFoo.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import dagger.Component;
+
+final class OuterClassFoo {
+ @Component(modules = PrimitivesModule.class)
+ interface NestedComponent {
+ Thing thing();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ParentModule.java b/compiler/src/it/functional-tests/src/main/java/test/ParentModule.java
new file mode 100644
index 000000000..a161abaa8
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ParentModule.java
@@ -0,0 +1,18 @@
+package test;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.ArrayList;
+import java.util.List;
+
+@Module
+abstract class ParentModule<A extends Number & Comparable<A>, B, C extends Iterable<A>> {
+ @Provides Iterable<A> provideIterableOfAWithC(A a, C c) {
+ List<A> list = new ArrayList<>();
+ list.add(a);
+ for (A elt : c) {
+ list.add(elt);
+ }
+ return list;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/PrimitivesModule.java b/compiler/src/it/functional-tests/src/main/java/test/PrimitivesModule.java
new file mode 100644
index 000000000..acbf271df
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/PrimitivesModule.java
@@ -0,0 +1,93 @@
+package test;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+final class PrimitivesModule {
+ static final byte BOUND_BYTE = -41;
+ static final char BOUND_CHAR = 'g';
+ static final short BOUND_SHORT = 21840;
+ static final int BOUND_INT = 1894833693;
+ static final long BOUND_LONG = -4369839828653523584L;
+ static final boolean BOUND_BOOLEAN = true;
+ static final float BOUND_FLOAT = (float) 0.9964542;
+ static final double BOUND_DOUBLE = 0.12681322049667765;
+
+ /*
+ * While we can't ensure that these constants stay constant, this is a test so we're just going to
+ * keep our fingers crossed that we're not going to be jerks.
+ */
+ static final byte[] BOUND_BYTE_ARRAY = {1, 2, 3};
+ static final char[] BOUND_CHAR_ARRAY = {'g', 'a', 'k'};
+ static final short[] BOUND_SHORT_ARRAY = {2, 4};
+ static final int[] BOUND_INT_ARRAY = {3, 1, 2};
+ static final long[] BOUND_LONG_ARRAY = {1, 1, 2, 3, 5};
+ static final boolean[] BOUND_BOOLEAN_ARRAY = {false, true, false, false};
+ static final float[] BOUND_FLOAT_ARRAY = {(float) 0.1, (float) 0.01, (float) 0.001};
+ static final double[] BOUND_DOUBLE_ARRAY = {0.2, 0.02, 0.002};
+
+ @Provides static byte provideByte() {
+ return BOUND_BYTE;
+ }
+
+ @Provides static char provideChar() {
+ return BOUND_CHAR;
+ }
+
+ @Provides static short provideShort() {
+ return BOUND_SHORT;
+ }
+
+ @Provides static int provideInt() {
+ return BOUND_INT;
+ }
+
+ @Provides static long provideLong() {
+ return BOUND_LONG;
+ }
+
+ @Provides static boolean provideBoolean() {
+ return BOUND_BOOLEAN;
+ }
+
+ @Provides static float provideFloat() {
+ return BOUND_FLOAT;
+ }
+
+ @Provides static double boundDouble() {
+ return BOUND_DOUBLE;
+ }
+
+ @Provides static byte[] provideByteArray() {
+ return BOUND_BYTE_ARRAY;
+ }
+
+ @Provides static char[] provideCharArray() {
+ return BOUND_CHAR_ARRAY;
+ }
+
+ @Provides static short[] provideShortArray() {
+ return BOUND_SHORT_ARRAY;
+ }
+
+ @Provides static int[] provideIntArray() {
+ return BOUND_INT_ARRAY;
+ }
+
+ @Provides static long[] provideLongArray() {
+ return BOUND_LONG_ARRAY;
+ }
+
+ @Provides static boolean[] provideBooleanArray() {
+ return BOUND_BOOLEAN_ARRAY;
+ }
+
+ @Provides static float[] provideFloatArray() {
+ return BOUND_FLOAT_ARRAY;
+ }
+
+ @Provides static double[] boundDoubleArray() {
+ return BOUND_DOUBLE_ARRAY;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ReferencesGeneric.java b/compiler/src/it/functional-tests/src/main/java/test/ReferencesGeneric.java
new file mode 100644
index 000000000..812c45d35
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ReferencesGeneric.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import javax.inject.Inject;
+
+class ReferencesGeneric {
+ final Generic<A> genericA;
+
+ @Inject ReferencesGeneric(Generic<A> genericA) {
+ this.genericA = genericA;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ScopedGeneric.java b/compiler/src/it/functional-tests/src/main/java/test/ScopedGeneric.java
new file mode 100644
index 000000000..37d68e01e
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ScopedGeneric.java
@@ -0,0 +1,12 @@
+package test;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+@Singleton
+class ScopedGeneric<T> {
+ final T t;
+ @Inject ScopedGeneric(T t) {
+ this.t = t;
+ }
+} \ No newline at end of file
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ShortKey.java b/compiler/src/it/functional-tests/src/main/java/test/ShortKey.java
new file mode 100644
index 000000000..01b3aa99d
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ShortKey.java
@@ -0,0 +1,23 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import dagger.MapKey;
+
+@MapKey(unwrapValue = true)
+@interface ShortKey {
+ short value();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/SingletonGenericComponent.java b/compiler/src/it/functional-tests/src/main/java/test/SingletonGenericComponent.java
new file mode 100644
index 000000000..44a2cb553
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/SingletonGenericComponent.java
@@ -0,0 +1,13 @@
+package test;
+
+import dagger.Component;
+import javax.inject.Singleton;
+
+@Singleton
+@Component
+interface SingletonGenericComponent {
+
+ ScopedGeneric<A> scopedGenericA();
+ ScopedGeneric<B> scopedGenericB();
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/Thing.java b/compiler/src/it/functional-tests/src/main/java/test/Thing.java
new file mode 100644
index 000000000..46cbdc999
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/Thing.java
@@ -0,0 +1,23 @@
+/*
+* Copyright (C) 2014 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import javax.inject.Inject;
+import test.sub.OtherThing;
+
+final class Thing {
+ @Inject Thing(@SuppressWarnings("unused") OtherThing unused) {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/TypeWithInheritedMembersInjection.java b/compiler/src/it/functional-tests/src/main/java/test/TypeWithInheritedMembersInjection.java
new file mode 100644
index 000000000..587baade1
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/TypeWithInheritedMembersInjection.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import javax.inject.Inject;
+
+final class TypeWithInheritedMembersInjection extends AbstractMiddleClassWithoutMembers {
+ @Inject TypeWithInheritedMembersInjection() {}
+}
+
diff --git a/compiler/src/it/functional-tests/src/main/java/test/UnwrappedAnnotationKey.java b/compiler/src/it/functional-tests/src/main/java/test/UnwrappedAnnotationKey.java
new file mode 100644
index 000000000..21ed95841
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/UnwrappedAnnotationKey.java
@@ -0,0 +1,24 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import dagger.MapKey;
+import dagger.mapkeys.StringKey;
+
+@MapKey(unwrapValue = true)
+@interface UnwrappedAnnotationKey {
+ StringKey value();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/WrappedAnnotationKey.java b/compiler/src/it/functional-tests/src/main/java/test/WrappedAnnotationKey.java
new file mode 100644
index 000000000..5d6e86dc7
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/WrappedAnnotationKey.java
@@ -0,0 +1,28 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import dagger.MapKey;
+import dagger.mapkeys.ClassKey;
+import dagger.mapkeys.StringKey;
+
+@MapKey(unwrapValue = false)
+@interface WrappedAnnotationKey {
+ StringKey value();
+ int[] integers();
+ ClassKey[] annotations();
+ Class<? extends Number>[] classes();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/ByteModule.java b/compiler/src/it/functional-tests/src/main/java/test/builder/ByteModule.java
new file mode 100644
index 000000000..8b85d606c
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/ByteModule.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+class ByteModule {
+ final byte b;
+
+ ByteModule(byte b) {
+ this.b = b;
+ }
+
+ @Provides byte b() { return b; }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/DepComponent.java b/compiler/src/it/functional-tests/src/main/java/test/builder/DepComponent.java
new file mode 100644
index 000000000..93fd59def
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/DepComponent.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Component;
+
+@Component
+interface DepComponent {
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/DoubleModule.java b/compiler/src/it/functional-tests/src/main/java/test/builder/DoubleModule.java
new file mode 100644
index 000000000..2dec4a7a2
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/DoubleModule.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+class DoubleModule {
+ @Provides
+ double d() {
+ return 4.2d;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/FloatModule.java b/compiler/src/it/functional-tests/src/main/java/test/builder/FloatModule.java
new file mode 100644
index 000000000..309e7ee98
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/FloatModule.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+class FloatModule {
+ @Provides
+ float f() {
+ return 5.5f;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/GenericParent.java b/compiler/src/it/functional-tests/src/main/java/test/builder/GenericParent.java
new file mode 100644
index 000000000..af196eeda
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/GenericParent.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+interface GenericParent<B> {
+ B subcomponentBuilder();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/Grandchild.java b/compiler/src/it/functional-tests/src/main/java/test/builder/Grandchild.java
new file mode 100644
index 000000000..8cbf67b19
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/Grandchild.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Subcomponent;
+
+@Subcomponent(modules = IntModuleIncludingDoubleAndFloat.class)
+interface Grandchild {
+ int i();
+ String s();
+
+ @Subcomponent.Builder
+ interface Builder {
+ Grandchild build();
+ Builder set(IntModuleIncludingDoubleAndFloat intModule);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/IntModuleIncludingDoubleAndFloat.java b/compiler/src/it/functional-tests/src/main/java/test/builder/IntModuleIncludingDoubleAndFloat.java
new file mode 100644
index 000000000..5e3a92827
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/IntModuleIncludingDoubleAndFloat.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module(includes = { DoubleModule.class, FloatModule.class })
+class IntModuleIncludingDoubleAndFloat {
+ final int integer;
+
+ IntModuleIncludingDoubleAndFloat(int integer) {
+ this.integer = integer;
+ }
+
+ @Provides
+ int integer() {
+ return integer;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/LongModule.java b/compiler/src/it/functional-tests/src/main/java/test/builder/LongModule.java
new file mode 100644
index 000000000..c16c9c79f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/LongModule.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+class LongModule {
+ @Provides
+ long l() {
+ return 6L;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/MiddleChild.java b/compiler/src/it/functional-tests/src/main/java/test/builder/MiddleChild.java
new file mode 100644
index 000000000..59c29ab34
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/MiddleChild.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Subcomponent;
+
+@MiddleScope
+@Subcomponent(modules = StringModule.class)
+interface MiddleChild {
+ String s();
+
+ Grandchild.Builder grandchildBuilder();
+
+ @Subcomponent.Builder
+ interface Builder {
+ MiddleChild build();
+ Builder set(StringModule stringModule);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/MiddleScope.java b/compiler/src/it/functional-tests/src/main/java/test/builder/MiddleScope.java
new file mode 100644
index 000000000..e2fbcaa42
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/MiddleScope.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import java.lang.annotation.Retention;
+import javax.inject.Scope;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Scope
+@Retention(RUNTIME)
+@interface MiddleScope {
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/OtherMiddleChild.java b/compiler/src/it/functional-tests/src/main/java/test/builder/OtherMiddleChild.java
new file mode 100644
index 000000000..28e43bafe
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/OtherMiddleChild.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Subcomponent;
+
+@MiddleScope
+@Subcomponent(modules = {StringModule.class, LongModule.class})
+interface OtherMiddleChild {
+ long l();
+ String s();
+
+ Grandchild.Builder grandchildBuilder();
+
+ @Subcomponent.Builder
+ interface Builder {
+ OtherMiddleChild build();
+ Builder set(StringModule stringModule);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/ParentComponent.java b/compiler/src/it/functional-tests/src/main/java/test/builder/ParentComponent.java
new file mode 100644
index 000000000..f901b8863
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/ParentComponent.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Component;
+import javax.inject.Singleton;
+
+@Singleton
+@Component
+interface ParentComponent {
+ TestChildComponentWithBuilderAbstractClass.Builder childAbstractClassBuilder();
+ TestChildComponentWithBuilderInterface.Builder childInterfaceBuilder();
+
+ MiddleChild.Builder middleBuilder();
+ OtherMiddleChild.Builder otherBuilder();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/ParentOfGenericComponent.java b/compiler/src/it/functional-tests/src/main/java/test/builder/ParentOfGenericComponent.java
new file mode 100644
index 000000000..474c61701
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/ParentOfGenericComponent.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Component;
+import javax.inject.Singleton;
+
+@Component(modules = StringModule.class)
+@Singleton
+interface ParentOfGenericComponent extends GenericParent<Grandchild.Builder> {}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/StringModule.java b/compiler/src/it/functional-tests/src/main/java/test/builder/StringModule.java
new file mode 100644
index 000000000..3b979a5ab
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/StringModule.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+class StringModule {
+ final String string;
+
+ StringModule(String string) {
+ this.string = string;
+ }
+
+ @Provides
+ String string() {
+ return string;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/TestChildComponentWithBuilderAbstractClass.java b/compiler/src/it/functional-tests/src/main/java/test/builder/TestChildComponentWithBuilderAbstractClass.java
new file mode 100644
index 000000000..8f39c1401
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/TestChildComponentWithBuilderAbstractClass.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Subcomponent;
+
+@Subcomponent(modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class,
+ LongModule.class, ByteModule.class})
+interface TestChildComponentWithBuilderAbstractClass {
+ String s();
+ int i();
+ long l();
+ float f();
+ double d();
+ byte b();
+
+ abstract class SharedBuilder<B, C, M1, M2> {
+ abstract C build(); // Test resolving return type of build()
+ abstract B setM1(M1 m1); // Test resolving return type & param of setter
+ abstract SharedBuilder<B, C, M1, M2> setM2(M2 m2); // Test being overridden
+ abstract void setM3(DoubleModule doubleModule); // Test being overridden
+ abstract SharedBuilder<B, C, M1, M2> set(FloatModule floatModule); // Test returning supertype.
+ }
+
+ @Subcomponent.Builder
+ abstract class Builder extends SharedBuilder<Builder, TestChildComponentWithBuilderAbstractClass,
+ StringModule, IntModuleIncludingDoubleAndFloat> {
+ @Override abstract Builder setM2(IntModuleIncludingDoubleAndFloat m2); // Test covariance
+ @Override abstract void setM3(DoubleModule doubleModule); // Test simple overrides allowed
+ abstract void set(ByteModule byteModule);
+
+ // Note we're missing LongModule -- it's implicit
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/TestChildComponentWithBuilderInterface.java b/compiler/src/it/functional-tests/src/main/java/test/builder/TestChildComponentWithBuilderInterface.java
new file mode 100644
index 000000000..2add34ed5
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/TestChildComponentWithBuilderInterface.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Subcomponent;
+
+@Subcomponent(modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class,
+ LongModule.class, ByteModule.class})
+interface TestChildComponentWithBuilderInterface {
+ String s();
+ int i();
+ long l();
+ float f();
+ double d();
+ byte b();
+
+ interface SharedBuilder<B, C, M1, M2> {
+ C build(); // Test resolving return type of build()
+ B setM1(M1 m1); // Test resolving return type & param of setter
+ SharedBuilder<B, C, M1, M2> setM2(M2 m2); // Test being overridden
+ void setM3(DoubleModule doubleModule); // Test being overridden
+ SharedBuilder<B, C, M1, M2> set(FloatModule floatModule); // Test return type is supertype.
+ }
+
+ @Subcomponent.Builder
+ interface Builder extends SharedBuilder<Builder, TestChildComponentWithBuilderInterface,
+ StringModule, IntModuleIncludingDoubleAndFloat> {
+ @Override Builder setM2(IntModuleIncludingDoubleAndFloat m2); // Test covariant overrides
+ @Override void setM3(DoubleModule doubleModule); // Test simple overrides allowed
+ void set(ByteModule byteModule);
+
+ // Note we're missing LongModule -- it's implicit
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithBuilderAbstractClass.java b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithBuilderAbstractClass.java
new file mode 100644
index 000000000..5eef53fe5
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithBuilderAbstractClass.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Component;
+
+@Component(
+ modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class, LongModule.class},
+ dependencies = DepComponent.class)
+abstract class TestComponentWithBuilderAbstractClass {
+
+ static Builder builder() {
+ return DaggerTestComponentWithBuilderAbstractClass.builder();
+ }
+
+ abstract String s();
+ abstract int i();
+ abstract long l();
+ abstract float f();
+ abstract double d();
+
+
+ static abstract class SharedBuilder {
+ // Make sure we use the overriding signature.
+ abstract Object build();
+
+ Object stringModule(@SuppressWarnings("unused") StringModule stringModule) {
+ return null;
+ }
+
+ SharedBuilder ignoredLongModule(@SuppressWarnings("unused") LongModule longModule) {
+ return null;
+ }
+
+ }
+
+ @Component.Builder
+ static abstract class Builder extends SharedBuilder {
+ @Override abstract TestComponentWithBuilderAbstractClass build(); // Narrowing return type
+ @Override abstract Builder stringModule(StringModule stringModule); // Make abstract & narrow
+ abstract Builder intModule(IntModuleIncludingDoubleAndFloat intModule);
+ abstract void doubleModule(DoubleModule doubleModule); // Module w/o args
+ abstract void depComponent(DepComponent depComponent);
+
+ Builder ignoredIntModule(
+ @SuppressWarnings("unused") IntModuleIncludingDoubleAndFloat intModule) {
+ return null;
+ }
+
+ // Note we're missing LongModule & FloatModule -- they/re implicit
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithBuilderInterface.java b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithBuilderInterface.java
new file mode 100644
index 000000000..55214f836
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithBuilderInterface.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Component;
+
+@Component(
+ modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class, LongModule.class},
+ dependencies = DepComponent.class)
+interface TestComponentWithBuilderInterface {
+ String s();
+ int i();
+ long l();
+ float f();
+ double d();
+
+ interface SharedBuilder {
+ // Make sure we use the overriding signature.
+ Object build();
+ Object stringModule(StringModule m1);
+ }
+
+ @Component.Builder
+ interface Builder extends SharedBuilder {
+ @Override TestComponentWithBuilderInterface build(); // Narrowing return type
+ @Override Builder stringModule(StringModule stringModule); // Narrowing return type
+ Builder intModule(IntModuleIncludingDoubleAndFloat intModule);
+ void doubleModule(DoubleModule doubleModule); // Module w/o args
+ void depComponent(DepComponent depComponent);
+
+ // Note we're missing LongModule & FloatModule -- they/re implicit
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithGenericBuilderAbstractClass.java b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithGenericBuilderAbstractClass.java
new file mode 100644
index 000000000..8032185b2
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithGenericBuilderAbstractClass.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Component;
+
+@Component(
+ modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class, LongModule.class},
+ dependencies = DepComponent.class)
+interface TestComponentWithGenericBuilderAbstractClass {
+ String s();
+ int i();
+ long l();
+ float f();
+ double d();
+
+ static abstract class SharedBuilder<B, C, M1, M2> {
+ abstract C build(); // Test resolving return type of build()
+ abstract B setM1(M1 m1); // Test resolving return type & param of setter
+ abstract SharedBuilder<B, C, M1, M2> setM2(M2 m2); // Test being overridden
+ abstract void doubleModule(DoubleModule doubleModule); // Test being overridden
+ abstract SharedBuilder<B, C, M1, M2> depComponent(FloatModule floatModule); // Test return type
+ }
+
+ @Component.Builder
+ static abstract class Builder extends SharedBuilder<Builder,
+ TestComponentWithGenericBuilderAbstractClass, StringModule,
+ IntModuleIncludingDoubleAndFloat> {
+ @Override abstract Builder setM2(IntModuleIncludingDoubleAndFloat m2); // Test covariant overrides
+ @Override abstract void doubleModule(DoubleModule module3); // Test simple overrides allowed
+ abstract void depComponent(DepComponent depComponent);
+
+ // Note we're missing LongModule & FloatModule -- they're implicit
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithGenericBuilderInterface.java b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithGenericBuilderInterface.java
new file mode 100644
index 000000000..f63e3ec90
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithGenericBuilderInterface.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import dagger.Component;
+
+@Component(
+ modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class, LongModule.class},
+ dependencies = DepComponent.class)
+interface TestComponentWithGenericBuilderInterface {
+ String s();
+ int i();
+ long l();
+ float f();
+ double d();
+
+ interface SharedBuilder<B, C, M1, M2> {
+ C build(); // Test resolving return type of build()
+ B setM1(M1 m1); // Test resolving return type & param of setter
+ SharedBuilder<B, C, M1, M2> setM2(M2 m2); // Test being overridden
+ void doubleModule(DoubleModule doubleModule); // Test being overridden
+ SharedBuilder<B, C, M1, M2> set(FloatModule floatModule); // Test return type is supertype.
+ }
+
+ @Component.Builder
+ interface Builder extends SharedBuilder<Builder, TestComponentWithGenericBuilderInterface,
+ StringModule, IntModuleIncludingDoubleAndFloat> {
+ @Override Builder setM2(IntModuleIncludingDoubleAndFloat m2); // Test covariant overrides allowed
+ @Override void doubleModule(DoubleModule module3); // Test simple overrides allowed
+ void depComponent(DepComponent depComponent);
+
+ // Note we're missing M5 -- that's implicit.
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/cycle/Cycles.java b/compiler/src/it/functional-tests/src/main/java/test/cycle/Cycles.java
new file mode 100644
index 000000000..8d67d92eb
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/cycle/Cycles.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.cycle;
+
+import dagger.Component;
+import dagger.Lazy;
+import dagger.Module;
+import dagger.Provides;
+import dagger.Subcomponent;
+import dagger.mapkeys.StringKey;
+import java.util.Map;
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+import static dagger.Provides.Type.MAP;
+
+/**
+ * Cycle classes used for testing cyclic dependencies.
+ * A <- (E <- D <- B <- C <- Provider<A>, Lazy<A>), (B <- C <- Provider<A>, Lazy<A>)
+ * S <- Provider<S>, Lazy<S>
+ *
+ * @author Tony Bentancur
+ * @since 2.0
+ */
+
+final class Cycles {
+ private Cycles() {}
+
+ static class A {
+ public final B b;
+ public final E e;
+
+ @Inject
+ A(E e, B b) {
+ this.e = e;
+ this.b = b;
+ }
+ }
+
+ static class B {
+ public final C c;
+
+ @Inject
+ B(C c) {
+ this.c = c;
+ }
+ }
+
+ static class C {
+ public final Provider<A> aProvider;
+ @Inject public Lazy<A> aLazy;
+
+ @Inject
+ C(Provider<A> aProvider) {
+ this.aProvider = aProvider;
+ }
+ }
+
+ static class D {
+ public final B b;
+
+ @Inject
+ D(B b) {
+ this.b = b;
+ }
+ }
+
+ static class E {
+ public final D d;
+
+ @Inject
+ E(D d) {
+ this.d = d;
+ }
+ }
+
+ static class S {
+ public final Provider<S> sProvider;
+ @Inject public Lazy<S> sLazy;
+
+ @Inject
+ S(Provider<S> sProvider) {
+ this.sProvider = sProvider;
+ }
+ }
+
+ static class X {
+ public final Y y;
+
+ @Inject
+ X(Y y) {
+ this.y = y;
+ }
+ }
+
+ static class Y {
+ public final Map<String, Provider<X>> mapOfProvidersOfX;
+ public final Map<String, Provider<Y>> mapOfProvidersOfY;
+
+ @Inject
+ Y(Map<String, Provider<X>> mapOfProvidersOfX, Map<String, Provider<Y>> mapOfProvidersOfY) {
+ this.mapOfProvidersOfX = mapOfProvidersOfX;
+ this.mapOfProvidersOfY = mapOfProvidersOfY;
+ }
+ }
+
+ @Module
+ static class CycleMapModule {
+ @Provides(type = MAP)
+ @StringKey("X")
+ static X x(X x) {
+ return x;
+ }
+
+ @Provides(type = MAP)
+ @StringKey("Y")
+ static Y y(Y y) {
+ return y;
+ }
+ }
+
+ @SuppressWarnings("dependency-cycle")
+ @Component(modules = CycleMapModule.class)
+ interface CycleMapComponent {
+ Y y();
+ }
+
+ @SuppressWarnings("dependency-cycle")
+ @Component
+ interface CycleComponent {
+ A a();
+
+ C c();
+
+ ChildCycleComponent child();
+ }
+
+ @SuppressWarnings("dependency-cycle")
+ @Component
+ interface SelfCycleComponent {
+ S s();
+ }
+
+ @Subcomponent
+ interface ChildCycleComponent {
+ @SuppressWarnings("dependency-cycle")
+ A a();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/cycle/LongCycle.java b/compiler/src/it/functional-tests/src/main/java/test/cycle/LongCycle.java
new file mode 100644
index 000000000..b4f61e096
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/cycle/LongCycle.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.cycle;
+
+import dagger.Component;
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+final class LongCycle {
+ static class Class1 { @Inject Class1(Class2 class2) {} }
+ static class Class2 { @Inject Class2(Class3 class3) {} }
+ static class Class3 { @Inject Class3(Class4 class4) {} }
+ static class Class4 { @Inject Class4(Class5 class5) {} }
+ static class Class5 { @Inject Class5(Class6 class6) {} }
+ static class Class6 { @Inject Class6(Class7 class7) {} }
+ static class Class7 { @Inject Class7(Class8 class8) {} }
+ static class Class8 { @Inject Class8(Class9 class9) {} }
+ static class Class9 { @Inject Class9(Class10 class10) {} }
+ static class Class10 { @Inject Class10(Class11 class11) {} }
+ static class Class11 { @Inject Class11(Class12 class12) {} }
+ static class Class12 { @Inject Class12(Class13 class13) {} }
+ static class Class13 { @Inject Class13(Class14 class14) {} }
+ static class Class14 { @Inject Class14(Class15 class15) {} }
+ static class Class15 { @Inject Class15(Class16 class16) {} }
+ static class Class16 { @Inject Class16(Class17 class17) {} }
+ static class Class17 { @Inject Class17(Class18 class18) {} }
+ static class Class18 { @Inject Class18(Class19 class19) {} }
+ static class Class19 { @Inject Class19(Class20 class20) {} }
+ static class Class20 { @Inject Class20(Class21 class21) {} }
+ static class Class21 { @Inject Class21(Class22 class22) {} }
+ static class Class22 { @Inject Class22(Class23 class23) {} }
+ static class Class23 { @Inject Class23(Class24 class24) {} }
+ static class Class24 { @Inject Class24(Class25 class25) {} }
+ static class Class25 { @Inject Class25(Class26 class26) {} }
+ static class Class26 { @Inject Class26(Class27 class27) {} }
+ static class Class27 { @Inject Class27(Class28 class28) {} }
+ static class Class28 { @Inject Class28(Class29 class29) {} }
+ static class Class29 { @Inject Class29(Class30 class30) {} }
+ static class Class30 { @Inject Class30(Class31 class31) {} }
+ static class Class31 { @Inject Class31(Class32 class32) {} }
+ static class Class32 { @Inject Class32(Class33 class33) {} }
+ static class Class33 { @Inject Class33(Class34 class34) {} }
+ static class Class34 { @Inject Class34(Class35 class35) {} }
+ static class Class35 { @Inject Class35(Class36 class36) {} }
+ static class Class36 { @Inject Class36(Class37 class37) {} }
+ static class Class37 { @Inject Class37(Class38 class38) {} }
+ static class Class38 { @Inject Class38(Class39 class39) {} }
+ static class Class39 { @Inject Class39(Class40 class40) {} }
+ static class Class40 { @Inject Class40(Class41 class41) {} }
+ static class Class41 { @Inject Class41(Class42 class42) {} }
+ static class Class42 { @Inject Class42(Class43 class43) {} }
+ static class Class43 { @Inject Class43(Class44 class44) {} }
+ static class Class44 { @Inject Class44(Class45 class45) {} }
+ static class Class45 { @Inject Class45(Class46 class46) {} }
+ static class Class46 { @Inject Class46(Class47 class47) {} }
+ static class Class47 { @Inject Class47(Class48 class48) {} }
+ static class Class48 { @Inject Class48(Class49 class49) {} }
+ static class Class49 { @Inject Class49(Class50 class50) {} }
+ static class Class50 { @Inject Class50(Class51 class51) {} }
+ static class Class51 { @Inject Class51(Class52 class52) {} }
+ static class Class52 { @Inject Class52(Class53 class53) {} }
+ static class Class53 { @Inject Class53(Class54 class54) {} }
+ static class Class54 { @Inject Class54(Class55 class55) {} }
+ static class Class55 { @Inject Class55(Class56 class56) {} }
+ static class Class56 { @Inject Class56(Class57 class57) {} }
+ static class Class57 { @Inject Class57(Class58 class58) {} }
+ static class Class58 { @Inject Class58(Class59 class59) {} }
+ static class Class59 { @Inject Class59(Class60 class60) {} }
+ static class Class60 { @Inject Class60(Class61 class61) {} }
+ static class Class61 { @Inject Class61(Class62 class62) {} }
+ static class Class62 { @Inject Class62(Class63 class63) {} }
+ static class Class63 { @Inject Class63(Class64 class64) {} }
+ static class Class64 { @Inject Class64(Class65 class65) {} }
+ static class Class65 { @Inject Class65(Class66 class66) {} }
+ static class Class66 { @Inject Class66(Class67 class67) {} }
+ static class Class67 { @Inject Class67(Class68 class68) {} }
+ static class Class68 { @Inject Class68(Class69 class69) {} }
+ static class Class69 { @Inject Class69(Class70 class70) {} }
+ static class Class70 { @Inject Class70(Class71 class71) {} }
+ static class Class71 { @Inject Class71(Class72 class72) {} }
+ static class Class72 { @Inject Class72(Class73 class73) {} }
+ static class Class73 { @Inject Class73(Class74 class74) {} }
+ static class Class74 { @Inject Class74(Class75 class75) {} }
+ static class Class75 { @Inject Class75(Class76 class76) {} }
+ static class Class76 { @Inject Class76(Class77 class77) {} }
+ static class Class77 { @Inject Class77(Class78 class78) {} }
+ static class Class78 { @Inject Class78(Class79 class79) {} }
+ static class Class79 { @Inject Class79(Class80 class80) {} }
+ static class Class80 { @Inject Class80(Class81 class81) {} }
+ static class Class81 { @Inject Class81(Class82 class82) {} }
+ static class Class82 { @Inject Class82(Class83 class83) {} }
+ static class Class83 { @Inject Class83(Class84 class84) {} }
+ static class Class84 { @Inject Class84(Class85 class85) {} }
+ static class Class85 { @Inject Class85(Class86 class86) {} }
+ static class Class86 { @Inject Class86(Class87 class87) {} }
+ static class Class87 { @Inject Class87(Class88 class88) {} }
+ static class Class88 { @Inject Class88(Class89 class89) {} }
+ static class Class89 { @Inject Class89(Class90 class90) {} }
+ static class Class90 { @Inject Class90(Class91 class91) {} }
+ static class Class91 { @Inject Class91(Class92 class92) {} }
+ static class Class92 { @Inject Class92(Class93 class93) {} }
+ static class Class93 { @Inject Class93(Class94 class94) {} }
+ static class Class94 { @Inject Class94(Class95 class95) {} }
+ static class Class95 { @Inject Class95(Class96 class96) {} }
+ static class Class96 { @Inject Class96(Class97 class97) {} }
+ static class Class97 { @Inject Class97(Class98 class98) {} }
+ static class Class98 { @Inject Class98(Class99 class99) {} }
+ static class Class99 { @Inject Class99(Class100 class100) {} }
+ static class Class100 { @Inject Class100(Class101 class101) {} }
+ static class Class101 { @Inject Class101(Provider<Class1> class1Provider) {} }
+
+ @SuppressWarnings("dependency-cycle")
+ @Component
+ interface LongCycleComponent {
+ Class1 class1();
+ }
+
+ private LongCycle() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfArrayOfParentOfStringArray.java b/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfArrayOfParentOfStringArray.java
new file mode 100644
index 000000000..22efcf12e
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfArrayOfParentOfStringArray.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.membersinject;
+
+class ChildOfArrayOfParentOfStringArray extends
+ MembersInjectGenericParent<MembersInjectGenericParent<String[]>[]> {
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfPrimitiveIntArray.java b/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfPrimitiveIntArray.java
new file mode 100644
index 000000000..e01c1c266
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfPrimitiveIntArray.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.membersinject;
+
+class ChildOfPrimitiveIntArray extends MembersInjectGenericParent<int[]> {
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfStringArray.java b/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfStringArray.java
new file mode 100644
index 000000000..8ec943b96
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfStringArray.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.membersinject;
+
+class ChildOfStringArray extends MembersInjectGenericParent<String[]> {
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectComponent.java b/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectComponent.java
new file mode 100644
index 000000000..9ab8c1928
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectComponent.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.membersinject;
+
+import dagger.Component;
+
+@Component(modules = {MembersInjectModule.class})
+interface MembersInjectComponent {
+
+ void inject(ChildOfStringArray subfoo);
+ void inject(ChildOfArrayOfParentOfStringArray subfoo);
+ void inject(ChildOfPrimitiveIntArray subfoo);
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectGenericParent.java b/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectGenericParent.java
new file mode 100644
index 000000000..064b88642
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectGenericParent.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.membersinject;
+
+import javax.inject.Inject;
+
+class MembersInjectGenericParent<T> {
+
+ @Inject T t;
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectModule.java b/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectModule.java
new file mode 100644
index 000000000..a6c1fadb9
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectModule.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.membersinject;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+class MembersInjectModule {
+
+ @Provides String[] provideStringArray() { return new String[10]; }
+
+ @Provides int[] provideIntArray() { return new int[10]; }
+
+ @SuppressWarnings("unchecked")
+ @Provides MembersInjectGenericParent<String[]>[] provideFooArrayOfStringArray() { return new MembersInjectGenericParent[10]; }
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/membersinject/NonRequestedChild.java b/compiler/src/it/functional-tests/src/main/java/test/membersinject/NonRequestedChild.java
new file mode 100644
index 000000000..108a1b58f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/membersinject/NonRequestedChild.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.membersinject;
+
+import javax.inject.Inject;
+
+/**
+ * A class that should not be requested by any component, to ensure that we still generate a members
+ * injector for it.
+ */
+class NonRequestedChild extends MembersInjectGenericParent<String> {
+ @Inject
+ NonRequestedChild() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/FooComponent.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/FooComponent.java
new file mode 100644
index 000000000..3c884159f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/FooComponent.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.multipackage;
+
+import dagger.Component;
+import java.util.Set;
+import test.multipackage.a.AModule;
+import test.multipackage.sub.FooChildComponent;
+
+/**
+ * A component that tests the interaction between subcomponents, multiple packages, and
+ * multibindings. Specifically, we want:
+ * <ul>
+ * <li>A set binding with some contributions in the parent component, and some in the subcomponent.
+ * <li>The contributions come from different packages, but not the package of either component.
+ * <li>The set binding is requested in the subcomponent through a binding from a separate package.
+ * <li>No binding in the subcomponent, that's in the subcomponent's package, directly uses any
+ * binding from the component's package.
+ * </ul>
+ */
+// NOTE(beder): Be careful about changing any bindings in either this component or the subcomponent.
+// Even adding a binding might stop this test from testing what it's supposed to test.
+@Component(modules = {AModule.class})
+interface FooComponent {
+ Set<String> setOfString();
+
+ FooChildComponent fooChildComponent();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/MembersInjectionVisibilityComponent.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/MembersInjectionVisibilityComponent.java
new file mode 100644
index 000000000..85ce40aac
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/MembersInjectionVisibilityComponent.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.multipackage;
+
+import dagger.Component;
+import test.multipackage.a.AGrandchild;
+import test.multipackage.a.AModule;
+import test.multipackage.a.AParent;
+import test.multipackage.b.BChild;
+
+/**
+ * A component that tests members injection across packages and subclasses.
+ */
+@Component(modules = {AModule.class})
+public interface MembersInjectionVisibilityComponent {
+ void inject(AParent aParent);
+
+ void inject(BChild aChild);
+
+ void inject(AGrandchild aGrandchild);
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AGrandchild.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AGrandchild.java
new file mode 100644
index 000000000..8f0f1f39c
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AGrandchild.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.multipackage.a;
+
+import javax.inject.Inject;
+import test.multipackage.b.BChild;
+
+public class AGrandchild extends BChild {
+
+ @Inject APackagePrivateObject aGrandchildField;
+
+ private APackagePrivateObject aGrandchildMethod;
+
+ @Inject
+ void aGrandchildMethod(APackagePrivateObject aGrandchildMethod) {
+ this.aGrandchildMethod = aGrandchildMethod;
+ }
+
+ @Override
+ @Inject
+ protected void aParentMethod(APublicObject aParentMethod) {
+ super.aParentMethod(aParentMethod);
+ }
+
+ @Override
+ protected void aChildMethod(APublicObject aChildMethod) {
+ super.aChildMethod(aChildMethod);
+ }
+
+ public APackagePrivateObject aGrandchildField() {
+ return aGrandchildField;
+ }
+
+ public APackagePrivateObject aGrandchildMethod() {
+ return aGrandchildMethod;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AModule.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AModule.java
new file mode 100644
index 000000000..d62506a56
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AModule.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.multipackage.a;
+
+import dagger.Module;
+import dagger.Provides;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+public final class AModule {
+ @Provides(type = SET) String provideString() {
+ return "a";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/APackagePrivateObject.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/APackagePrivateObject.java
new file mode 100644
index 000000000..d60413331
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/APackagePrivateObject.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.multipackage.a;
+
+import javax.inject.Inject;
+
+class APackagePrivateObject {
+
+ @Inject
+ APackagePrivateObject() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AParent.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AParent.java
new file mode 100644
index 000000000..4c91a6f26
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AParent.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.multipackage.a;
+
+import javax.inject.Inject;
+
+public class AParent {
+
+ @Inject APackagePrivateObject aParentField;
+
+ private APublicObject aParentMethod;
+
+ @Inject
+ protected void aParentMethod(APublicObject aParentMethod) {
+ this.aParentMethod = aParentMethod;
+ }
+
+ public APackagePrivateObject aParentField() {
+ return aParentField;
+ }
+
+ public APublicObject aParentMethod() {
+ return aParentMethod;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/APublicObject.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/APublicObject.java
new file mode 100644
index 000000000..90357f661
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/APublicObject.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.multipackage.a;
+
+import javax.inject.Inject;
+
+public class APublicObject {
+
+ @Inject
+ APublicObject() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BChild.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BChild.java
new file mode 100644
index 000000000..188d1201f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BChild.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.multipackage.b;
+
+import javax.inject.Inject;
+import test.multipackage.a.AParent;
+import test.multipackage.a.APublicObject;
+
+public class BChild extends AParent {
+
+ @Inject BPackagePrivateObject aChildField;
+
+ private APublicObject aChildMethod;
+
+ @Inject
+ protected void aChildMethod(APublicObject aChildMethod) {
+ this.aChildMethod = aChildMethod;
+ }
+
+ @Override
+ protected void aParentMethod(APublicObject aParentMethod) {
+ super.aParentMethod(aParentMethod);
+ }
+
+ public BPackagePrivateObject aChildField() {
+ return aChildField;
+ }
+
+ public APublicObject aChildMethod() {
+ return aChildMethod;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BModule.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BModule.java
new file mode 100644
index 000000000..4d817f153
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BModule.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.multipackage.b;
+
+import dagger.Module;
+import dagger.Provides;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+public final class BModule {
+ @Provides(type = SET) String provideString() {
+ return "b";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BPackagePrivateObject.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BPackagePrivateObject.java
new file mode 100644
index 000000000..c397a02c8
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BPackagePrivateObject.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.multipackage.b;
+
+import javax.inject.Inject;
+
+class BPackagePrivateObject {
+
+ @Inject
+ BPackagePrivateObject() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/c/CModule.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/c/CModule.java
new file mode 100644
index 000000000..e608afb2c
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/c/CModule.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.multipackage.c;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.Set;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+public final class CModule {
+ @Provides(type = SET) String provideString() {
+ return "c";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/d/DModule.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/d/DModule.java
new file mode 100644
index 000000000..51f8ace76
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/d/DModule.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.multipackage.d;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.Set;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+public final class DModule {
+ @Provides(type = SET) String provideString() {
+ return "d";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/foo/Foo.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/foo/Foo.java
new file mode 100644
index 000000000..35f5862ad
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/foo/Foo.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.multipackage.foo;
+
+import java.util.Set;
+import javax.inject.Inject;
+
+public final class Foo<T> {
+ public final Set<String> strings;
+
+ @Inject Foo(Set<String> strings) {
+ this.strings = strings;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/grandsub/FooGrandchildComponent.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/grandsub/FooGrandchildComponent.java
new file mode 100644
index 000000000..16a61dd54
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/grandsub/FooGrandchildComponent.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.multipackage.grandsub;
+
+import dagger.Subcomponent;
+import test.multipackage.d.DModule;
+import test.multipackage.foo.Foo;
+
+@Subcomponent(modules = DModule.class)
+public interface FooGrandchildComponent {
+ Foo<FooGrandchildComponent> foo();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/sub/FooChildComponent.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/sub/FooChildComponent.java
new file mode 100644
index 000000000..9050fcd72
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/sub/FooChildComponent.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.multipackage.sub;
+
+import dagger.Subcomponent;
+import test.multipackage.b.BModule;
+import test.multipackage.c.CModule;
+import test.multipackage.foo.Foo;
+import test.multipackage.grandsub.FooGrandchildComponent;
+
+@Subcomponent(modules = {BModule.class, CModule.class})
+public interface FooChildComponent {
+ Foo<FooChildComponent> foo();
+
+ FooGrandchildComponent fooGrandchildComponent();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/nullables/NullComponent.java b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullComponent.java
new file mode 100644
index 000000000..a8a572473
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullComponent.java
@@ -0,0 +1,29 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test.nullables;
+
+import javax.inject.Provider;
+
+import dagger.Component;
+
+@Component(modules = NullModule.class)
+interface NullComponent {
+ NullFoo nullFoo();
+ @Nullable String string();
+ Provider<String> stringProvider();
+ Number number();
+ Provider<Number> numberProvider();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/nullables/NullComponentWithDependency.java b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullComponentWithDependency.java
new file mode 100644
index 000000000..05093ed60
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullComponentWithDependency.java
@@ -0,0 +1,28 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test.nullables;
+
+import javax.inject.Provider;
+
+import dagger.Component;
+
+@Component(dependencies = NullComponent.class)
+interface NullComponentWithDependency {
+ @Nullable String string();
+ Provider<String> stringProvider();
+ Number number();
+ Provider<Number> numberProvider();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/nullables/NullFoo.java b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullFoo.java
new file mode 100644
index 000000000..9ed4b5dea
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullFoo.java
@@ -0,0 +1,56 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test.nullables;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+class NullFoo {
+ final String string;
+ final Provider<String> stringProvider;
+ final Number number;
+ final Provider<Number> numberProvider;
+
+ @Inject
+ NullFoo(@Nullable String string,
+ Provider<String> stringProvider,
+ Number number,
+ Provider<Number> numberProvider) {
+ this.string = string;
+ this.stringProvider = stringProvider;
+ this.number = number;
+ this.numberProvider = numberProvider;
+ }
+
+ String methodInjectedString;
+ Provider<String> methodInjectedStringProvider;
+ Number methodInjectedNumber;
+ Provider<Number> methodInjectedNumberProvider;
+ @Inject void inject(@Nullable String string,
+ Provider<String> stringProvider,
+ Number number,
+ Provider<Number> numberProvider) {
+ this.methodInjectedString = string;
+ this.methodInjectedStringProvider = stringProvider;
+ this.methodInjectedNumber = number;
+ this.methodInjectedNumberProvider = numberProvider;
+ }
+
+ @Nullable @Inject String fieldInjectedString;
+ @Inject Provider<String> fieldInjectedStringProvider;
+ @Inject Number fieldInjectedNumber;
+ @Inject Provider<Number> fieldInjectedNumberProvider;
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/nullables/NullModule.java b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullModule.java
new file mode 100644
index 000000000..652d5ebbb
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullModule.java
@@ -0,0 +1,35 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test.nullables;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+class NullModule {
+ Number numberValue = null;
+
+ @Nullable
+ @Provides
+ String provideNullableString() {
+ return null;
+ }
+
+ @Provides
+ Number provideNumber() {
+ return numberValue;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/nullables/Nullable.java b/compiler/src/it/functional-tests/src/main/java/test/nullables/Nullable.java
new file mode 100644
index 000000000..86776406a
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/nullables/Nullable.java
@@ -0,0 +1,3 @@
+package test.nullables;
+
+@interface Nullable {}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/staticprovides/AllStaticModule.java b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/AllStaticModule.java
new file mode 100644
index 000000000..f47d36c6a
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/AllStaticModule.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.staticprovides;
+
+import static dagger.Provides.Type.SET;
+import static dagger.Provides.Type.SET_VALUES;
+import static java.util.Collections.emptySet;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.Set;
+
+@Module
+final class AllStaticModule {
+ @Provides(type = SET) static String contributeString() {
+ return AllStaticModule.class + ".contributeString";
+ }
+
+ @Provides(type = SET_VALUES) static Set<Integer> contibuteEmptyIntegerSet() {
+ return emptySet();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/staticprovides/SomeStaticModule.java b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/SomeStaticModule.java
new file mode 100644
index 000000000..53ee14d95
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/SomeStaticModule.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.staticprovides;
+
+import static dagger.Provides.Type.SET;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+final class SomeStaticModule {
+ @Provides(type = SET) static String contributeStringFromAStaticMethod() {
+ return SomeStaticModule.class + ".contributeStringFromAStaticMethod";
+ }
+
+ @Provides(type = SET) String contributeStringFromAnInstanceMethod() {
+ return SomeStaticModule.class + ".contributeStringFromAnInstanceMethod";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/staticprovides/StaticTestComponent.java b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/StaticTestComponent.java
new file mode 100644
index 000000000..4be51ed7b
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/StaticTestComponent.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.staticprovides;
+
+import dagger.Component;
+import java.util.Set;
+
+/**
+ * A simple component that demonstrates both static and non-static provides methods.
+ */
+@Component(modules = {AllStaticModule.class, SomeStaticModule.class})
+interface StaticTestComponent {
+ Set<String> getMultiboundStrings();
+ Set<Integer> getMultiboundIntegers();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/staticprovides/StaticTestComponentWithBuilder.java b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/StaticTestComponentWithBuilder.java
new file mode 100644
index 000000000..d778fc5c5
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/StaticTestComponentWithBuilder.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.staticprovides;
+
+import dagger.Component;
+
+/**
+ * A simple component that demonstrates both static and non-static provides methods with a builder.
+ */
+@Component(modules = {AllStaticModule.class, SomeStaticModule.class})
+interface StaticTestComponentWithBuilder extends StaticTestComponent {
+ @Component.Builder
+ interface Builder {
+ Builder allStaticModule(AllStaticModule allStaticModule);
+ Builder someStaticModule(SomeStaticModule someStaticModule);
+ StaticTestComponentWithBuilder build();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/sub/ContributionsModule.java b/compiler/src/it/functional-tests/src/main/java/test/sub/ContributionsModule.java
new file mode 100644
index 000000000..b10ac4533
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/sub/ContributionsModule.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.sub;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import static dagger.Provides.Type.SET;
+import static dagger.Provides.Type.SET_VALUES;
+
+@Module
+public final class ContributionsModule {
+ @Provides(type = SET) int contributeAnInt(double doubleDependency) {
+ return 1742;
+ }
+
+ @Provides(type = SET) int contributeAnotherInt() {
+ return 832;
+ }
+
+ @Provides(type = SET_VALUES) Set<Integer> contributeSomeInts() {
+ return Collections.unmodifiableSet(new LinkedHashSet<Integer>(Arrays.asList(-1, -90, -17)));
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/sub/Exposed.java b/compiler/src/it/functional-tests/src/main/java/test/sub/Exposed.java
new file mode 100644
index 000000000..9195b33f9
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/sub/Exposed.java
@@ -0,0 +1,19 @@
+package test.sub;
+
+import javax.inject.Inject;
+import test.Generic;
+import test.Generic2;
+
+public class Exposed {
+
+ @Inject public Generic2<PackagePrivate> gpp2;
+ @Inject public Generic2<PackagePrivateContainer.PublicEnclosed> gppc2;
+
+ public Generic<PackagePrivate> gpp;
+ public Generic<PackagePrivateContainer.PublicEnclosed> gppc;
+
+ @Inject Exposed(Generic<PackagePrivate> gpp, Generic<PackagePrivateContainer.PublicEnclosed> gppc) {
+ this.gpp = gpp;
+ this.gppc = gppc;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/sub/OtherThing.java b/compiler/src/it/functional-tests/src/main/java/test/sub/OtherThing.java
new file mode 100644
index 000000000..94935171f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/sub/OtherThing.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.sub;
+
+import javax.inject.Inject;
+
+public final class OtherThing {
+ @Inject public OtherThing(int i) {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/sub/PackagePrivate.java b/compiler/src/it/functional-tests/src/main/java/test/sub/PackagePrivate.java
new file mode 100644
index 000000000..9af646a50
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/sub/PackagePrivate.java
@@ -0,0 +1,7 @@
+package test.sub;
+
+import javax.inject.Inject;
+
+class PackagePrivate {
+ @Inject PackagePrivate() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/sub/PackagePrivateContainer.java b/compiler/src/it/functional-tests/src/main/java/test/sub/PackagePrivateContainer.java
new file mode 100644
index 000000000..765b01504
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/sub/PackagePrivateContainer.java
@@ -0,0 +1,9 @@
+package test.sub;
+
+import javax.inject.Inject;
+
+class PackagePrivateContainer {
+ public static class PublicEnclosed {
+ @Inject PublicEnclosed() {}
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/sub/PublicSubclass.java b/compiler/src/it/functional-tests/src/main/java/test/sub/PublicSubclass.java
new file mode 100644
index 000000000..586d55d93
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/sub/PublicSubclass.java
@@ -0,0 +1,10 @@
+package test.sub;
+
+import javax.inject.Inject;
+import test.Generic;
+
+public class PublicSubclass extends Generic<PackagePrivate> {
+ @Inject public PublicSubclass(PackagePrivate pp) {
+ super(pp);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/sub/PublicSubclass2.java b/compiler/src/it/functional-tests/src/main/java/test/sub/PublicSubclass2.java
new file mode 100644
index 000000000..c356fa8f0
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/sub/PublicSubclass2.java
@@ -0,0 +1,10 @@
+package test.sub;
+
+import javax.inject.Inject;
+import test.Generic;
+
+public class PublicSubclass2 extends Generic<PackagePrivateContainer.PublicEnclosed> {
+ @Inject public PublicSubclass2(PackagePrivateContainer.PublicEnclosed pp) {
+ super(pp);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/AnInterface.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/AnInterface.java
new file mode 100644
index 000000000..8aaa015d1
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/AnInterface.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+interface AnInterface {
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/BoundAsSingleton.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/BoundAsSingleton.java
new file mode 100644
index 000000000..8ae147415
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/BoundAsSingleton.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import javax.inject.Qualifier;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Documented
+@Retention(RUNTIME)
+@Qualifier
+@interface BoundAsSingleton {}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildAbstractClassComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildAbstractClassComponent.java
new file mode 100644
index 000000000..6c061bc5c
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildAbstractClassComponent.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Subcomponent;
+
+@Subcomponent(modules = ChildModule.class)
+abstract class ChildAbstractClassComponent implements ChildComponent {
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponent.java
new file mode 100644
index 000000000..67d66cae9
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponent.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Subcomponent;
+import java.util.Set;
+import javax.inject.Provider;
+
+@Subcomponent(modules = ChildModule.class)
+interface ChildComponent {
+ Provider<UnscopedType> getUnscopedTypeProvider();
+
+ RequiresSingletons requiresSingleton();
+
+ Set<Object> objectSet();
+
+ GrandchildComponent newGrandchildComponent();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponentRequiringModules.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponentRequiringModules.java
new file mode 100644
index 000000000..905c68990
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponentRequiringModules.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Subcomponent;
+
+@Subcomponent(modules = {
+ ChildModule.class,
+ ChildModuleWithParameters.class,
+ ChildModuleWithState.class})
+interface ChildComponentRequiringModules {
+ int getInt();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponentWithMultibindings.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponentWithMultibindings.java
new file mode 100644
index 000000000..9ed266aec
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponentWithMultibindings.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Subcomponent;
+
+@Subcomponent(modules = ChildMultibindingModule.class)
+interface ChildComponentWithMultibindings {
+ RequiresMultibindingsInChild requiresMultibindingsInChild();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModule.java
new file mode 100644
index 000000000..ef28bd47a
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModule.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Module;
+import dagger.Provides;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+final class ChildModule {
+ @Provides(type = SET) Object provideUnscopedObject() {
+ return new Object() {
+ @Override public String toString() {
+ return "unscoped in child";
+ }
+ };
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithParameters.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithParameters.java
new file mode 100644
index 000000000..e18b4a6da
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithParameters.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Module;
+
+/**
+ * This is a module that can't be constructed with a default constructor.
+ */
+@Module
+final class ChildModuleWithParameters {
+ public ChildModuleWithParameters(@SuppressWarnings("unused") Object whatever) {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithState.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithState.java
new file mode 100644
index 000000000..5908a005b
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithState.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * This is a module that can be constructed with a default constructor, but has state, so callers
+ * might want to pass a reference anyway.
+ */
+@Module
+final class ChildModuleWithState {
+ private int i = 0;
+
+ @Provides int provideInt() {
+ return i++;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildMultibindingModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildMultibindingModule.java
new file mode 100644
index 000000000..ae02b9e6f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildMultibindingModule.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.mapkeys.StringKey;
+
+import static dagger.Provides.Type.MAP;
+import static dagger.Provides.Type.SET;
+
+@Module
+class ChildMultibindingModule {
+
+ @Provides(type = SET)
+ static Object childObject() {
+ return "object provided by child";
+ }
+
+ @Provides(type = MAP)
+ @StringKey("child key")
+ static Object childKeyObject() {
+ return "object in child";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GenericParentComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GenericParentComponent.java
new file mode 100644
index 000000000..5580ab8d4
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GenericParentComponent.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+interface GenericParentComponent<B> {
+ B subcomponent();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GrandchildComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GrandchildComponent.java
new file mode 100644
index 000000000..9f724edfc
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GrandchildComponent.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Subcomponent;
+import java.util.Set;
+import javax.inject.Provider;
+
+@Subcomponent(modules = GrandchildModule.class)
+interface GrandchildComponent {
+ Provider<UnscopedType> getUnscopedTypeProvider();
+
+ RequiresSingletons requiresSingleton();
+
+ Set<Object> objectSet();
+
+ NeedsAnInterface needsAnInterface();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GrandchildModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GrandchildModule.java
new file mode 100644
index 000000000..b2885412f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GrandchildModule.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Module;
+import dagger.Provides;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+final class GrandchildModule {
+ @Provides(type = SET) Object provideUnscopedObject() {
+ return new Object() {
+ @Override public String toString() {
+ return "unscoped in grandchild";
+ }
+ };
+ }
+
+ @Provides AnInterface provideAnInterface(ImplementsAnInterface implementsAnInterface) {
+ return implementsAnInterface;
+ }
+
+ @Provides NeedsAnInterface provideNeedsAnInterface(AnInterface anInterface) {
+ return new NeedsAnInterface(anInterface);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ImplementsAnInterface.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ImplementsAnInterface.java
new file mode 100644
index 000000000..ff3170cba
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ImplementsAnInterface.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import javax.inject.Inject;
+
+class ImplementsAnInterface implements AnInterface {
+ @Inject ImplementsAnInterface() {}
+}
+
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/NeedsAnInterface.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/NeedsAnInterface.java
new file mode 100644
index 000000000..bccde8589
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/NeedsAnInterface.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+class NeedsAnInterface {
+ NeedsAnInterface(AnInterface anInterface) {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponent.java
new file mode 100644
index 000000000..ebb067d6f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponent.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Component;
+import javax.inject.Singleton;
+
+@Component(modules = ParentModule.class)
+@Singleton
+interface ParentComponent extends ParentGetters {
+ ChildComponent newChildComponent();
+
+ ChildAbstractClassComponent newChildAbstractClassComponent();
+
+ ChildComponentRequiringModules newChildComponentRequiringModules(
+ ChildModuleWithParameters cmwp,
+ ChildModuleWithState childModuleWithState);
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponentWithMultibindings.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponentWithMultibindings.java
new file mode 100644
index 000000000..46fe8835c
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponentWithMultibindings.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Component;
+
+@Component(modules = ParentMultibindingModule.class)
+interface ParentComponentWithMultibindings extends ParentComponentWithoutMultibindings {
+ RequiresMultibindingsInParent requiresMultibindingsInParent();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponentWithoutMultibindings.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponentWithoutMultibindings.java
new file mode 100644
index 000000000..3d4431ca9
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponentWithoutMultibindings.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Component;
+
+@Component(modules = ParentMultibindingModule.class)
+interface ParentComponentWithoutMultibindings {
+ ChildComponentWithMultibindings childComponent();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentGetters.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentGetters.java
new file mode 100644
index 000000000..3ff855a9d
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentGetters.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import java.util.Set;
+import javax.inject.Provider;
+
+interface ParentGetters {
+ Provider<UnscopedType> getUnscopedTypeProvider();
+
+ Set<Object> objectSet();
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentModule.java
new file mode 100644
index 000000000..dbe1a534a
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentModule.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Module;
+import dagger.Provides;
+import javax.inject.Singleton;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+final class ParentModule {
+ @Provides(type = SET) Object provideUnscopedObject() {
+ return new Object() {
+ @Override public String toString() {
+ return "unscoped in parent";
+ }
+ };
+ }
+
+ @Provides(type = SET) @Singleton Object provideSingletonObject() {
+ return new Object() {
+ @Override public String toString() {
+ return "singleton";
+ }
+ };
+ }
+
+ @Provides @Singleton @BoundAsSingleton UnscopedType provideUnscopedTypeBoundAsSingleton(
+ UnscopedType unscopedType) {
+ return unscopedType;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentMultibindingModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentMultibindingModule.java
new file mode 100644
index 000000000..e4ec173de
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentMultibindingModule.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.mapkeys.StringKey;
+
+import static dagger.Provides.Type.MAP;
+import static dagger.Provides.Type.SET;
+
+@Module
+class ParentMultibindingModule {
+
+ @Provides(type = SET)
+ static Object provideObject() {
+ return "object provided by parent";
+ }
+
+ @Provides(type = SET)
+ static String provideString() {
+ return "string provided by parent";
+ }
+
+ @Provides(type = SET)
+ static RequiresMultiboundObjects requiresMultiboundObjects(
+ RequiresMultiboundObjects requiresMultiboundObjects) {
+ return requiresMultiboundObjects;
+ }
+
+ @Provides(type = MAP)
+ @StringKey("parent key")
+ static String parentKeyString() {
+ return "string in parent";
+ }
+
+ @Provides(type = MAP)
+ @StringKey("parent key")
+ static Object parentKeyObject() {
+ return "object in parent";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentOfGenericComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentOfGenericComponent.java
new file mode 100644
index 000000000..bf8553772
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentOfGenericComponent.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import dagger.Component;
+import javax.inject.Singleton;
+
+@Component(modules = ParentModule.class)
+@Singleton
+interface ParentOfGenericComponent extends GenericParentComponent<ChildComponent>, ParentGetters {
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultibindingsInChild.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultibindingsInChild.java
new file mode 100644
index 000000000..4ec0469de
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultibindingsInChild.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import java.util.Set;
+import javax.inject.Inject;
+
+class RequiresMultibindingsInChild extends RequiresMultibindingsInParent {
+
+ @Inject
+ RequiresMultibindingsInChild(
+ RequiresMultiboundObjects requiresMultiboundObjects,
+ RequiresMultiboundStrings requiresMultiboundStrings,
+ Set<RequiresMultiboundObjects> setOfRequiresMultiboundObjects) {
+ super(requiresMultiboundObjects, requiresMultiboundStrings, setOfRequiresMultiboundObjects);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultibindingsInParent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultibindingsInParent.java
new file mode 100644
index 000000000..a48d38bfa
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultibindingsInParent.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import java.util.Set;
+import javax.inject.Inject;
+
+class RequiresMultibindingsInParent {
+ private final RequiresMultiboundObjects requiresMultiboundObjects;
+ private final RequiresMultiboundStrings requiresMultiboundStrings;
+ private final Set<RequiresMultiboundObjects> setOfRequiresMultiboundObjects;
+
+ @Inject
+ RequiresMultibindingsInParent(
+ RequiresMultiboundObjects requiresMultiboundObjects,
+ RequiresMultiboundStrings requiresMultiboundStrings,
+ Set<RequiresMultiboundObjects> setOfRequiresMultiboundObjects) {
+ this.requiresMultiboundObjects = requiresMultiboundObjects;
+ this.requiresMultiboundStrings = requiresMultiboundStrings;
+ this.setOfRequiresMultiboundObjects = setOfRequiresMultiboundObjects;
+ }
+
+ RequiresMultiboundObjects requiresMultiboundObjects() {
+ return requiresMultiboundObjects;
+ }
+
+ RequiresMultiboundStrings requiresMultiboundStrings() {
+ return requiresMultiboundStrings;
+ }
+
+ Set<RequiresMultiboundObjects> setOfRequiresMultiboundObjects() {
+ return setOfRequiresMultiboundObjects;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultiboundObjects.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultiboundObjects.java
new file mode 100644
index 000000000..d787153e3
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultiboundObjects.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Inject;
+
+class RequiresMultiboundObjects {
+ private final Set<Object> setOfObjects;
+ private final Map<String, Object> mapOfObjects;
+
+ @Inject
+ RequiresMultiboundObjects(Set<Object> setOfObjects, Map<String, Object> mapOfObjects) {
+ this.setOfObjects = setOfObjects;
+ this.mapOfObjects = mapOfObjects;
+ }
+
+ Set<Object> setOfObjects() {
+ return setOfObjects;
+ }
+
+ Map<String, Object> mapOfObjects() {
+ return mapOfObjects;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultiboundStrings.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultiboundStrings.java
new file mode 100644
index 000000000..410bdf2c0
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultiboundStrings.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Inject;
+
+class RequiresMultiboundStrings {
+ private final Set<String> setOfStrings;
+ private final Map<String, String> mapOfStrings;
+
+ @Inject
+ RequiresMultiboundStrings(Set<String> setOfStrings, Map<String, String> mapOfStrings) {
+ this.setOfStrings = setOfStrings;
+ this.mapOfStrings = mapOfStrings;
+ }
+
+ Set<String> setOfStrings() {
+ return setOfStrings;
+ }
+
+ Map<String, String> mapOfStrings() {
+ return mapOfStrings;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresSingletons.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresSingletons.java
new file mode 100644
index 000000000..2d4053824
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresSingletons.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import javax.inject.Inject;
+
+final class RequiresSingletons {
+ private final SingletonType singletonType;
+ private final UnscopedType unscopedTypeBoundAsSingleton;
+
+ @Inject RequiresSingletons(SingletonType singletonType,
+ @BoundAsSingleton UnscopedType unscopedTypeBoundAsSingleton) {
+ this.singletonType = singletonType;
+ this.unscopedTypeBoundAsSingleton = unscopedTypeBoundAsSingleton;
+ }
+
+ SingletonType singletonType() {
+ return singletonType;
+ }
+
+ UnscopedType unscopedTypeBoundAsSingleton() {
+ return unscopedTypeBoundAsSingleton;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/SingletonType.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/SingletonType.java
new file mode 100644
index 000000000..663e858a9
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/SingletonType.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+@Singleton
+final class SingletonType {
+ @Inject SingletonType() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/UnscopedType.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/UnscopedType.java
new file mode 100644
index 000000000..89c00855f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/UnscopedType.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import javax.inject.Inject;
+
+final class UnscopedType {
+ @Inject UnscopedType(@SuppressWarnings("unused") SingletonType singletonType) {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/ChildComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/ChildComponent.java
new file mode 100644
index 000000000..b95502cf8
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/ChildComponent.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent.hiding;
+
+import dagger.Subcomponent;
+
+@Subcomponent(modules = test.subcomponent.hiding.b.CommonModuleName.class)
+interface ChildComponent {
+ //ensure that t.s.h.a.CommonName gets bound in this component
+ test.subcomponent.hiding.a.CommonName aCommonName();
+ //ensure that t.s.h.b.CommonName gets bound in this component
+ test.subcomponent.hiding.b.CommonName bCommonName();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/ParentComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/ParentComponent.java
new file mode 100644
index 000000000..d7c66a679
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/ParentComponent.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent.hiding;
+
+import dagger.Component;
+import javax.inject.Singleton;
+
+@Component(modules = test.subcomponent.hiding.a.CommonModuleName.class)
+@Singleton
+interface ParentComponent {
+ // ensure that t.s.h.a.CommonName gets bound in this component
+ test.subcomponent.hiding.a.CommonName aCommonName();
+
+ ChildComponent newChildComponent();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/a/CommonModuleName.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/a/CommonModuleName.java
new file mode 100644
index 000000000..ad692896f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/a/CommonModuleName.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent.hiding.a;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+public class CommonModuleName {
+ @Provides String provideString() {
+ return "a";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/a/CommonName.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/a/CommonName.java
new file mode 100644
index 000000000..b2aefda06
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/a/CommonName.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent.hiding.a;
+
+import javax.inject.Inject;
+
+public final class CommonName {
+ private final String s;
+
+ @Inject CommonName(String s) {
+ this.s = s;
+ }
+
+ @Override
+ public String toString() {
+ return s;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/b/CommonModuleName.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/b/CommonModuleName.java
new file mode 100644
index 000000000..66deab5aa
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/b/CommonModuleName.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent.hiding.b;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+public class CommonModuleName {
+ @Provides int provideString() {
+ return 1;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/b/CommonName.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/b/CommonName.java
new file mode 100644
index 000000000..023cbdbf2
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/b/CommonName.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent.hiding.b;
+
+import javax.inject.Inject;
+
+public final class CommonName {
+ private final int i;
+
+ @Inject CommonName(int i) {
+ this.i = i;
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toString(i);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/OnlyUsedInChild.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/OnlyUsedInChild.java
new file mode 100644
index 000000000..2dd8d20d3
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/OnlyUsedInChild.java
@@ -0,0 +1,5 @@
+package test.subcomponent.repeat;
+
+abstract class OnlyUsedInChild {
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/OnlyUsedInParent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/OnlyUsedInParent.java
new file mode 100644
index 000000000..cc22b1e05
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/OnlyUsedInParent.java
@@ -0,0 +1,5 @@
+package test.subcomponent.repeat;
+
+abstract class OnlyUsedInParent {
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/ParentComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/ParentComponent.java
new file mode 100644
index 000000000..f0af00237
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/ParentComponent.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent.repeat;
+
+import dagger.Component;
+import java.util.Set;
+
+@Component(modules = RepeatedModule.class)
+interface ParentComponent {
+ Object state();
+
+ String getString();
+ Set<String> getMultiboundStrings();
+ OnlyUsedInParent getOnlyUsedInParent();
+
+ SubcomponentWithRepeatedModule.Builder newChildComponentBuilder();
+
+ SubcomponentWithoutRepeatedModule newChildComponentWithoutRepeatedModule();
+
+ @Component.Builder
+ interface Builder {
+ Builder repeatedModule(RepeatedModule repeatedModule);
+
+ ParentComponent build();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/RepeatedModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/RepeatedModule.java
new file mode 100644
index 000000000..d0997513d
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/RepeatedModule.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent.repeat;
+
+import dagger.Module;
+import dagger.Provides;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+final class RepeatedModule {
+ private final Object state = new Object();
+
+ @Provides
+ Object state() {
+ return state;
+ }
+
+ @Provides
+ static String provideString() {
+ return "a string";
+ }
+
+ @Provides(type = SET)
+ static String contributeString() {
+ return "a string in a set";
+ }
+
+ @Provides
+ static OnlyUsedInParent provideOnlyUsedInParent() {
+ return new OnlyUsedInParent() {};
+ }
+
+ @Provides
+ static OnlyUsedInChild provideOnlyUsedInChild() {
+ return new OnlyUsedInChild() {};
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/SubcomponentWithRepeatedModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/SubcomponentWithRepeatedModule.java
new file mode 100644
index 000000000..279bc954c
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/SubcomponentWithRepeatedModule.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent.repeat;
+
+import dagger.Subcomponent;
+import java.util.Set;
+
+@Subcomponent(modules = RepeatedModule.class)
+interface SubcomponentWithRepeatedModule {
+ Object state();
+
+ String getString();
+
+ Set<String> getMultiboundStrings();
+
+ OnlyUsedInChild getOnlyUsedInChild();
+
+ @Subcomponent.Builder
+ interface Builder {
+ Builder repeatedModule(RepeatedModule repeatedModule);
+
+ SubcomponentWithRepeatedModule build();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/SubcomponentWithoutRepeatedModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/SubcomponentWithoutRepeatedModule.java
new file mode 100644
index 000000000..e63c9a0ae
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/SubcomponentWithoutRepeatedModule.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent.repeat;
+
+import dagger.Subcomponent;
+
+@Subcomponent
+interface SubcomponentWithoutRepeatedModule {
+ SubcomponentWithRepeatedModule.Builder newGrandchildBuilder();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/tck/CarModule.java b/compiler/src/it/functional-tests/src/main/java/test/tck/CarModule.java
new file mode 100644
index 000000000..bc7851739
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/tck/CarModule.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.tck;
+
+import dagger.Module;
+import dagger.Provides;
+import org.atinject.tck.auto.Car;
+import org.atinject.tck.auto.Convertible;
+
+@Module
+class CarModule {
+ @Provides
+ Car provideConvertible(Convertible convertible) {
+ return convertible;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/tck/CarShop.java b/compiler/src/it/functional-tests/src/main/java/test/tck/CarShop.java
new file mode 100644
index 000000000..e42532e9d
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/tck/CarShop.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.tck;
+
+import dagger.Component;
+import org.atinject.tck.auto.Car;
+import javax.inject.Singleton;
+
+@Singleton
+@Component(
+ modules = {
+ CarModule.class,
+ TireModule.class,
+ SeatModule.class,
+ EngineModule.class,
+ FuelTankModule.class
+ }
+)
+public interface CarShop {
+ @SuppressWarnings("dependency-cycle")
+ Car make();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/tck/EngineModule.java b/compiler/src/it/functional-tests/src/main/java/test/tck/EngineModule.java
new file mode 100644
index 000000000..577fb5b70
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/tck/EngineModule.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.tck;
+
+import dagger.MembersInjector;
+import dagger.Module;
+import dagger.Provides;
+import org.atinject.tck.auto.Engine;
+import org.atinject.tck.auto.V8Engine;
+
+@Module
+public class EngineModule {
+ @Provides
+ Engine provideEngine(MembersInjector<V8Engine> injector) {
+ // This is provided because V8Engine has no @Inject constructor and Dagger requires an @Inject
+ // constructor, however this is a TCK supplied class that we prefer to leave unmodified.
+ V8Engine engine = new V8Engine();
+ injector.injectMembers(engine);
+ return engine;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/tck/FuelTankModule.java b/compiler/src/it/functional-tests/src/main/java/test/tck/FuelTankModule.java
new file mode 100644
index 000000000..931556cfe
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/tck/FuelTankModule.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.tck;
+
+import dagger.Module;
+import dagger.Provides;
+import org.atinject.tck.auto.FuelTank;
+
+@Module
+class FuelTankModule {
+ @Provides
+ FuelTank provideFuelTank() {
+ return new FuelTank();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/tck/SeatModule.java b/compiler/src/it/functional-tests/src/main/java/test/tck/SeatModule.java
new file mode 100644
index 000000000..5c6b72988
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/tck/SeatModule.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.tck;
+
+import dagger.Module;
+import dagger.Provides;
+import org.atinject.tck.auto.Drivers;
+import org.atinject.tck.auto.DriversSeat;
+import org.atinject.tck.auto.Seat;
+
+@Module
+class SeatModule {
+ @Provides
+ @Drivers
+ Seat provideSeat(DriversSeat seat) {
+ return seat;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/tck/TireModule.java b/compiler/src/it/functional-tests/src/main/java/test/tck/TireModule.java
new file mode 100644
index 000000000..914a6d6ec
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/tck/TireModule.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.tck;
+
+import dagger.Module;
+import dagger.Provides;
+import org.atinject.tck.auto.Tire;
+import org.atinject.tck.auto.accessories.SpareTire;
+import javax.inject.Named;
+
+@Module
+class TireModule {
+ @Provides
+ @Named("spare")
+ Tire provideTire(SpareTire sparetire) {
+ return sparetire;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/BasicTest.java b/compiler/src/it/functional-tests/src/test/java/test/BasicTest.java
new file mode 100644
index 000000000..fe9c6afe9
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/BasicTest.java
@@ -0,0 +1,116 @@
+/*
+* Copyright (C) 2014 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+import static com.google.common.truth.Truth.assertThat;
+import static test.PrimitivesModule.BOUND_BOOLEAN;
+import static test.PrimitivesModule.BOUND_BOOLEAN_ARRAY;
+import static test.PrimitivesModule.BOUND_BYTE;
+import static test.PrimitivesModule.BOUND_BYTE_ARRAY;
+import static test.PrimitivesModule.BOUND_CHAR;
+import static test.PrimitivesModule.BOUND_CHAR_ARRAY;
+import static test.PrimitivesModule.BOUND_DOUBLE;
+import static test.PrimitivesModule.BOUND_DOUBLE_ARRAY;
+import static test.PrimitivesModule.BOUND_FLOAT;
+import static test.PrimitivesModule.BOUND_FLOAT_ARRAY;
+import static test.PrimitivesModule.BOUND_INT;
+import static test.PrimitivesModule.BOUND_INT_ARRAY;
+import static test.PrimitivesModule.BOUND_LONG;
+import static test.PrimitivesModule.BOUND_LONG_ARRAY;
+import static test.PrimitivesModule.BOUND_SHORT;
+import static test.PrimitivesModule.BOUND_SHORT_ARRAY;
+
+@RunWith(Theories.class)
+public class BasicTest {
+ @DataPoint
+ public static final BasicComponent basicComponent = DaggerBasicComponent.create();
+ @DataPoint
+ public static final BasicComponent abstractClassBasicComponent =
+ DaggerBasicAbstractClassComponent.create();
+
+ @Theory public void primitives(BasicComponent basicComponent) {
+ assertThat(basicComponent.getByte()).isEqualTo(BOUND_BYTE);
+ assertThat(basicComponent.getChar()).isEqualTo(BOUND_CHAR);
+ assertThat(basicComponent.getShort()).isEqualTo(BOUND_SHORT);
+ assertThat(basicComponent.getInt()).isEqualTo(BOUND_INT);
+ assertThat(basicComponent.getLong()).isEqualTo(BOUND_LONG);
+ assertThat(basicComponent.getBoolean()).isEqualTo(BOUND_BOOLEAN);
+ assertThat(basicComponent.getFloat()).isEqualTo(BOUND_FLOAT);
+ assertThat(basicComponent.getDouble()).isEqualTo(BOUND_DOUBLE);
+ }
+
+ @Theory public void boxedPrimitives(BasicComponent basicComponent) {
+ assertThat(basicComponent.getBoxedByte()).isEqualTo(new Byte(BOUND_BYTE));
+ assertThat(basicComponent.getBoxedChar()).isEqualTo(new Character(BOUND_CHAR));
+ assertThat(basicComponent.getBoxedShort()).isEqualTo(new Short(BOUND_SHORT));
+ assertThat(basicComponent.getBoxedInt()).isEqualTo(new Integer(BOUND_INT));
+ assertThat(basicComponent.getBoxedLong()).isEqualTo(new Long(BOUND_LONG));
+ assertThat(basicComponent.getBoxedBoolean()).isEqualTo(new Boolean(BOUND_BOOLEAN));
+ assertThat(basicComponent.getBoxedFloat()).isEqualTo(new Float(BOUND_FLOAT));
+ assertThat(basicComponent.getBoxedDouble()).isEqualTo(new Double(BOUND_DOUBLE));
+ }
+
+ @Theory public void boxedPrimitiveProviders(BasicComponent basicComponent) {
+ assertThat(basicComponent.getByteProvider().get()).isEqualTo(new Byte(BOUND_BYTE));
+ assertThat(basicComponent.getCharProvider().get()).isEqualTo(new Character(BOUND_CHAR));
+ assertThat(basicComponent.getShortProvider().get()).isEqualTo(new Short(BOUND_SHORT));
+ assertThat(basicComponent.getIntProvider().get()).isEqualTo(new Integer(BOUND_INT));
+ assertThat(basicComponent.getLongProvider().get()).isEqualTo(new Long(BOUND_LONG));
+ assertThat(basicComponent.getBooleanProvider().get()).isEqualTo(new Boolean(BOUND_BOOLEAN));
+ assertThat(basicComponent.getFloatProvider().get()).isEqualTo(new Float(BOUND_FLOAT));
+ assertThat(basicComponent.getDoubleProvider().get()).isEqualTo(new Double(BOUND_DOUBLE));
+ }
+
+ @Theory public void primitiveArrays(BasicComponent basicComponent) {
+ assertThat(basicComponent.getByteArray()).isSameAs(BOUND_BYTE_ARRAY);
+ assertThat(basicComponent.getCharArray()).isSameAs(BOUND_CHAR_ARRAY);
+ assertThat(basicComponent.getShortArray()).isSameAs(BOUND_SHORT_ARRAY);
+ assertThat(basicComponent.getIntArray()).isSameAs(BOUND_INT_ARRAY);
+ assertThat(basicComponent.getLongArray()).isSameAs(BOUND_LONG_ARRAY);
+ assertThat(basicComponent.getBooleanArray()).isSameAs(BOUND_BOOLEAN_ARRAY);
+ assertThat(basicComponent.getFloatArray()).isSameAs(BOUND_FLOAT_ARRAY);
+ assertThat(basicComponent.getDoubleArray()).isSameAs(BOUND_DOUBLE_ARRAY);
+ }
+
+ @Theory public void primitiveArrayProviders(BasicComponent basicComponent) {
+ assertThat(basicComponent.getByteArrayProvider().get()).isSameAs(BOUND_BYTE_ARRAY);
+ assertThat(basicComponent.getCharArrayProvider().get()).isSameAs(BOUND_CHAR_ARRAY);
+ assertThat(basicComponent.getShortArrayProvider().get()).isSameAs(BOUND_SHORT_ARRAY);
+ assertThat(basicComponent.getIntArrayProvider().get()).isSameAs(BOUND_INT_ARRAY);
+ assertThat(basicComponent.getLongArrayProvider().get()).isSameAs(BOUND_LONG_ARRAY);
+ assertThat(basicComponent.getBooleanArrayProvider().get()).isSameAs(BOUND_BOOLEAN_ARRAY);
+ assertThat(basicComponent.getFloatArrayProvider().get()).isSameAs(BOUND_FLOAT_ARRAY);
+ assertThat(basicComponent.getDoubleArrayProvider().get()).isSameAs(BOUND_DOUBLE_ARRAY);
+ }
+
+ @Theory public void noOpMembersInjection(BasicComponent basicComponent) {
+ Object object = new Object();
+ assertThat(basicComponent.noOpMembersInjection(object)).isSameAs(object);
+ }
+
+ @Theory public void basicObject_noDeps(BasicComponent basicComponent) {
+ assertThat(basicComponent.thing()).isNotNull();
+ }
+
+ @Theory public void inheritedMembersInjection(BasicComponent basicComponent) {
+ assertThat(basicComponent.typeWithInheritedMembersInjection().thing).isNotNull();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/DependsOnGeneratedCodeTest.java b/compiler/src/it/functional-tests/src/test/java/test/DependsOnGeneratedCodeTest.java
new file mode 100644
index 000000000..0310df6ef
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/DependsOnGeneratedCodeTest.java
@@ -0,0 +1,29 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class DependsOnGeneratedCodeTest {
+ @Test public void testComponentDependsOnGeneratedCode() {
+ assertThat(DaggerComponentDependsOnGeneratedCode.create().needsFactory()).isNotNull();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/GenericTest.java b/compiler/src/it/functional-tests/src/test/java/test/GenericTest.java
new file mode 100644
index 000000000..f1c981f25
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/GenericTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import test.sub.Exposed;
+import test.sub.PublicSubclass;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+
+@RunWith(JUnit4.class)
+public class GenericTest {
+
+ @Test public void testGenericComponentCreate() {
+ GenericComponent component = DaggerGenericComponent.create();
+ assertThat(component).isNotNull();
+ }
+
+ @Test public void testGenericSimpleReferences() {
+ GenericComponent component = DaggerGenericComponent.create();
+ assertThat(component.referencesGeneric().genericA.t).isNotNull();
+ }
+
+ @Test public void testGenericDoubleReferences() {
+ GenericComponent component = DaggerGenericComponent.create();
+ GenericDoubleReferences<A> doubleA = component.doubleGenericA();
+ assertThat(doubleA.a).isNotNull();
+ assertThat(doubleA.a2).isNotNull();
+ assertThat(doubleA.t).isNotNull();
+ assertThat(doubleA.t2).isNotNull();
+
+ GenericDoubleReferences<B> doubleB = component.doubleGenericB();
+ assertThat(doubleB.a).isNotNull();
+ assertThat(doubleB.a2).isNotNull();
+ assertThat(doubleB.t).isNotNull();
+ assertThat(doubleB.t2).isNotNull();
+ }
+
+ @Test public void complexGenerics() {
+ GenericComponent component = DaggerGenericComponent.create();
+ // validate these can be called w/o exceptions.
+ component.complexGenerics();
+ }
+
+ @Test public void noDepsGenerics() {
+ GenericComponent component = DaggerGenericComponent.create();
+ // validate these can be called w/o exceptions.
+ component.noDepsA();
+ component.noDepsB();
+ }
+
+ @Test public void boundedGenerics() {
+ BoundedGenericModule expected = new BoundedGenericModule();
+ BoundedGenericComponent component = DaggerBoundedGenericComponent.create();
+ BoundedGenerics<Integer, ArrayList<String>, LinkedList<CharSequence>, Integer, List<Integer>>
+ b1 = component.bounds1();
+ assertEquals(expected.provideInteger(), b1.a);
+ assertEquals(expected.provideArrayListString(), b1.b);
+ assertEquals(expected.provideLinkedListCharSeq(), b1.c);
+ assertEquals(expected.provideInteger(), b1.d);
+ assertEquals(expected.provideListOfInteger(), b1.e);
+
+ BoundedGenerics<Double, LinkedList<String>, LinkedList<Comparable<String>>, Double, Set<Double>>
+ b2 = component.bounds2();
+ assertEquals(expected.provideDouble(), b2.a);
+ assertEquals(expected.provideLinkedListString(), b2.b);
+ assertEquals(expected.provideArrayListOfComparableString(), b2.c);
+ assertEquals(expected.provideDouble(), b2.d);
+ assertEquals(expected.provideSetOfDouble(), b2.e);
+ }
+
+ @Test public void membersInjections() {
+ GenericComponent component = DaggerGenericComponent.create();
+ GenericChild<A> childA = new GenericChild<A>();
+ component.injectA(childA);
+ assertThat(childA.a).isNotNull();
+ assertThat(childA.b).isNotNull();
+ assertThat(childA.registeredA).isNotNull();
+ assertThat(childA.registeredB).isNotNull();
+ assertThat(childA.registeredT).isNotNull();
+ assertThat(childA.registeredX).isNotNull();
+ assertThat(childA.registeredY).isNotNull();
+
+ GenericChild<B> childB = new GenericChild<B>();
+ component.injectB(childB);
+ assertThat(childB.a).isNotNull();
+ assertThat(childB.b).isNotNull();
+ assertThat(childB.registeredA).isNotNull();
+ assertThat(childB.registeredB).isNotNull();
+ assertThat(childB.registeredT).isNotNull();
+ assertThat(childB.registeredX).isNotNull();
+ assertThat(childB.registeredY).isNotNull();
+ }
+
+ @Test public void packagePrivateTypeParameterDependencies() {
+ GenericComponent component = DaggerGenericComponent.create();
+ Exposed exposed = component.exposed();
+ assertThat(exposed.gpp.t).isNotNull();
+ assertThat(exposed.gpp2).isNotNull();
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test public void publicSubclassWithPackagePrivateTypeParameterOfSuperclass() {
+ GenericComponent component = DaggerGenericComponent.create();
+ PublicSubclass publicSubclass = component.publicSubclass();
+ assertThat(((Generic)publicSubclass).t).isNotNull();
+ }
+
+ @Test public void singletonScopesAppliesToEachResolvedType() {
+ SingletonGenericComponent component = DaggerSingletonGenericComponent.create();
+ ScopedGeneric<A> a = component.scopedGenericA();
+ assertThat(a).isSameAs(component.scopedGenericA());
+ assertThat(a.t).isNotNull();
+
+ ScopedGeneric<B> b = component.scopedGenericB();
+ assertThat(b).isSameAs(component.scopedGenericB());
+ assertThat(b.t).isNotNull();
+
+ assertThat(a).isNotSameAs(b);
+ }
+
+ @Test public void genericModules() {
+ GenericComponent component = DaggerGenericComponent.create();
+ assertThat(component.iterableInt()).containsExactly(1, 2).inOrder();
+ assertThat(component.iterableDouble()).containsExactly(3d, 4d).inOrder();
+
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/MultibindingTest.java b/compiler/src/it/functional-tests/src/test/java/test/MultibindingTest.java
new file mode 100644
index 000000000..5e06f848f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/MultibindingTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT 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 test;
+
+import com.google.auto.value.AutoAnnotation;
+import com.google.common.collect.ImmutableMap;
+import dagger.mapkeys.ClassKey;
+import dagger.mapkeys.StringKey;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Map;
+import javax.inject.Provider;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class MultibindingTest {
+ private MultibindingComponent multibindingComponent;
+
+ @Before public void setUp() {
+ multibindingComponent = DaggerMultibindingComponent.builder()
+ .multibindingDependency(new MultibindingDependency() {
+ @Override public double doubleDependency() {
+ return 0.0;
+ }
+ })
+ .build();
+ }
+
+ @Test public void map() {
+ Map<String, String> map = multibindingComponent.map();
+ assertThat(map).hasSize(2);
+ assertThat(map).containsEntry("foo", "foo value");
+ assertThat(map).containsEntry("bar", "bar value");
+ }
+
+ @Test public void mapOfProviders() {
+ Map<String, Provider<String>> mapOfProviders = multibindingComponent.mapOfProviders();
+ assertThat(mapOfProviders).hasSize(2);
+ assertThat(mapOfProviders.get("foo").get()).isEqualTo("foo value");
+ assertThat(mapOfProviders.get("bar").get()).isEqualTo("bar value");
+ }
+
+ @Test public void mapKeysAndValues() {
+ assertThat(multibindingComponent.mapKeys()).containsExactly("foo", "bar");
+ assertThat(multibindingComponent.mapValues()).containsExactly("foo value", "bar value");
+ }
+
+ @Test public void nestedKeyMap() {
+ assertThat(multibindingComponent.nestedKeyMap()).isEqualTo(
+ ImmutableMap.of(
+ nestedWrappedKey(Integer.class), "integer",
+ nestedWrappedKey(Long.class), "long"));
+ }
+
+ @Test
+ public void unwrappedAnnotationKeyMap() {
+ assertThat(multibindingComponent.unwrappedAnnotationKeyMap())
+ .isEqualTo(ImmutableMap.of(testStringKey("foo\n"), "foo annotation"));
+ }
+
+ @Test
+ public void wrappedAnnotationKeyMap() {
+ @SuppressWarnings("unchecked")
+ Class<? extends Number>[] classes = new Class[] {Long.class, Integer.class};
+ assertThat(multibindingComponent.wrappedAnnotationKeyMap())
+ .isEqualTo(
+ ImmutableMap.of(
+ testWrappedAnnotationKey(
+ testStringKey("foo"), new int[] {1, 2, 3}, new ClassKey[] {}, classes),
+ "wrapped foo annotation"));
+ }
+
+ @Test
+ public void booleanKeyMap() {
+ assertThat(multibindingComponent.booleanKeyMap()).isEqualTo(ImmutableMap.of(true, "true"));
+ }
+
+ @Test
+ public void byteKeyMap() {
+ assertThat(multibindingComponent.byteKeyMap())
+ .isEqualTo(ImmutableMap.of((byte) 100, "100 byte"));
+ }
+
+ @Test
+ public void charKeyMap() {
+ assertThat(multibindingComponent.characterKeyMap())
+ .isEqualTo(ImmutableMap.of('a', "a char", '\n', "newline char"));
+ }
+
+ @Test
+ public void classKeyMap() {
+ assertThat(multibindingComponent.classKeyMap())
+ .isEqualTo(
+ ImmutableMap.of(
+ Integer.class, "integer",
+ Long.class, "long"));
+ }
+
+ @Test
+ public void numberClassKeyMap() {
+ assertThat(multibindingComponent.numberClassKeyMap())
+ .isEqualTo(
+ ImmutableMap.of(
+ BigDecimal.class, "bigdecimal",
+ BigInteger.class, "biginteger"));
+ }
+
+ @Test
+ public void intKeyMap() {
+ assertThat(multibindingComponent.integerKeyMap()).isEqualTo(ImmutableMap.of(100, "100 int"));
+ }
+
+ @Test
+ public void longKeyMap() {
+ assertThat(multibindingComponent.longKeyMap())
+ .isEqualTo(ImmutableMap.of((long) 100, "100 long"));
+ }
+
+ @Test
+ public void shortKeyMap() {
+ assertThat(multibindingComponent.shortKeyMap())
+ .isEqualTo(ImmutableMap.of((short) 100, "100 short"));
+ }
+
+ @Test public void setBindings() {
+ assertThat(multibindingComponent.set()).containsExactly(-90, -17, -1, 5, 6, 832, 1742);
+ }
+
+ @Test public void complexQualifierSet() {
+ assertThat(multibindingComponent.complexQualifierStringSet()).containsExactly("foo");
+ }
+
+ @AutoAnnotation
+ static StringKey testStringKey(String value) {
+ return new AutoAnnotation_MultibindingTest_testStringKey(value);
+ }
+
+ @AutoAnnotation
+ static NestedAnnotationContainer.NestedWrappedKey nestedWrappedKey(Class<?> value) {
+ return new AutoAnnotation_MultibindingTest_nestedWrappedKey(value);
+ }
+
+ @AutoAnnotation
+ static WrappedAnnotationKey testWrappedAnnotationKey(
+ StringKey value, int[] integers, ClassKey[] annotations, Class<? extends Number>[] classes) {
+ return new AutoAnnotation_MultibindingTest_testWrappedAnnotationKey(
+ value, integers, annotations, classes);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/NestedTest.java b/compiler/src/it/functional-tests/src/test/java/test/NestedTest.java
new file mode 100644
index 000000000..14c3e5385
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/NestedTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class NestedTest {
+ @Test public void nestedFoo() {
+ OuterClassFoo.NestedComponent nestedFoo = DaggerOuterClassFoo_NestedComponent.create();
+ assertThat(nestedFoo.thing()).isNotNull();
+ }
+
+ @Test public void nestedBar() {
+ OuterClassBar.NestedComponent nestedBar = DaggerOuterClassBar_NestedComponent.create();
+ assertThat(nestedBar.injectedThing()).isNotNull();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/NonComponentDependencyTest.java b/compiler/src/it/functional-tests/src/test/java/test/NonComponentDependencyTest.java
new file mode 100644
index 000000000..37d3f7aec
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/NonComponentDependencyTest.java
@@ -0,0 +1,34 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class NonComponentDependencyTest {
+ @Test public void testThing() {
+ NonComponentDependencyComponent component =
+ DaggerNonComponentDependencyComponent.builder()
+ .thingComponent(new NonComponentDependencyComponent.ThingComponentImpl())
+ .build();
+ assertThat(component).isNotNull();
+ assertThat(component.thingTwo()).isNotNull();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/builder/BuilderTest.java b/compiler/src/it/functional-tests/src/test/java/test/builder/BuilderTest.java
new file mode 100644
index 000000000..ba590d2d9
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/builder/BuilderTest.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.builder;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+@RunWith(JUnit4.class)
+public class BuilderTest {
+
+ @Test public void interfaceBuilder() {
+ TestComponentWithBuilderInterface.Builder builder =
+ DaggerTestComponentWithBuilderInterface.builder();
+
+ // Make sure things fail if we don't set our required modules.
+ try {
+ builder.build();
+ fail();
+ } catch(IllegalStateException expected) {}
+
+ builder.intModule(new IntModuleIncludingDoubleAndFloat(1))
+ .stringModule(new StringModule("sam"))
+ .depComponent(new DepComponent() {});
+ builder.doubleModule(new DoubleModule());
+ // Don't set other modules -- make sure it works.
+
+ TestComponentWithBuilderInterface component = builder.build();
+ assertThat(component.s()).isEqualTo("sam");
+ assertThat(component.i()).isEqualTo(1);
+ assertThat(component.d()).isWithin(0).of(4.2d);
+ assertThat(component.f()).isEqualTo(5.5f);
+ assertThat(component.l()).isEqualTo(6L);
+ }
+
+ @Test public void abstractClassBuilder() {
+ TestComponentWithBuilderAbstractClass.Builder builder =
+ TestComponentWithBuilderAbstractClass.builder();
+
+ // Make sure things fail if we don't set our required modules.
+ try {
+ builder.build();
+ fail();
+ } catch(IllegalStateException expected) {}
+
+ builder.intModule(new IntModuleIncludingDoubleAndFloat(1))
+ .stringModule(new StringModule("sam"))
+ .depComponent(new DepComponent() {});
+ builder.doubleModule(new DoubleModule());
+ // Don't set other modules -- make sure it works.
+
+ TestComponentWithBuilderAbstractClass component = builder.build();
+ assertThat(component.s()).isEqualTo("sam");
+ assertThat(component.i()).isEqualTo(1);
+ assertThat(component.d()).isWithin(0).of(4.2d);
+ assertThat(component.f()).isEqualTo(5.5f);
+ assertThat(component.l()).isEqualTo(6L);
+ }
+
+ @Test public void interfaceGenericBuilder() {
+ TestComponentWithGenericBuilderInterface.Builder builder =
+ DaggerTestComponentWithGenericBuilderInterface.builder();
+
+ // Make sure things fail if we don't set our required modules.
+ try {
+ builder.build();
+ fail();
+ } catch(IllegalStateException expected) {}
+
+ builder.setM2(new IntModuleIncludingDoubleAndFloat(1))
+ .setM1(new StringModule("sam"))
+ .depComponent(new DepComponent() {});
+ builder.doubleModule(new DoubleModule());
+ // Don't set other modules -- make sure it works.
+
+ TestComponentWithGenericBuilderInterface component = builder.build();
+ assertThat(component.s()).isEqualTo("sam");
+ assertThat(component.i()).isEqualTo(1);
+ assertThat(component.d()).isWithin(0).of(4.2d);
+ assertThat(component.f()).isEqualTo(5.5f);
+ assertThat(component.l()).isEqualTo(6L);
+ }
+
+ @Test public void abstractClassGenericBuilder() {
+ TestComponentWithGenericBuilderAbstractClass.Builder builder =
+ DaggerTestComponentWithGenericBuilderAbstractClass.builder();
+
+ // Make sure things fail if we don't set our required modules.
+ try {
+ builder.build();
+ fail();
+ } catch(IllegalStateException expected) {}
+
+ builder.setM2(new IntModuleIncludingDoubleAndFloat(1))
+ .setM1(new StringModule("sam"))
+ .depComponent(new DepComponent() {});
+ builder.doubleModule(new DoubleModule());
+ // Don't set other modules -- make sure it works.
+
+ TestComponentWithGenericBuilderAbstractClass component = builder.build();
+ assertThat(component.s()).isEqualTo("sam");
+ assertThat(component.i()).isEqualTo(1);
+ assertThat(component.d()).isWithin(0).of(4.2d);
+ assertThat(component.f()).isEqualTo(5.5f);
+ assertThat(component.l()).isEqualTo(6L);
+ }
+
+ @Test public void subcomponents_interface() {
+ ParentComponent parent = DaggerParentComponent.create();
+ TestChildComponentWithBuilderInterface.Builder builder1 = parent.childInterfaceBuilder();
+ try {
+ builder1.build();
+ fail();
+ } catch(IllegalStateException expected) {}
+
+ builder1.setM2(new IntModuleIncludingDoubleAndFloat(1))
+ .setM1(new StringModule("sam"))
+ .set(new ByteModule((byte)7));
+ builder1.set(new FloatModule());
+ TestChildComponentWithBuilderInterface child1 = builder1.build();
+ assertThat(child1.s()).isEqualTo("sam");
+ assertThat(child1.i()).isEqualTo(1);
+ assertThat(child1.d()).isWithin(0).of(4.2d);
+ assertThat(child1.f()).isEqualTo(5.5f);
+ assertThat(child1.l()).isEqualTo(6L);
+ assertThat(child1.b()).isEqualTo((byte)7);
+ }
+
+ @Test public void subcomponents_abstractclass() {
+ ParentComponent parent = DaggerParentComponent.create();
+ TestChildComponentWithBuilderAbstractClass.Builder builder2 =
+ parent.childAbstractClassBuilder();
+ try {
+ builder2.build();
+ fail();
+ } catch(IllegalStateException expected) {}
+
+ builder2.setM2(new IntModuleIncludingDoubleAndFloat(10))
+ .setM1(new StringModule("tara"))
+ .set(new ByteModule((byte)70));
+ builder2.set(new FloatModule());
+ TestChildComponentWithBuilderAbstractClass child2 = builder2.build();
+ assertThat(child2.s()).isEqualTo("tara");
+ assertThat(child2.i()).isEqualTo(10);
+ assertThat(child2.d()).isWithin(0).of(4.2d);
+ assertThat(child2.f()).isEqualTo(5.5f);
+ assertThat(child2.l()).isEqualTo(6L);
+ assertThat(child2.b()).isEqualTo((byte)70);
+ }
+
+ @Test
+ public void grandchildren() {
+ ParentComponent parent = DaggerParentComponent.create();
+ MiddleChild middle1 = parent.middleBuilder().set(new StringModule("sam")).build();
+ Grandchild grandchild1 =
+ middle1.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(21)).build();
+ Grandchild grandchild2 =
+ middle1.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(22)).build();
+
+ assertThat(middle1.s()).isEqualTo("sam");
+ assertThat(grandchild1.i()).isEqualTo(21);
+ assertThat(grandchild1.s()).isEqualTo("sam");
+ assertThat(grandchild2.i()).isEqualTo(22);
+ assertThat(grandchild2.s()).isEqualTo("sam");
+
+ // Make sure grandchildren from newer children have no relation to the older ones.
+ MiddleChild middle2 = parent.middleBuilder().set(new StringModule("tara")).build();
+ Grandchild grandchild3 =
+ middle2.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(23)).build();
+ Grandchild grandchild4 =
+ middle2.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(24)).build();
+
+ assertThat(middle2.s()).isEqualTo("tara");
+ assertThat(grandchild3.i()).isEqualTo(23);
+ assertThat(grandchild3.s()).isEqualTo("tara");
+ assertThat(grandchild4.i()).isEqualTo(24);
+ assertThat(grandchild4.s()).isEqualTo("tara");
+ }
+
+ @Test
+ public void diamondGrandchildren() {
+ ParentComponent parent = DaggerParentComponent.create();
+ MiddleChild middle = parent.middleBuilder().set(new StringModule("sam")).build();
+ OtherMiddleChild other = parent.otherBuilder().set(new StringModule("tara")).build();
+
+ Grandchild middlegrand =
+ middle.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(21)).build();
+ Grandchild othergrand =
+ other.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(22)).build();
+
+ assertThat(middle.s()).isEqualTo("sam");
+ assertThat(other.s()).isEqualTo("tara");
+ assertThat(middlegrand.s()).isEqualTo("sam");
+ assertThat(othergrand.s()).isEqualTo("tara");
+ assertThat(middlegrand.i()).isEqualTo(21);
+ assertThat(othergrand.i()).isEqualTo(22);
+ }
+
+ @Test
+ public void genericSubcomponentMethod() {
+ ParentOfGenericComponent parent =
+ DaggerParentOfGenericComponent.builder().stringModule(new StringModule("sam")).build();
+ Grandchild.Builder builder = parent.subcomponentBuilder();
+ Grandchild child = builder.set(new IntModuleIncludingDoubleAndFloat(21)).build();
+ assertThat(child.s()).isEqualTo("sam");
+ assertThat(child.i()).isEqualTo(21);
+ }
+
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/cycle/CycleTest.java b/compiler/src/it/functional-tests/src/test/java/test/cycle/CycleTest.java
new file mode 100644
index 000000000..d3bc2cbad
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/cycle/CycleTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.cycle;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import test.cycle.Cycles.A;
+import test.cycle.Cycles.C;
+import test.cycle.Cycles.ChildCycleComponent;
+import test.cycle.Cycles.CycleComponent;
+import test.cycle.Cycles.CycleMapComponent;
+import test.cycle.Cycles.S;
+import test.cycle.Cycles.SelfCycleComponent;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class CycleTest {
+ @Test
+ public void providerIndirectionSelfCycle() {
+ SelfCycleComponent selfCycleComponent = DaggerCycles_SelfCycleComponent.create();
+ S s = selfCycleComponent.s();
+ assertThat(s.sProvider.get()).isNotNull();
+ }
+
+ @Test
+ public void providerIndirectionCycle() {
+ CycleComponent cycleComponent = DaggerCycles_CycleComponent.create();
+ A a = cycleComponent.a();
+ C c = cycleComponent.c();
+ assertThat(c.aProvider.get()).isNotNull();
+ assertThat(a.b.c.aProvider.get()).isNotNull();
+ assertThat(a.e.d.b.c.aProvider.get()).isNotNull();
+ }
+
+ @Test
+ public void lazyIndirectionSelfCycle() {
+ SelfCycleComponent selfCycleComponent = DaggerCycles_SelfCycleComponent.create();
+ S s = selfCycleComponent.s();
+ assertThat(s.sLazy.get()).isNotNull();
+ }
+
+ @Test
+ public void lazyIndirectionCycle() {
+ CycleComponent cycleComponent = DaggerCycles_CycleComponent.create();
+ A a = cycleComponent.a();
+ C c = cycleComponent.c();
+ assertThat(c.aLazy.get()).isNotNull();
+ assertThat(a.b.c.aLazy.get()).isNotNull();
+ assertThat(a.e.d.b.c.aLazy.get()).isNotNull();
+ }
+
+ @Test
+ public void subcomponentIndirectionCycle() {
+ ChildCycleComponent childCycleComponent = DaggerCycles_CycleComponent.create().child();
+ A a = childCycleComponent.a();
+ assertThat(a.b.c.aProvider.get()).isNotNull();
+ assertThat(a.e.d.b.c.aProvider.get()).isNotNull();
+ }
+
+ @Test
+ public void providerMapIndirectionCycle() {
+ CycleMapComponent cycleMapComponent = DaggerCycles_CycleMapComponent.create();
+ assertThat(cycleMapComponent.y()).isNotNull();
+ assertThat(cycleMapComponent.y().mapOfProvidersOfX).containsKey("X");
+ assertThat(cycleMapComponent.y().mapOfProvidersOfX.get("X")).isNotNull();
+ assertThat(cycleMapComponent.y().mapOfProvidersOfX.get("X").get()).isNotNull();
+ assertThat(cycleMapComponent.y().mapOfProvidersOfX.get("X").get().y).isNotNull();
+ assertThat(cycleMapComponent.y().mapOfProvidersOfX).hasSize(1);
+ assertThat(cycleMapComponent.y().mapOfProvidersOfY).containsKey("Y");
+ assertThat(cycleMapComponent.y().mapOfProvidersOfY.get("Y")).isNotNull();
+ assertThat(cycleMapComponent.y().mapOfProvidersOfY.get("Y").get()).isNotNull();
+ assertThat(cycleMapComponent.y().mapOfProvidersOfY.get("Y").get().mapOfProvidersOfX).hasSize(1);
+ assertThat(cycleMapComponent.y().mapOfProvidersOfY.get("Y").get().mapOfProvidersOfY).hasSize(1);
+ assertThat(cycleMapComponent.y().mapOfProvidersOfY).hasSize(1);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/cycle/LongCycleTest.java b/compiler/src/it/functional-tests/src/test/java/test/cycle/LongCycleTest.java
new file mode 100644
index 000000000..e50eaee69
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/cycle/LongCycleTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.cycle;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import test.cycle.LongCycle.LongCycleComponent;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class LongCycleTest {
+
+ /**
+ * Tests a cycle long enough that the real factory is created in a separate initialize method from
+ * the delegate factory.
+ */
+ @Test
+ public void longCycle() {
+ LongCycleComponent longCycleComponent = DaggerLongCycle_LongCycleComponent.create();
+ assertThat(longCycleComponent.class1()).isNotNull();
+ }
+
+ /**
+ * Fails if {@link LongCycleComponent} doesn't have a long enough cycle to make sure the real
+ * factory is created in a separate method from the delegate factory.
+ */
+ @Test
+ public void longCycleHasMoreThanOneInitializeMethod() throws NoSuchMethodException {
+ DaggerLongCycle_LongCycleComponent.class
+ .getDeclaredMethod("initialize1", DaggerLongCycle_LongCycleComponent.Builder.class);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/membersinject/MembersInjectTest.java b/compiler/src/it/functional-tests/src/test/java/test/membersinject/MembersInjectTest.java
new file mode 100644
index 000000000..411ecb177
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/membersinject/MembersInjectTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.membersinject;
+
+import dagger.MembersInjector;
+import javax.inject.Provider;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import test.multipackage.DaggerMembersInjectionVisibilityComponent;
+import test.multipackage.MembersInjectionVisibilityComponent;
+import test.multipackage.a.AGrandchild;
+import test.multipackage.a.AParent;
+import test.multipackage.b.BChild;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class MembersInjectTest {
+ @Test public void testMembersInject_arrays() {
+ MembersInjectComponent component = DaggerMembersInjectComponent.builder().build();
+
+ ChildOfStringArray childOfStringArray = new ChildOfStringArray();
+ component.inject(childOfStringArray);
+ }
+
+ @Test public void testMembersInject_nestedArrays() {
+ MembersInjectComponent component = DaggerMembersInjectComponent.builder().build();
+
+ ChildOfArrayOfParentOfStringArray childOfArrayOfParentOfStringArray =
+ new ChildOfArrayOfParentOfStringArray();
+ component.inject(childOfArrayOfParentOfStringArray);
+ }
+
+ @Test public void testMembersInject_primitives() {
+ MembersInjectComponent component = DaggerMembersInjectComponent.builder().build();
+
+ ChildOfPrimitiveIntArray childOfPrimitiveIntArray = new ChildOfPrimitiveIntArray();
+ component.inject(childOfPrimitiveIntArray);
+ }
+
+ @Test
+ public void testMembersInject_overrides() {
+ MembersInjectionVisibilityComponent component =
+ DaggerMembersInjectionVisibilityComponent.create();
+ AParent aParent = new AParent();
+ component.inject(aParent);
+ assertThat(aParent.aParentField()).isNotNull();
+ assertThat(aParent.aParentMethod()).isNotNull();
+
+ BChild aChild = new BChild();
+ component.inject(aChild);
+ assertThat(aChild.aParentField()).isNotNull();
+ assertThat(aChild.aParentMethod()).isNull();
+ assertThat(aChild.aChildField()).isNotNull();
+ assertThat(aChild.aChildMethod()).isNotNull();
+
+ AGrandchild aGrandchild = new AGrandchild();
+ component.inject(aGrandchild);
+ assertThat(aGrandchild.aParentField()).isNotNull();
+ assertThat(aGrandchild.aParentMethod()).isNotNull();
+ assertThat(aGrandchild.aChildField()).isNotNull();
+ assertThat(aGrandchild.aChildMethod()).isNull();
+ assertThat(aGrandchild.aGrandchildField()).isNotNull();
+ assertThat(aGrandchild.aGrandchildMethod()).isNotNull();
+ }
+
+ @Test
+ public void testNonRequestedMembersInjector() {
+ NonRequestedChild child = new NonRequestedChild();
+ Provider<String> provider =
+ new Provider<String>() {
+ @Override
+ public String get() {
+ return "field!";
+ }
+ };
+ MembersInjector<NonRequestedChild> injector = new NonRequestedChild_MembersInjector(provider);
+ injector.injectMembers(child);
+ assertThat(child.t).isEqualTo("field!");
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/nullables/NullabilityTest.java b/compiler/src/it/functional-tests/src/test/java/test/nullables/NullabilityTest.java
new file mode 100644
index 000000000..a0e1e22f5
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/nullables/NullabilityTest.java
@@ -0,0 +1,110 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test.nullables;
+
+import javax.inject.Provider;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+@RunWith(JUnit4.class)
+public class NullabilityTest {
+ @Test public void testNullability_provides() {
+ NullModule module = new NullModule();
+ NullComponent component = DaggerNullComponent.builder().nullModule(module).build();
+
+ // Can't construct NullFoo because it depends on Number, and Number was null.
+ try {
+ component.nullFoo();
+ fail();
+ } catch (NullPointerException npe) {
+ assertThat(npe).hasMessage("Cannot return null from a non-@Nullable @Provides method");
+ }
+
+ // set number to non-null so we can create
+ module.numberValue = 1;
+ NullFoo nullFoo = component.nullFoo();
+
+ // Then set it back to null so we can test its providers.
+ module.numberValue = null;
+ validate(true, nullFoo.string, nullFoo.stringProvider, nullFoo.numberProvider);
+ validate(true, nullFoo.methodInjectedString, nullFoo.methodInjectedStringProvider,
+ nullFoo.methodInjectedNumberProvider);
+ validate(true, nullFoo.fieldInjectedString, nullFoo.fieldInjectedStringProvider,
+ nullFoo.fieldInjectedNumberProvider);
+ }
+
+ @Test public void testNullability_components() {
+ NullComponent nullComponent = new NullComponent() {
+ @Override public Provider<String> stringProvider() {
+ return new Provider<String>() {
+ @Override public String get() {
+ return null;
+ }
+ };
+ }
+
+ @Override public String string() {
+ return null;
+ }
+
+ @Override public Provider<Number> numberProvider() {
+ return new Provider<Number>() {
+ @Override public Number get() {
+ return null;
+ }
+ };
+ }
+
+ @Override public Number number() {
+ return null;
+ }
+
+ @Override public NullFoo nullFoo() {
+ return null;
+ }
+ };
+ NullComponentWithDependency component =
+ DaggerNullComponentWithDependency.builder().nullComponent(nullComponent).build();
+ validate(false, component.string(), component.stringProvider(), component.numberProvider());
+
+ // Also validate that the component's number() method fails
+ try {
+ component.number();
+ fail();
+ } catch (NullPointerException npe) {
+ assertThat(npe).hasMessage("Cannot return null from a non-@Nullable component method");
+ }
+ }
+
+ private void validate(boolean fromProvides,
+ String string,
+ Provider<String> stringProvider,
+ Provider<Number> numberProvider) {
+ assertThat(string).isNull();
+ assertThat(numberProvider).isNotNull();
+ try {
+ numberProvider.get();
+ fail();
+ } catch(NullPointerException npe) {
+ assertThat(npe).hasMessage("Cannot return null from a non-@Nullable "
+ + (fromProvides ? "@Provides" : "component") + " method");
+ }
+ assertThat(stringProvider.get()).isNull();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/staticprovides/StaticProvidesTest.java b/compiler/src/it/functional-tests/src/test/java/test/staticprovides/StaticProvidesTest.java
new file mode 100644
index 000000000..397259403
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/staticprovides/StaticProvidesTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.staticprovides;
+
+import com.google.common.collect.ImmutableSet;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+@RunWith(Parameterized.class)
+public class StaticProvidesTest {
+ @Parameters
+ public static Collection<Object[]> components() {
+ return Arrays.asList(new Object[][] {
+ {DaggerStaticTestComponent.create()},
+ {DaggerStaticTestComponentWithBuilder.builder().build()},
+ {DaggerStaticTestComponentWithBuilder.builder()
+ .allStaticModule(new AllStaticModule())
+ .someStaticModule(new SomeStaticModule())
+ .build()}});
+ }
+
+ @Parameter
+ public StaticTestComponent component;
+
+ @Test public void setMultibinding() {
+ assertThat(component.getMultiboundStrings()).isEqualTo(ImmutableSet.of(
+ AllStaticModule.class + ".contributeString",
+ SomeStaticModule.class + ".contributeStringFromAStaticMethod",
+ SomeStaticModule.class + ".contributeStringFromAnInstanceMethod"));
+ }
+
+ @Test public void allStaticProvidesModules_noFieldInComponentBuilder() {
+ for (Field field : DaggerStaticTestComponent.Builder.class.getDeclaredFields()) {
+ assertWithMessage(field.getName())
+ .that(field.getType()).isNotEqualTo(AllStaticModule.class);
+ }
+ }
+
+ @Test public void allStaticProvidesModules_deprecatedMethodInComponentBuilder() {
+ for (Method method : DaggerStaticTestComponent.Builder.class.getDeclaredMethods()) {
+ if (Arrays.asList(method.getParameterTypes()).contains(AllStaticModule.class)) {
+ assertWithMessage(method.getName())
+ .that(method.isAnnotationPresent(Deprecated.class))
+ .isTrue();
+ }
+ }
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentMultibindingsTest.java b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentMultibindingsTest.java
new file mode 100644
index 000000000..f57a77831
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentMultibindingsTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+@RunWith(Parameterized.class)
+public class SubcomponentMultibindingsTest {
+
+ @Parameters(name = "{0}")
+ public static Collection<Object[]> parameters() {
+ return ImmutableList.of(
+ new Object[] {DaggerParentComponentWithMultibindings.create()},
+ new Object[] {DaggerParentComponentWithoutMultibindings.create()});
+ }
+
+ private ParentComponentWithoutMultibindings parent;
+
+ public SubcomponentMultibindingsTest(ParentComponentWithoutMultibindings parentComponent) {
+ this.parent = parentComponent;
+ }
+
+ @Test
+ public void testMultibindingsInSubcomponents() {
+ RequiresMultibindingsInChild requiresMultibindingsInChild =
+ parent.childComponent().requiresMultibindingsInChild();
+
+ assertWithMessage("requiresMultiboundObjects.setOfObjects")
+ .that(requiresMultibindingsInChild.requiresMultiboundObjects().setOfObjects())
+ .containsExactly("object provided by parent", "object provided by child");
+
+ assertWithMessage("requiresMultiboundObjects.mapOfObjects")
+ .that(requiresMultibindingsInChild.requiresMultiboundObjects().mapOfObjects())
+ .isEqualTo(
+ ImmutableMap.of("parent key", "object in parent", "child key", "object in child"));
+
+ assertWithMessage("requiresMultiboundStrings")
+ .that(requiresMultibindingsInChild.requiresMultiboundStrings().setOfStrings())
+ .containsExactly("string provided by parent");
+
+ assertWithMessage("requiresMultiboundStrings.mapOfStrings")
+ .that(requiresMultibindingsInChild.requiresMultiboundStrings().mapOfStrings())
+ .isEqualTo(ImmutableMap.of("parent key", "string in parent"));
+ }
+
+ @Test
+ public void testOverriddenMultibindingsInSubcomponents() {
+ RequiresMultibindingsInChild requiresMultibindingsInChild =
+ parent.childComponent().requiresMultibindingsInChild();
+
+ assertWithMessage("setOfRequiresMultiboundObjects")
+ .that(requiresMultibindingsInChild.setOfRequiresMultiboundObjects())
+ .hasSize(1);
+
+ RequiresMultiboundObjects onlyElementInMultiboundRequiresMultiboundObjects =
+ getOnlyElement(requiresMultibindingsInChild.setOfRequiresMultiboundObjects());
+
+ assertWithMessage("setOfRequiresMultiboundObjects[only].setOfObjects")
+ .that(onlyElementInMultiboundRequiresMultiboundObjects.setOfObjects())
+ .containsExactly("object provided by parent", "object provided by child");
+
+ assertWithMessage("setOfRequiresMultiboundObjects[only].mapOfObjects")
+ .that(onlyElementInMultiboundRequiresMultiboundObjects.mapOfObjects())
+ .isEqualTo(
+ ImmutableMap.of("parent key", "object in parent", "child key", "object in child"));
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentTest.java b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentTest.java
new file mode 100644
index 000000000..cb6292513
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.google.common.collect.Sets.intersection;
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(Parameterized.class)
+public class SubcomponentTest {
+ private static final ParentComponent parentComponent = DaggerParentComponent.create();
+ private static final ParentOfGenericComponent parentOfGenericComponent =
+ DaggerParentOfGenericComponent.create();
+
+ @Parameters
+ public static Collection<Object[]> parameters() {
+ return Arrays.asList(new Object[][] {
+ { parentComponent, parentComponent.newChildComponent() },
+ { parentComponent, parentComponent.newChildAbstractClassComponent() },
+ { parentOfGenericComponent, parentOfGenericComponent.subcomponent() }});
+ }
+
+ private final ParentGetters parentGetters;
+ private final ChildComponent childComponent;
+
+ public SubcomponentTest(ParentGetters parentGetters, ChildComponent childComponent) {
+ this.parentGetters = parentGetters;
+ this.childComponent = childComponent;
+ }
+
+
+ @Test
+ public void scopePropagatesUpward_class() {
+ assertThat(childComponent.requiresSingleton().singletonType())
+ .isSameAs(childComponent.requiresSingleton().singletonType());
+ assertThat(childComponent.requiresSingleton().singletonType())
+ .isSameAs(childComponent.newGrandchildComponent().requiresSingleton().singletonType());
+ }
+
+ @Test
+ public void scopePropagatesUpward_provides() {
+ assertThat(childComponent
+ .requiresSingleton().unscopedTypeBoundAsSingleton())
+ .isSameAs(childComponent
+ .requiresSingleton().unscopedTypeBoundAsSingleton());
+ assertThat(childComponent
+ .requiresSingleton().unscopedTypeBoundAsSingleton())
+ .isSameAs(childComponent.newGrandchildComponent()
+ .requiresSingleton().unscopedTypeBoundAsSingleton());
+ }
+
+ @Test
+ public void multibindingContributions() {
+ Set<Object> parentObjectSet = parentGetters.objectSet();
+ assertThat(parentObjectSet).hasSize(2);
+ Set<Object> childObjectSet = childComponent.objectSet();
+ assertThat(childObjectSet).hasSize(3);
+ Set<Object> grandchildObjectSet =
+ childComponent.newGrandchildComponent().objectSet();
+ assertThat(grandchildObjectSet).hasSize(4);
+ assertThat(intersection(parentObjectSet, childObjectSet)).hasSize(1);
+ assertThat(intersection(parentObjectSet, grandchildObjectSet)).hasSize(1);
+ assertThat(intersection(childObjectSet, grandchildObjectSet)).hasSize(1);
+ }
+
+ @Test
+ public void unscopedProviders() {
+ assertThat(parentGetters.getUnscopedTypeProvider())
+ .isSameAs(childComponent.getUnscopedTypeProvider());
+ assertThat(parentGetters.getUnscopedTypeProvider())
+ .isSameAs(childComponent
+ .newGrandchildComponent()
+ .getUnscopedTypeProvider());
+ }
+
+ @Test
+ public void passedModules() {
+ ChildModuleWithState childModuleWithState = new ChildModuleWithState();
+ ChildComponentRequiringModules childComponent1 =
+ parentComponent.newChildComponentRequiringModules(
+ new ChildModuleWithParameters(new Object()),
+ childModuleWithState);
+ ChildComponentRequiringModules childComponent2 =
+ parentComponent.newChildComponentRequiringModules(
+ new ChildModuleWithParameters(new Object()),
+ childModuleWithState);
+ assertThat(childComponent1.getInt()).isEqualTo(0);
+ assertThat(childComponent2.getInt()).isEqualTo(1);
+ }
+
+ @Test
+ public void dependenceisInASubcomponent() {
+ assertThat(childComponent.newGrandchildComponent().needsAnInterface()).isNotNull();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/subcomponent/hiding/SubcomponentHidingTest.java b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/hiding/SubcomponentHidingTest.java
new file mode 100644
index 000000000..27dcbb690
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/hiding/SubcomponentHidingTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent.hiding;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class SubcomponentHidingTest {
+ @Test public void moduleNameHiding() {
+ ParentComponent parent = DaggerParentComponent.create();
+ assertThat(parent.aCommonName().toString()).isEqualTo("a");
+ assertThat(parent.newChildComponent().aCommonName().toString()).isEqualTo("a");
+ assertThat(parent.newChildComponent().bCommonName().toString()).isEqualTo("1");
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/subcomponent/repeat/RepeatedModuleTest.java b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/repeat/RepeatedModuleTest.java
new file mode 100644
index 000000000..7e92371bf
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/repeat/RepeatedModuleTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.subcomponent.repeat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+@RunWith(JUnit4.class)
+public final class RepeatedModuleTest {
+ private ParentComponent parentComponent;
+
+ @Before
+ public void initializeParentComponent() {
+ this.parentComponent = DaggerParentComponent.builder().build();
+ }
+
+ @Test
+ public void repeatedModuleHasSameStateInSubcomponent() {
+ SubcomponentWithRepeatedModule childComponent =
+ parentComponent.newChildComponentBuilder().build();
+ assertThat(parentComponent.state()).isSameAs(childComponent.state());
+ }
+
+ @Test
+ public void repeatedModuleHasSameStateInGrandchildSubcomponent() {
+ SubcomponentWithoutRepeatedModule childComponent =
+ parentComponent.newChildComponentWithoutRepeatedModule();
+ SubcomponentWithRepeatedModule grandchildComponent =
+ childComponent.newGrandchildBuilder().build();
+ assertThat(parentComponent.state()).isSameAs(grandchildComponent.state());
+ }
+
+ @Test
+ public void repeatedModuleBuilderThrowsInSubcomponent() {
+ SubcomponentWithRepeatedModule.Builder childComponentBuilder =
+ parentComponent.newChildComponentBuilder();
+ try {
+ childComponentBuilder.repeatedModule(new RepeatedModule());
+ fail();
+ } catch (UnsupportedOperationException expected) {
+ assertThat(expected)
+ .hasMessage(
+ "test.subcomponent.repeat.RepeatedModule cannot be set "
+ + "because it is inherited from the enclosing component");
+ }
+ }
+
+ @Test
+ public void repeatedModuleBuilderThrowsInGrandchildSubcomponent() {
+ SubcomponentWithoutRepeatedModule childComponent =
+ parentComponent.newChildComponentWithoutRepeatedModule();
+ SubcomponentWithRepeatedModule.Builder grandchildComponentBuilder =
+ childComponent.newGrandchildBuilder();
+ try {
+ grandchildComponentBuilder.repeatedModule(new RepeatedModule());
+ fail();
+ } catch (UnsupportedOperationException expected) {
+ assertThat(expected)
+ .hasMessage(
+ "test.subcomponent.repeat.RepeatedModule cannot be set "
+ + "because it is inherited from the enclosing component");
+ }
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/tck/TckTest.java b/compiler/src/it/functional-tests/src/test/java/test/tck/TckTest.java
new file mode 100644
index 000000000..d79b06b6a
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/tck/TckTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test.tck;
+
+import junit.framework.Test;
+import org.atinject.tck.Tck;
+import org.atinject.tck.auto.Car;
+import org.atinject.tck.auto.Convertible;
+
+/**
+ * Test suite to execute the JSR-330 TCK in JUnit.
+ */
+public class TckTest {
+ public static Test suite() {
+ CarShop carShopComponent = DaggerCarShop.create();
+ Car car = carShopComponent.make();
+ Convertible.localConvertible.set((Convertible) car);
+ return Tck.testsFor(car, false, false);
+ }
+}
diff --git a/compiler/src/it/functional-tests/target/classes/test/A.class b/compiler/src/it/functional-tests/target/classes/test/A.class
new file mode 100644
index 000000000..5b0f08afd
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/A.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/A_Factory.class b/compiler/src/it/functional-tests/target/classes/test/A_Factory.class
new file mode 100644
index 000000000..7252360f9
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/A_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/AbstractMembersInjectingBaseClass.class b/compiler/src/it/functional-tests/target/classes/test/AbstractMembersInjectingBaseClass.class
new file mode 100644
index 000000000..5d256bc1c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/AbstractMembersInjectingBaseClass.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/AbstractMembersInjectingBaseClass_MembersInjector.class b/compiler/src/it/functional-tests/target/classes/test/AbstractMembersInjectingBaseClass_MembersInjector.class
new file mode 100644
index 000000000..951d719e5
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/AbstractMembersInjectingBaseClass_MembersInjector.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/AbstractMiddleClassWithoutMembers.class b/compiler/src/it/functional-tests/target/classes/test/AbstractMiddleClassWithoutMembers.class
new file mode 100644
index 000000000..481151778
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/AbstractMiddleClassWithoutMembers.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestStringKey$NestedWrappedKeyCreator_createNestedWrappedKey.class b/compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestStringKey$NestedWrappedKeyCreator_createNestedWrappedKey.class
new file mode 100644
index 000000000..e64da63d3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestStringKey$NestedWrappedKeyCreator_createNestedWrappedKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestUnwrappedAnnotationKeyCreator_createTestStringKey.class b/compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestUnwrappedAnnotationKeyCreator_createTestStringKey.class
new file mode 100644
index 000000000..81a137fc3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestUnwrappedAnnotationKeyCreator_createTestStringKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestStringKey.class b/compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestStringKey.class
new file mode 100644
index 000000000..21de57ba7
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestStringKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey.class b/compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey.class
new file mode 100644
index 000000000..295d9e2ec
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/B.class b/compiler/src/it/functional-tests/target/classes/test/B.class
new file mode 100644
index 000000000..a8f05ad34
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/B.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/B_Factory.class b/compiler/src/it/functional-tests/target/classes/test/B_Factory.class
new file mode 100644
index 000000000..1e7e7974f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/B_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/BasicAbstractClassComponent.class b/compiler/src/it/functional-tests/target/classes/test/BasicAbstractClassComponent.class
new file mode 100644
index 000000000..f8487e3ae
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/BasicAbstractClassComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/BasicComponent.class b/compiler/src/it/functional-tests/target/classes/test/BasicComponent.class
new file mode 100644
index 000000000..034057b14
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/BasicComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/BoundedGenericComponent.class b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericComponent.class
new file mode 100644
index 000000000..29c895e5a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule.class b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule.class
new file mode 100644
index 000000000..55df97392
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideArrayListOfComparableStringFactory.class b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideArrayListOfComparableStringFactory.class
new file mode 100644
index 000000000..78d93e115
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideArrayListOfComparableStringFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideArrayListStringFactory.class b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideArrayListStringFactory.class
new file mode 100644
index 000000000..b3fd3f7c4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideArrayListStringFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideDoubleFactory.class b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideDoubleFactory.class
new file mode 100644
index 000000000..22b6f3667
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideDoubleFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideIntegerFactory.class b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideIntegerFactory.class
new file mode 100644
index 000000000..85c626bee
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideIntegerFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideLinkedListCharSeqFactory.class b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideLinkedListCharSeqFactory.class
new file mode 100644
index 000000000..8a8fb9bd9
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideLinkedListCharSeqFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideLinkedListStringFactory.class b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideLinkedListStringFactory.class
new file mode 100644
index 000000000..49ee8dc92
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideLinkedListStringFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideListOfIntegerFactory.class b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideListOfIntegerFactory.class
new file mode 100644
index 000000000..1262b1a0b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideListOfIntegerFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideSetOfDoubleFactory.class b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideSetOfDoubleFactory.class
new file mode 100644
index 000000000..8dfa9f37b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/BoundedGenericModule_ProvideSetOfDoubleFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/BoundedGenerics.class b/compiler/src/it/functional-tests/target/classes/test/BoundedGenerics.class
new file mode 100644
index 000000000..727d42b04
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/BoundedGenerics.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/BoundedGenerics_Factory.class b/compiler/src/it/functional-tests/target/classes/test/BoundedGenerics_Factory.class
new file mode 100644
index 000000000..ee50c4137
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/BoundedGenerics_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/ChildDoubleModule.class b/compiler/src/it/functional-tests/target/classes/test/ChildDoubleModule.class
new file mode 100644
index 000000000..990bb389e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/ChildDoubleModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/ChildDoubleModule_ProvideDoubleFactory.class b/compiler/src/it/functional-tests/target/classes/test/ChildDoubleModule_ProvideDoubleFactory.class
new file mode 100644
index 000000000..7c6c0f882
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/ChildDoubleModule_ProvideDoubleFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/ChildDoubleModule_ProvideListOfDoubleFactory.class b/compiler/src/it/functional-tests/target/classes/test/ChildDoubleModule_ProvideListOfDoubleFactory.class
new file mode 100644
index 000000000..ba4d2324a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/ChildDoubleModule_ProvideListOfDoubleFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/ChildIntegerModule.class b/compiler/src/it/functional-tests/target/classes/test/ChildIntegerModule.class
new file mode 100644
index 000000000..bfd9c3686
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/ChildIntegerModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/ChildIntegerModule_ProvideIntegerFactory.class b/compiler/src/it/functional-tests/target/classes/test/ChildIntegerModule_ProvideIntegerFactory.class
new file mode 100644
index 000000000..4d9791b0f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/ChildIntegerModule_ProvideIntegerFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/ChildIntegerModule_ProvideListOfIntegerFactory.class b/compiler/src/it/functional-tests/target/classes/test/ChildIntegerModule_ProvideListOfIntegerFactory.class
new file mode 100644
index 000000000..cf4785f1f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/ChildIntegerModule_ProvideListOfIntegerFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/ComplexGenerics.class b/compiler/src/it/functional-tests/target/classes/test/ComplexGenerics.class
new file mode 100644
index 000000000..ca5cc7e2a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/ComplexGenerics.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/ComplexGenerics_Factory.class b/compiler/src/it/functional-tests/target/classes/test/ComplexGenerics_Factory.class
new file mode 100644
index 000000000..bab5eb4bc
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/ComplexGenerics_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/ComponentDependsOnGeneratedCode.class b/compiler/src/it/functional-tests/target/classes/test/ComponentDependsOnGeneratedCode.class
new file mode 100644
index 000000000..0baa3d016
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/ComponentDependsOnGeneratedCode.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerBasicAbstractClassComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/DaggerBasicAbstractClassComponent$1.class
new file mode 100644
index 000000000..11913f2fa
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerBasicAbstractClassComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerBasicAbstractClassComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/DaggerBasicAbstractClassComponent$Builder.class
new file mode 100644
index 000000000..1c014f15c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerBasicAbstractClassComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerBasicAbstractClassComponent.class b/compiler/src/it/functional-tests/target/classes/test/DaggerBasicAbstractClassComponent.class
new file mode 100644
index 000000000..832bb9103
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerBasicAbstractClassComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerBasicComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/DaggerBasicComponent$1.class
new file mode 100644
index 000000000..30c29a475
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerBasicComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerBasicComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/DaggerBasicComponent$Builder.class
new file mode 100644
index 000000000..9b51bb9f9
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerBasicComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerBasicComponent.class b/compiler/src/it/functional-tests/target/classes/test/DaggerBasicComponent.class
new file mode 100644
index 000000000..2d8060bdd
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerBasicComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerBoundedGenericComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/DaggerBoundedGenericComponent$1.class
new file mode 100644
index 000000000..bd2e5abad
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerBoundedGenericComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerBoundedGenericComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/DaggerBoundedGenericComponent$Builder.class
new file mode 100644
index 000000000..443a01e69
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerBoundedGenericComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerBoundedGenericComponent.class b/compiler/src/it/functional-tests/target/classes/test/DaggerBoundedGenericComponent.class
new file mode 100644
index 000000000..2a31cacc4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerBoundedGenericComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerComponentDependsOnGeneratedCode$1.class b/compiler/src/it/functional-tests/target/classes/test/DaggerComponentDependsOnGeneratedCode$1.class
new file mode 100644
index 000000000..fd47fd2e1
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerComponentDependsOnGeneratedCode$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerComponentDependsOnGeneratedCode$Builder.class b/compiler/src/it/functional-tests/target/classes/test/DaggerComponentDependsOnGeneratedCode$Builder.class
new file mode 100644
index 000000000..3f139958b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerComponentDependsOnGeneratedCode$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerComponentDependsOnGeneratedCode.class b/compiler/src/it/functional-tests/target/classes/test/DaggerComponentDependsOnGeneratedCode.class
new file mode 100644
index 000000000..d97c40196
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerComponentDependsOnGeneratedCode.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerGenericComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/DaggerGenericComponent$1.class
new file mode 100644
index 000000000..d6bacc444
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerGenericComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerGenericComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/DaggerGenericComponent$Builder.class
new file mode 100644
index 000000000..3702f1acd
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerGenericComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerGenericComponent.class b/compiler/src/it/functional-tests/target/classes/test/DaggerGenericComponent.class
new file mode 100644
index 000000000..db28d8e1e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerGenericComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerMultibindingComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/DaggerMultibindingComponent$1.class
new file mode 100644
index 000000000..e3b23fd47
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerMultibindingComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerMultibindingComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/DaggerMultibindingComponent$Builder.class
new file mode 100644
index 000000000..a771169d0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerMultibindingComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerMultibindingComponent.class b/compiler/src/it/functional-tests/target/classes/test/DaggerMultibindingComponent.class
new file mode 100644
index 000000000..2db66f42f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerMultibindingComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerNonComponentDependencyComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/DaggerNonComponentDependencyComponent$1.class
new file mode 100644
index 000000000..24b088959
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerNonComponentDependencyComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerNonComponentDependencyComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/DaggerNonComponentDependencyComponent$Builder.class
new file mode 100644
index 000000000..baa205f34
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerNonComponentDependencyComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerNonComponentDependencyComponent.class b/compiler/src/it/functional-tests/target/classes/test/DaggerNonComponentDependencyComponent.class
new file mode 100644
index 000000000..9036479f1
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerNonComponentDependencyComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassBar_NestedComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassBar_NestedComponent$1.class
new file mode 100644
index 000000000..d2f173c06
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassBar_NestedComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassBar_NestedComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassBar_NestedComponent$Builder.class
new file mode 100644
index 000000000..9a70a92cf
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassBar_NestedComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassBar_NestedComponent.class b/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassBar_NestedComponent.class
new file mode 100644
index 000000000..e78c1f7f0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassBar_NestedComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassFoo_NestedComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassFoo_NestedComponent$1.class
new file mode 100644
index 000000000..7d3a20fd1
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassFoo_NestedComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassFoo_NestedComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassFoo_NestedComponent$Builder.class
new file mode 100644
index 000000000..1ce5ec3bb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassFoo_NestedComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassFoo_NestedComponent.class b/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassFoo_NestedComponent.class
new file mode 100644
index 000000000..9066f6e4a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerOuterClassFoo_NestedComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerSingletonGenericComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/DaggerSingletonGenericComponent$1.class
new file mode 100644
index 000000000..2847d0164
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerSingletonGenericComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerSingletonGenericComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/DaggerSingletonGenericComponent$Builder.class
new file mode 100644
index 000000000..2db3bca06
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerSingletonGenericComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/DaggerSingletonGenericComponent.class b/compiler/src/it/functional-tests/target/classes/test/DaggerSingletonGenericComponent.class
new file mode 100644
index 000000000..f9aea2c80
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/DaggerSingletonGenericComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/Generic.class b/compiler/src/it/functional-tests/target/classes/test/Generic.class
new file mode 100644
index 000000000..74c6a2dfe
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/Generic.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/Generic2.class b/compiler/src/it/functional-tests/target/classes/test/Generic2.class
new file mode 100644
index 000000000..70d0c4d16
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/Generic2.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/Generic2_Factory.class b/compiler/src/it/functional-tests/target/classes/test/Generic2_Factory.class
new file mode 100644
index 000000000..5a80da9d2
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/Generic2_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/GenericChild.class b/compiler/src/it/functional-tests/target/classes/test/GenericChild.class
new file mode 100644
index 000000000..3636e1a5d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/GenericChild.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/GenericChild_Factory.class b/compiler/src/it/functional-tests/target/classes/test/GenericChild_Factory.class
new file mode 100644
index 000000000..05ac299e9
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/GenericChild_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/GenericChild_MembersInjector.class b/compiler/src/it/functional-tests/target/classes/test/GenericChild_MembersInjector.class
new file mode 100644
index 000000000..a43dd7f69
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/GenericChild_MembersInjector.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/GenericComponent.class b/compiler/src/it/functional-tests/target/classes/test/GenericComponent.class
new file mode 100644
index 000000000..2a8a12cdd
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/GenericComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/GenericDoubleReferences.class b/compiler/src/it/functional-tests/target/classes/test/GenericDoubleReferences.class
new file mode 100644
index 000000000..9d7383d4e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/GenericDoubleReferences.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/GenericDoubleReferences_Factory.class b/compiler/src/it/functional-tests/target/classes/test/GenericDoubleReferences_Factory.class
new file mode 100644
index 000000000..5288a1909
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/GenericDoubleReferences_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/GenericNoDeps.class b/compiler/src/it/functional-tests/target/classes/test/GenericNoDeps.class
new file mode 100644
index 000000000..20a8b789c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/GenericNoDeps.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/GenericNoDeps_Factory.class b/compiler/src/it/functional-tests/target/classes/test/GenericNoDeps_Factory.class
new file mode 100644
index 000000000..69535787c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/GenericNoDeps_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/GenericParent.class b/compiler/src/it/functional-tests/target/classes/test/GenericParent.class
new file mode 100644
index 000000000..00e5caf91
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/GenericParent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/GenericParent_Factory.class b/compiler/src/it/functional-tests/target/classes/test/GenericParent_Factory.class
new file mode 100644
index 000000000..0ad7a27b0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/GenericParent_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/GenericParent_MembersInjector.class b/compiler/src/it/functional-tests/target/classes/test/GenericParent_MembersInjector.class
new file mode 100644
index 000000000..ed217cc85
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/GenericParent_MembersInjector.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/Generic_Factory.class b/compiler/src/it/functional-tests/target/classes/test/Generic_Factory.class
new file mode 100644
index 000000000..c01a7ff40
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/Generic_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/InjectedThing.class b/compiler/src/it/functional-tests/target/classes/test/InjectedThing.class
new file mode 100644
index 000000000..ccbd10e73
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/InjectedThing.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/InjectedThing_Factory.class b/compiler/src/it/functional-tests/target/classes/test/InjectedThing_Factory.class
new file mode 100644
index 000000000..3e7589d2f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/InjectedThing_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/InjectedThing_MembersInjector.class b/compiler/src/it/functional-tests/target/classes/test/InjectedThing_MembersInjector.class
new file mode 100644
index 000000000..22230bddf
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/InjectedThing_MembersInjector.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/Injector.class b/compiler/src/it/functional-tests/target/classes/test/Injector.class
new file mode 100644
index 000000000..39a8f5869
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/Injector.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingComponent.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingComponent.class
new file mode 100644
index 000000000..2d3391439
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingDependency.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingDependency.class
new file mode 100644
index 000000000..e7d6f9c51
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingDependency.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule.class
new file mode 100644
index 000000000..57c672bcc
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideBarKeyFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideBarKeyFactory.class
new file mode 100644
index 000000000..2bbd4570f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideBarKeyFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideFiveToSetFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideFiveToSetFactory.class
new file mode 100644
index 000000000..d0f2b4261
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideFiveToSetFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideFooKeyFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideFooKeyFactory.class
new file mode 100644
index 000000000..a6279d068
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideFooKeyFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideMapKeysFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideMapKeysFactory.class
new file mode 100644
index 000000000..31f17031c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideMapKeysFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideMapValuesFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideMapValuesFactory.class
new file mode 100644
index 000000000..9bd2173fd
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideMapValuesFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideSixToSetFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideSixToSetFactory.class
new file mode 100644
index 000000000..76121c5a1
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ProvideSixToSetFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100ByteFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100ByteFactory.class
new file mode 100644
index 000000000..fbd700b14
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100ByteFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100IntFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100IntFactory.class
new file mode 100644
index 000000000..b5cf5a43e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100IntFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100LongFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100LongFactory.class
new file mode 100644
index 000000000..83e80b4fa
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100LongFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100ShortFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100ShortFactory.class
new file mode 100644
index 000000000..1a5716b24
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueFor100ShortFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForAFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForAFactory.class
new file mode 100644
index 000000000..bf8d6760c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForAFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForClassIntegerFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForClassIntegerFactory.class
new file mode 100644
index 000000000..eb38a7af1
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForClassIntegerFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForClassLongFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForClassLongFactory.class
new file mode 100644
index 000000000..e7f717817
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForClassLongFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForIntegerFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForIntegerFactory.class
new file mode 100644
index 000000000..dea9f0bf2
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForIntegerFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForLongFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForLongFactory.class
new file mode 100644
index 000000000..a8d262ae5
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForLongFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForNewlineFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForNewlineFactory.class
new file mode 100644
index 000000000..80789ac0d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForNewlineFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForNumberClassBigDecimalFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForNumberClassBigDecimalFactory.class
new file mode 100644
index 000000000..0f63660c5
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForNumberClassBigDecimalFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForNumberClassBigIntegerFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForNumberClassBigIntegerFactory.class
new file mode 100644
index 000000000..2ad1fe432
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForNumberClassBigIntegerFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForTrueFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForTrueFactory.class
new file mode 100644
index 000000000..e95ddb881
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForTrueFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForUnwrappedAnnotationKeyFooFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForUnwrappedAnnotationKeyFooFactory.class
new file mode 100644
index 000000000..66de50ec2
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForUnwrappedAnnotationKeyFooFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForWrappedAnnotationKeyFooFactory.class b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForWrappedAnnotationKeyFooFactory.class
new file mode 100644
index 000000000..481c7e664
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/MultibindingModule_ValueForWrappedAnnotationKeyFooFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/NeedsFactory$Something.class b/compiler/src/it/functional-tests/target/classes/test/NeedsFactory$Something.class
new file mode 100644
index 000000000..579b77617
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/NeedsFactory$Something.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/NeedsFactory.class b/compiler/src/it/functional-tests/target/classes/test/NeedsFactory.class
new file mode 100644
index 000000000..b27676afe
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/NeedsFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/NeedsFactory_Factory.class b/compiler/src/it/functional-tests/target/classes/test/NeedsFactory_Factory.class
new file mode 100644
index 000000000..45b59cc24
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/NeedsFactory_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/NeedsFactory_SomethingFactory.class b/compiler/src/it/functional-tests/target/classes/test/NeedsFactory_SomethingFactory.class
new file mode 100644
index 000000000..15e599ac5
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/NeedsFactory_SomethingFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/NeedsFactory_SomethingFactory_Factory.class b/compiler/src/it/functional-tests/target/classes/test/NeedsFactory_SomethingFactory_Factory.class
new file mode 100644
index 000000000..29ce60f94
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/NeedsFactory_SomethingFactory_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingComponent.class b/compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingComponent.class
new file mode 100644
index 000000000..4494f9a8d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingComponentImpl.class b/compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingComponentImpl.class
new file mode 100644
index 000000000..1ebef3bf3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingComponentImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingTwo.class b/compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingTwo.class
new file mode 100644
index 000000000..97ebdb398
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingTwo.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingTwo_Factory.class b/compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingTwo_Factory.class
new file mode 100644
index 000000000..ebda07e92
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent$ThingTwo_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent.class b/compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent.class
new file mode 100644
index 000000000..7871ef863
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/NonComponentDependencyComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/OuterClassBar$NestedComponent.class b/compiler/src/it/functional-tests/target/classes/test/OuterClassBar$NestedComponent.class
new file mode 100644
index 000000000..c0857cda8
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/OuterClassBar$NestedComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/OuterClassBar.class b/compiler/src/it/functional-tests/target/classes/test/OuterClassBar.class
new file mode 100644
index 000000000..ab2b71967
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/OuterClassBar.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/OuterClassFoo$NestedComponent.class b/compiler/src/it/functional-tests/target/classes/test/OuterClassFoo$NestedComponent.class
new file mode 100644
index 000000000..d5e118a3e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/OuterClassFoo$NestedComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/OuterClassFoo.class b/compiler/src/it/functional-tests/target/classes/test/OuterClassFoo.class
new file mode 100644
index 000000000..6cbc369cb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/OuterClassFoo.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/ParentModule.class b/compiler/src/it/functional-tests/target/classes/test/ParentModule.class
new file mode 100644
index 000000000..0fa3925a4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/ParentModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/ParentModule_ProvideIterableOfAWithCFactory.class b/compiler/src/it/functional-tests/target/classes/test/ParentModule_ProvideIterableOfAWithCFactory.class
new file mode 100644
index 000000000..0192dbc2c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/ParentModule_ProvideIterableOfAWithCFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule.class
new file mode 100644
index 000000000..7a1023538
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_BoundDoubleArrayFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_BoundDoubleArrayFactory.class
new file mode 100644
index 000000000..44dc60a19
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_BoundDoubleArrayFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_BoundDoubleFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_BoundDoubleFactory.class
new file mode 100644
index 000000000..ab7fe896a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_BoundDoubleFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideBooleanArrayFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideBooleanArrayFactory.class
new file mode 100644
index 000000000..23281c504
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideBooleanArrayFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideBooleanFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideBooleanFactory.class
new file mode 100644
index 000000000..260b1bf29
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideBooleanFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideByteArrayFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideByteArrayFactory.class
new file mode 100644
index 000000000..3569991a8
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideByteArrayFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideByteFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideByteFactory.class
new file mode 100644
index 000000000..d8b073d83
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideByteFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideCharArrayFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideCharArrayFactory.class
new file mode 100644
index 000000000..c9f3054c2
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideCharArrayFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideCharFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideCharFactory.class
new file mode 100644
index 000000000..31fd662bf
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideCharFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideFloatArrayFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideFloatArrayFactory.class
new file mode 100644
index 000000000..4bf1a3fee
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideFloatArrayFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideFloatFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideFloatFactory.class
new file mode 100644
index 000000000..c6cef2de0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideFloatFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideIntArrayFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideIntArrayFactory.class
new file mode 100644
index 000000000..02ba00587
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideIntArrayFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideIntFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideIntFactory.class
new file mode 100644
index 000000000..ba9f0115b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideIntFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideLongArrayFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideLongArrayFactory.class
new file mode 100644
index 000000000..7ea4d780a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideLongArrayFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideLongFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideLongFactory.class
new file mode 100644
index 000000000..127737fd3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideLongFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideShortArrayFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideShortArrayFactory.class
new file mode 100644
index 000000000..caa25df0e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideShortArrayFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideShortFactory.class b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideShortFactory.class
new file mode 100644
index 000000000..6e439f442
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/PrimitivesModule_ProvideShortFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/ReferencesGeneric.class b/compiler/src/it/functional-tests/target/classes/test/ReferencesGeneric.class
new file mode 100644
index 000000000..06185b659
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/ReferencesGeneric.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/ReferencesGeneric_Factory.class b/compiler/src/it/functional-tests/target/classes/test/ReferencesGeneric_Factory.class
new file mode 100644
index 000000000..5f82891d0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/ReferencesGeneric_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/ScopedGeneric.class b/compiler/src/it/functional-tests/target/classes/test/ScopedGeneric.class
new file mode 100644
index 000000000..20af34070
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/ScopedGeneric.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/ScopedGeneric_Factory.class b/compiler/src/it/functional-tests/target/classes/test/ScopedGeneric_Factory.class
new file mode 100644
index 000000000..8e6f668a3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/ScopedGeneric_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/SingletonGenericComponent.class b/compiler/src/it/functional-tests/target/classes/test/SingletonGenericComponent.class
new file mode 100644
index 000000000..f6de44c81
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/SingletonGenericComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TestBooleanKey.class b/compiler/src/it/functional-tests/target/classes/test/TestBooleanKey.class
new file mode 100644
index 000000000..3eb2852a0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TestBooleanKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TestByteKey.class b/compiler/src/it/functional-tests/target/classes/test/TestByteKey.class
new file mode 100644
index 000000000..74de216f6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TestByteKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TestCharKey.class b/compiler/src/it/functional-tests/target/classes/test/TestCharKey.class
new file mode 100644
index 000000000..153149415
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TestCharKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TestClassKey.class b/compiler/src/it/functional-tests/target/classes/test/TestClassKey.class
new file mode 100644
index 000000000..82e83525a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TestClassKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TestIntKey.class b/compiler/src/it/functional-tests/target/classes/test/TestIntKey.class
new file mode 100644
index 000000000..812d7a711
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TestIntKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TestLongKey.class b/compiler/src/it/functional-tests/target/classes/test/TestLongKey.class
new file mode 100644
index 000000000..08a84bcd6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TestLongKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TestNumberClassKey.class b/compiler/src/it/functional-tests/target/classes/test/TestNumberClassKey.class
new file mode 100644
index 000000000..29cc60f3e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TestNumberClassKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TestShortKey.class b/compiler/src/it/functional-tests/target/classes/test/TestShortKey.class
new file mode 100644
index 000000000..84c9c9718
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TestShortKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TestStringKey$NestedWrappedKey.class b/compiler/src/it/functional-tests/target/classes/test/TestStringKey$NestedWrappedKey.class
new file mode 100644
index 000000000..3558d1c5b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TestStringKey$NestedWrappedKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TestStringKey$NestedWrappedKeyCreator.class b/compiler/src/it/functional-tests/target/classes/test/TestStringKey$NestedWrappedKeyCreator.class
new file mode 100644
index 000000000..c40276320
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TestStringKey$NestedWrappedKeyCreator.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TestStringKey.class b/compiler/src/it/functional-tests/target/classes/test/TestStringKey.class
new file mode 100644
index 000000000..2da81617d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TestStringKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TestUnwrappedAnnotationKey.class b/compiler/src/it/functional-tests/target/classes/test/TestUnwrappedAnnotationKey.class
new file mode 100644
index 000000000..54f727992
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TestUnwrappedAnnotationKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TestUnwrappedAnnotationKeyCreator.class b/compiler/src/it/functional-tests/target/classes/test/TestUnwrappedAnnotationKeyCreator.class
new file mode 100644
index 000000000..cfba81f42
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TestUnwrappedAnnotationKeyCreator.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TestWrappedAnnotationKey.class b/compiler/src/it/functional-tests/target/classes/test/TestWrappedAnnotationKey.class
new file mode 100644
index 000000000..9545b6055
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TestWrappedAnnotationKey.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TestWrappedAnnotationKeyCreator.class b/compiler/src/it/functional-tests/target/classes/test/TestWrappedAnnotationKeyCreator.class
new file mode 100644
index 000000000..1f2e4a971
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TestWrappedAnnotationKeyCreator.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/Thing.class b/compiler/src/it/functional-tests/target/classes/test/Thing.class
new file mode 100644
index 000000000..24101196f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/Thing.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/Thing_Factory.class b/compiler/src/it/functional-tests/target/classes/test/Thing_Factory.class
new file mode 100644
index 000000000..bf7ffaae4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/Thing_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TypeWithInheritedMembersInjection.class b/compiler/src/it/functional-tests/target/classes/test/TypeWithInheritedMembersInjection.class
new file mode 100644
index 000000000..6272e296a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TypeWithInheritedMembersInjection.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/TypeWithInheritedMembersInjection_Factory.class b/compiler/src/it/functional-tests/target/classes/test/TypeWithInheritedMembersInjection_Factory.class
new file mode 100644
index 000000000..e39d4d5bc
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/TypeWithInheritedMembersInjection_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/ByteModule.class b/compiler/src/it/functional-tests/target/classes/test/builder/ByteModule.class
new file mode 100644
index 000000000..c7ce4efd0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/ByteModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/ByteModule_BFactory.class b/compiler/src/it/functional-tests/target/classes/test/builder/ByteModule_BFactory.class
new file mode 100644
index 000000000..d952ff841
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/ByteModule_BFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerDepComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerDepComponent$1.class
new file mode 100644
index 000000000..35a943118
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerDepComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerDepComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerDepComponent$Builder.class
new file mode 100644
index 000000000..bce0df01e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerDepComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerDepComponent.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerDepComponent.class
new file mode 100644
index 000000000..8b4f3ae74
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerDepComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$1.class
new file mode 100644
index 000000000..9d7936600
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$Builder.class
new file mode 100644
index 000000000..e0bff3dcf
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildBuilder.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildBuilder.class
new file mode 100644
index 000000000..25690f4ec
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildBuilder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildImpl$GrandchildBuilder.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildImpl$GrandchildBuilder.class
new file mode 100644
index 000000000..b07990ba6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildImpl$GrandchildBuilder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildImpl$GrandchildImpl.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildImpl$GrandchildImpl.class
new file mode 100644
index 000000000..137804e91
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildImpl$GrandchildImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildImpl.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildImpl.class
new file mode 100644
index 000000000..a92b722db
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$MiddleChildImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildBuilder.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildBuilder.class
new file mode 100644
index 000000000..01f7f32f0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildBuilder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildImpl$GrandchildBuilder.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildImpl$GrandchildBuilder.class
new file mode 100644
index 000000000..6bf6832fb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildImpl$GrandchildBuilder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildImpl$GrandchildImpl.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildImpl$GrandchildImpl.class
new file mode 100644
index 000000000..66a9181f8
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildImpl$GrandchildImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildImpl.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildImpl.class
new file mode 100644
index 000000000..c08cc4c26
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$OtherMiddleChildImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderAbstractClassBuilder.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderAbstractClassBuilder.class
new file mode 100644
index 000000000..0f4079f1d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderAbstractClassBuilder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderAbstractClassImpl.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderAbstractClassImpl.class
new file mode 100644
index 000000000..2317e4c04
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderAbstractClassImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderInterfaceBuilder.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderInterfaceBuilder.class
new file mode 100644
index 000000000..e3ab6a18c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderInterfaceBuilder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderInterfaceImpl.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderInterfaceImpl.class
new file mode 100644
index 000000000..5a33eb93e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent$TestChildComponentWithBuilderInterfaceImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent.class
new file mode 100644
index 000000000..7c13f8222
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$1.class
new file mode 100644
index 000000000..4f8a3d382
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$Builder.class
new file mode 100644
index 000000000..2615fecce
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$GrandchildBuilder.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$GrandchildBuilder.class
new file mode 100644
index 000000000..cfde9e75c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$GrandchildBuilder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$GrandchildImpl.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$GrandchildImpl.class
new file mode 100644
index 000000000..219673e81
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent$GrandchildImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent.class
new file mode 100644
index 000000000..fa43a6fdb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerParentOfGenericComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderAbstractClass$1.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderAbstractClass$1.class
new file mode 100644
index 000000000..e36e84790
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderAbstractClass$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderAbstractClass$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderAbstractClass$Builder.class
new file mode 100644
index 000000000..d8b980d0a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderAbstractClass$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderAbstractClass.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderAbstractClass.class
new file mode 100644
index 000000000..2b66078b6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderAbstractClass.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderInterface$1.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderInterface$1.class
new file mode 100644
index 000000000..86045c67c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderInterface$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderInterface$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderInterface$Builder.class
new file mode 100644
index 000000000..2a8e75f3e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderInterface$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderInterface.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderInterface.class
new file mode 100644
index 000000000..d72fea092
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithBuilderInterface.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass$1.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass$1.class
new file mode 100644
index 000000000..b8864e524
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass$Builder.class
new file mode 100644
index 000000000..91feb7d24
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass.class
new file mode 100644
index 000000000..8bb8b89d1
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderInterface$1.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderInterface$1.class
new file mode 100644
index 000000000..f9dbd60ba
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderInterface$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderInterface$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderInterface$Builder.class
new file mode 100644
index 000000000..cdeeb01de
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderInterface$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderInterface.class b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderInterface.class
new file mode 100644
index 000000000..817f26dcd
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DaggerTestComponentWithGenericBuilderInterface.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DepComponent.class b/compiler/src/it/functional-tests/target/classes/test/builder/DepComponent.class
new file mode 100644
index 000000000..817678039
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DepComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DoubleModule.class b/compiler/src/it/functional-tests/target/classes/test/builder/DoubleModule.class
new file mode 100644
index 000000000..6343fe117
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DoubleModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/DoubleModule_DFactory.class b/compiler/src/it/functional-tests/target/classes/test/builder/DoubleModule_DFactory.class
new file mode 100644
index 000000000..0057887ba
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/DoubleModule_DFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/FloatModule.class b/compiler/src/it/functional-tests/target/classes/test/builder/FloatModule.class
new file mode 100644
index 000000000..613f72c85
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/FloatModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/FloatModule_FFactory.class b/compiler/src/it/functional-tests/target/classes/test/builder/FloatModule_FFactory.class
new file mode 100644
index 000000000..15938e74f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/FloatModule_FFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/GenericParent.class b/compiler/src/it/functional-tests/target/classes/test/builder/GenericParent.class
new file mode 100644
index 000000000..5ad0f4f89
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/GenericParent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/Grandchild$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/Grandchild$Builder.class
new file mode 100644
index 000000000..8dc9ef273
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/Grandchild$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/Grandchild.class b/compiler/src/it/functional-tests/target/classes/test/builder/Grandchild.class
new file mode 100644
index 000000000..fe6467f04
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/Grandchild.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/IntModuleIncludingDoubleAndFloat.class b/compiler/src/it/functional-tests/target/classes/test/builder/IntModuleIncludingDoubleAndFloat.class
new file mode 100644
index 000000000..9f8593303
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/IntModuleIncludingDoubleAndFloat.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/IntModuleIncludingDoubleAndFloat_IntegerFactory.class b/compiler/src/it/functional-tests/target/classes/test/builder/IntModuleIncludingDoubleAndFloat_IntegerFactory.class
new file mode 100644
index 000000000..7f48d0bd3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/IntModuleIncludingDoubleAndFloat_IntegerFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/LongModule.class b/compiler/src/it/functional-tests/target/classes/test/builder/LongModule.class
new file mode 100644
index 000000000..756889a9b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/LongModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/LongModule_LFactory.class b/compiler/src/it/functional-tests/target/classes/test/builder/LongModule_LFactory.class
new file mode 100644
index 000000000..8af7ab1cc
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/LongModule_LFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/MiddleChild$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/MiddleChild$Builder.class
new file mode 100644
index 000000000..5932a2a4e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/MiddleChild$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/MiddleChild.class b/compiler/src/it/functional-tests/target/classes/test/builder/MiddleChild.class
new file mode 100644
index 000000000..6095caeb5
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/MiddleChild.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/MiddleScope.class b/compiler/src/it/functional-tests/target/classes/test/builder/MiddleScope.class
new file mode 100644
index 000000000..69a6d86db
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/MiddleScope.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/OtherMiddleChild$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/OtherMiddleChild$Builder.class
new file mode 100644
index 000000000..c66bdf6c4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/OtherMiddleChild$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/OtherMiddleChild.class b/compiler/src/it/functional-tests/target/classes/test/builder/OtherMiddleChild.class
new file mode 100644
index 000000000..fb2aa775e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/OtherMiddleChild.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/ParentComponent.class b/compiler/src/it/functional-tests/target/classes/test/builder/ParentComponent.class
new file mode 100644
index 000000000..1f8780851
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/ParentComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/ParentOfGenericComponent.class b/compiler/src/it/functional-tests/target/classes/test/builder/ParentOfGenericComponent.class
new file mode 100644
index 000000000..3806d0bdd
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/ParentOfGenericComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/StringModule.class b/compiler/src/it/functional-tests/target/classes/test/builder/StringModule.class
new file mode 100644
index 000000000..08b2472ce
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/StringModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/StringModule_StringFactory.class b/compiler/src/it/functional-tests/target/classes/test/builder/StringModule_StringFactory.class
new file mode 100644
index 000000000..14f561279
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/StringModule_StringFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderAbstractClass$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderAbstractClass$Builder.class
new file mode 100644
index 000000000..b8bb84009
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderAbstractClass$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderAbstractClass$SharedBuilder.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderAbstractClass$SharedBuilder.class
new file mode 100644
index 000000000..24f8a8fbd
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderAbstractClass$SharedBuilder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderAbstractClass.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderAbstractClass.class
new file mode 100644
index 000000000..b5607f7c0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderAbstractClass.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderInterface$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderInterface$Builder.class
new file mode 100644
index 000000000..ea9c38495
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderInterface$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderInterface$SharedBuilder.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderInterface$SharedBuilder.class
new file mode 100644
index 000000000..d06c2686d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderInterface$SharedBuilder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderInterface.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderInterface.class
new file mode 100644
index 000000000..7399f252c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestChildComponentWithBuilderInterface.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderAbstractClass$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderAbstractClass$Builder.class
new file mode 100644
index 000000000..b5d735403
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderAbstractClass$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderAbstractClass$SharedBuilder.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderAbstractClass$SharedBuilder.class
new file mode 100644
index 000000000..98bd32571
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderAbstractClass$SharedBuilder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderAbstractClass.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderAbstractClass.class
new file mode 100644
index 000000000..b9d209a17
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderAbstractClass.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderInterface$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderInterface$Builder.class
new file mode 100644
index 000000000..9099d5c44
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderInterface$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderInterface$SharedBuilder.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderInterface$SharedBuilder.class
new file mode 100644
index 000000000..e0cb76d85
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderInterface$SharedBuilder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderInterface.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderInterface.class
new file mode 100644
index 000000000..626909db9
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithBuilderInterface.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderAbstractClass$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderAbstractClass$Builder.class
new file mode 100644
index 000000000..6dcd5945a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderAbstractClass$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderAbstractClass$SharedBuilder.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderAbstractClass$SharedBuilder.class
new file mode 100644
index 000000000..37c0cf38a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderAbstractClass$SharedBuilder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderAbstractClass.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderAbstractClass.class
new file mode 100644
index 000000000..1f9c5061a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderAbstractClass.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderInterface$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderInterface$Builder.class
new file mode 100644
index 000000000..0f7b9a230
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderInterface$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderInterface$SharedBuilder.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderInterface$SharedBuilder.class
new file mode 100644
index 000000000..2bdb5e1ad
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderInterface$SharedBuilder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderInterface.class b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderInterface.class
new file mode 100644
index 000000000..ef5e25432
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/TestComponentWithGenericBuilderInterface.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/ApiComponent.class b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/ApiComponent.class
new file mode 100644
index 000000000..0bc10dd4b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/ApiComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/CloudContactDataStore.class b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/CloudContactDataStore.class
new file mode 100644
index 000000000..a66031958
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/CloudContactDataStore.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/ContactDataStore.class b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/ContactDataStore.class
new file mode 100644
index 000000000..ad2405284
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/ContactDataStore.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/ContactDataStore_MembersInjector.class b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/ContactDataStore_MembersInjector.class
new file mode 100644
index 000000000..c2e23b563
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/ContactDataStore_MembersInjector.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/DaggerApiComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/DaggerApiComponent$1.class
new file mode 100644
index 000000000..9a6f06b44
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/DaggerApiComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/DaggerApiComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/DaggerApiComponent$Builder.class
new file mode 100644
index 000000000..2cbd339a4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/DaggerApiComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/DaggerApiComponent.class b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/DaggerApiComponent.class
new file mode 100644
index 000000000..6cd698ce9
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/DaggerApiComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/RestClient.class b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/RestClient.class
new file mode 100644
index 000000000..38ff0921a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/RestClient.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/RestClient_Factory.class b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/RestClient_Factory.class
new file mode 100644
index 000000000..94dfe224a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/abstractinjectmethod/RestClient_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerOneComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerOneComponent$1.class
new file mode 100644
index 000000000..1474902a4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerOneComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerOneComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerOneComponent$Builder.class
new file mode 100644
index 000000000..a97a38fbb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerOneComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerOneComponent.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerOneComponent.class
new file mode 100644
index 000000000..0661cfb10
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerOneComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerTwoComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerTwoComponent$1.class
new file mode 100644
index 000000000..747559a4e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerTwoComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerTwoComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerTwoComponent$Builder.class
new file mode 100644
index 000000000..70de723df
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerTwoComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerTwoComponent.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerTwoComponent.class
new file mode 100644
index 000000000..a3e7f774c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/DaggerPackagerTwoComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/Packager.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/Packager.class
new file mode 100644
index 000000000..cce10a59a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/Packager.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/PackagerOneComponent.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/PackagerOneComponent.class
new file mode 100644
index 000000000..b419ad888
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/PackagerOneComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/PackagerTwoComponent.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/PackagerTwoComponent.class
new file mode 100644
index 000000000..4cfceaa69
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/PackagerTwoComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/Packager_Factory.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/Packager_Factory.class
new file mode 100644
index 000000000..ea9bc0d92
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/Packager_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/Product.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/Product.class
new file mode 100644
index 000000000..50a825947
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/Product.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOne.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOne.class
new file mode 100644
index 000000000..0acdccb81
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOne.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOneModule.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOneModule.class
new file mode 100644
index 000000000..5d234b694
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOneModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOneModule_ProvideProductFactory.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOneModule_ProvideProductFactory.class
new file mode 100644
index 000000000..89d723606
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOneModule_ProvideProductFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOne_Factory.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOne_Factory.class
new file mode 100644
index 000000000..bdb092bf8
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductOne_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwo.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwo.class
new file mode 100644
index 000000000..e6c976b17
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwo.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwoModule.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwoModule.class
new file mode 100644
index 000000000..3e20d4557
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwoModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwoModule_ProvideProductFactory.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwoModule_ProvideProductFactory.class
new file mode 100644
index 000000000..8f041c1ba
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwoModule_ProvideProductFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwo_Factory.class b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwo_Factory.class
new file mode 100644
index 000000000..c93aba532
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/product/ProductTwo_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent$1.class
new file mode 100644
index 000000000..493c9e370
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent$Builder.class
new file mode 100644
index 000000000..cf66600e1
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent$SubComponentImpl.class b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent$SubComponentImpl.class
new file mode 100644
index 000000000..a42a01c98
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent$SubComponentImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent.class b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent.class
new file mode 100644
index 000000000..f9802fc93
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/DaggerRootComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/ModuleWithParameter.class b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/ModuleWithParameter.class
new file mode 100644
index 000000000..d76d26b7e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/ModuleWithParameter.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/ModuleWithParameter_ProvidesStringFactory.class b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/ModuleWithParameter_ProvidesStringFactory.class
new file mode 100644
index 000000000..2a67a421f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/ModuleWithParameter_ProvidesStringFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/RootComponent.class b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/RootComponent.class
new file mode 100644
index 000000000..a37d7b6d4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/RootComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/SubComponent.class b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/SubComponent.class
new file mode 100644
index 000000000..49c82146e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/builder/subcomponent/SubComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/membersinject/ChildOfArrayOfParentOfStringArray.class b/compiler/src/it/functional-tests/target/classes/test/membersinject/ChildOfArrayOfParentOfStringArray.class
new file mode 100644
index 000000000..0173043f0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/membersinject/ChildOfArrayOfParentOfStringArray.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/membersinject/ChildOfPrimitiveIntArray.class b/compiler/src/it/functional-tests/target/classes/test/membersinject/ChildOfPrimitiveIntArray.class
new file mode 100644
index 000000000..6033324fb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/membersinject/ChildOfPrimitiveIntArray.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/membersinject/ChildOfStringArray.class b/compiler/src/it/functional-tests/target/classes/test/membersinject/ChildOfStringArray.class
new file mode 100644
index 000000000..ce1c979e3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/membersinject/ChildOfStringArray.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/membersinject/DaggerMembersInjectComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/membersinject/DaggerMembersInjectComponent$1.class
new file mode 100644
index 000000000..0ee2d134d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/membersinject/DaggerMembersInjectComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/membersinject/DaggerMembersInjectComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/membersinject/DaggerMembersInjectComponent$Builder.class
new file mode 100644
index 000000000..33b6eb3ec
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/membersinject/DaggerMembersInjectComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/membersinject/DaggerMembersInjectComponent.class b/compiler/src/it/functional-tests/target/classes/test/membersinject/DaggerMembersInjectComponent.class
new file mode 100644
index 000000000..6df464913
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/membersinject/DaggerMembersInjectComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectComponent.class b/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectComponent.class
new file mode 100644
index 000000000..1f2fdfb7a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectGenericParent.class b/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectGenericParent.class
new file mode 100644
index 000000000..b61d37511
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectGenericParent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectGenericParent_MembersInjector.class b/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectGenericParent_MembersInjector.class
new file mode 100644
index 000000000..61d659594
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectGenericParent_MembersInjector.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule.class b/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule.class
new file mode 100644
index 000000000..a68a17e11
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule_ProvideFooArrayOfStringArrayFactory.class b/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule_ProvideFooArrayOfStringArrayFactory.class
new file mode 100644
index 000000000..7a1ea5930
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule_ProvideFooArrayOfStringArrayFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule_ProvideIntArrayFactory.class b/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule_ProvideIntArrayFactory.class
new file mode 100644
index 000000000..fe84b88fa
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule_ProvideIntArrayFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule_ProvideStringArrayFactory.class b/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule_ProvideStringArrayFactory.class
new file mode 100644
index 000000000..994c86da5
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/membersinject/MembersInjectModule_ProvideStringArrayFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$1.class
new file mode 100644
index 000000000..af8df0808
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$Builder.class
new file mode 100644
index 000000000..05adb9da6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$FooChildComponentImpl$FooGrandchildComponentImpl.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$FooChildComponentImpl$FooGrandchildComponentImpl.class
new file mode 100644
index 000000000..a85147f1c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$FooChildComponentImpl$FooGrandchildComponentImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$FooChildComponentImpl.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$FooChildComponentImpl.class
new file mode 100644
index 000000000..df11bba99
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent$FooChildComponentImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent.class
new file mode 100644
index 000000000..25a8947f9
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/DaggerFooComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/FooComponent.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/FooComponent.class
new file mode 100644
index 000000000..06aaffa2b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/FooComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/a/AModule.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/a/AModule.class
new file mode 100644
index 000000000..292e4eea1
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/a/AModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/a/AModule_ProvideStringFactory.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/a/AModule_ProvideStringFactory.class
new file mode 100644
index 000000000..d39b39e9f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/a/AModule_ProvideStringFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/b/BModule.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/b/BModule.class
new file mode 100644
index 000000000..85a63abd1
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/b/BModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/b/BModule_ProvideStringFactory.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/b/BModule_ProvideStringFactory.class
new file mode 100644
index 000000000..0bafddc01
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/b/BModule_ProvideStringFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/c/CModule.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/c/CModule.class
new file mode 100644
index 000000000..0dd730550
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/c/CModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/c/CModule_ProvideStringFactory.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/c/CModule_ProvideStringFactory.class
new file mode 100644
index 000000000..69a9ebcce
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/c/CModule_ProvideStringFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/d/DModule.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/d/DModule.class
new file mode 100644
index 000000000..11af190f3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/d/DModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/d/DModule_ProvideStringFactory.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/d/DModule_ProvideStringFactory.class
new file mode 100644
index 000000000..c3d7c7169
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/d/DModule_ProvideStringFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/foo/Foo.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/foo/Foo.class
new file mode 100644
index 000000000..03eee0f7c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/foo/Foo.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/foo/Foo_Factory.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/foo/Foo_Factory.class
new file mode 100644
index 000000000..ffbe6e764
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/foo/Foo_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/grandsub/FooGrandchildComponent.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/grandsub/FooGrandchildComponent.class
new file mode 100644
index 000000000..9f04a7cc1
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/grandsub/FooGrandchildComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/multipackage/sub/FooChildComponent.class b/compiler/src/it/functional-tests/target/classes/test/multipackage/sub/FooChildComponent.class
new file mode 100644
index 000000000..757dc984c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/multipackage/sub/FooChildComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponent$1.class
new file mode 100644
index 000000000..d861d0793
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponent$Builder.class
new file mode 100644
index 000000000..b416d5cdf
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponent.class b/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponent.class
new file mode 100644
index 000000000..bf568f925
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency$1.class b/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency$1.class
new file mode 100644
index 000000000..72fcf3397
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency$2.class b/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency$2.class
new file mode 100644
index 000000000..7147fe63c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency$2.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency$Builder.class b/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency$Builder.class
new file mode 100644
index 000000000..b18e193d2
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency.class b/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency.class
new file mode 100644
index 000000000..c667dd696
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/DaggerNullComponentWithDependency.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/NullComponent.class b/compiler/src/it/functional-tests/target/classes/test/nullables/NullComponent.class
new file mode 100644
index 000000000..1ced792e2
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/NullComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/NullComponentWithDependency.class b/compiler/src/it/functional-tests/target/classes/test/nullables/NullComponentWithDependency.class
new file mode 100644
index 000000000..476368df4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/NullComponentWithDependency.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/NullFoo.class b/compiler/src/it/functional-tests/target/classes/test/nullables/NullFoo.class
new file mode 100644
index 000000000..9fc4521fa
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/NullFoo.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/NullFoo_Factory.class b/compiler/src/it/functional-tests/target/classes/test/nullables/NullFoo_Factory.class
new file mode 100644
index 000000000..cd8089692
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/NullFoo_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/NullFoo_MembersInjector.class b/compiler/src/it/functional-tests/target/classes/test/nullables/NullFoo_MembersInjector.class
new file mode 100644
index 000000000..5cfbcc8a0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/NullFoo_MembersInjector.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/NullModule.class b/compiler/src/it/functional-tests/target/classes/test/nullables/NullModule.class
new file mode 100644
index 000000000..5b5ed66b4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/NullModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/NullModule_ProvideNullableStringFactory.class b/compiler/src/it/functional-tests/target/classes/test/nullables/NullModule_ProvideNullableStringFactory.class
new file mode 100644
index 000000000..2d714b490
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/NullModule_ProvideNullableStringFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/NullModule_ProvideNumberFactory.class b/compiler/src/it/functional-tests/target/classes/test/nullables/NullModule_ProvideNumberFactory.class
new file mode 100644
index 000000000..f086d2c8b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/NullModule_ProvideNumberFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/nullables/Nullable.class b/compiler/src/it/functional-tests/target/classes/test/nullables/Nullable.class
new file mode 100644
index 000000000..6fac710a3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/nullables/Nullable.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/staticprovides/AllStaticModule.class b/compiler/src/it/functional-tests/target/classes/test/staticprovides/AllStaticModule.class
new file mode 100644
index 000000000..496239799
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/staticprovides/AllStaticModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/staticprovides/AllStaticModule_ContibuteEmptyIntegerSetFactory.class b/compiler/src/it/functional-tests/target/classes/test/staticprovides/AllStaticModule_ContibuteEmptyIntegerSetFactory.class
new file mode 100644
index 000000000..5acb9db36
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/staticprovides/AllStaticModule_ContibuteEmptyIntegerSetFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/staticprovides/AllStaticModule_ContributeStringFactory.class b/compiler/src/it/functional-tests/target/classes/test/staticprovides/AllStaticModule_ContributeStringFactory.class
new file mode 100644
index 000000000..7a57a3579
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/staticprovides/AllStaticModule_ContributeStringFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/staticprovides/DaggerStaticTestComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/staticprovides/DaggerStaticTestComponent$1.class
new file mode 100644
index 000000000..e6bbfaa4e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/staticprovides/DaggerStaticTestComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/staticprovides/DaggerStaticTestComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/staticprovides/DaggerStaticTestComponent$Builder.class
new file mode 100644
index 000000000..f538647ab
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/staticprovides/DaggerStaticTestComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/staticprovides/DaggerStaticTestComponent.class b/compiler/src/it/functional-tests/target/classes/test/staticprovides/DaggerStaticTestComponent.class
new file mode 100644
index 000000000..11accabc0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/staticprovides/DaggerStaticTestComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/staticprovides/SomeStaticModule.class b/compiler/src/it/functional-tests/target/classes/test/staticprovides/SomeStaticModule.class
new file mode 100644
index 000000000..3144f7ab4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/staticprovides/SomeStaticModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/staticprovides/SomeStaticModule_ContributeStringFromAStaticMethodFactory.class b/compiler/src/it/functional-tests/target/classes/test/staticprovides/SomeStaticModule_ContributeStringFromAStaticMethodFactory.class
new file mode 100644
index 000000000..124e8e040
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/staticprovides/SomeStaticModule_ContributeStringFromAStaticMethodFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/staticprovides/SomeStaticModule_ContributeStringFromAnInstanceMethodFactory.class b/compiler/src/it/functional-tests/target/classes/test/staticprovides/SomeStaticModule_ContributeStringFromAnInstanceMethodFactory.class
new file mode 100644
index 000000000..5b4aece3e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/staticprovides/SomeStaticModule_ContributeStringFromAnInstanceMethodFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/staticprovides/StaticTestComponent.class b/compiler/src/it/functional-tests/target/classes/test/staticprovides/StaticTestComponent.class
new file mode 100644
index 000000000..1abae9660
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/staticprovides/StaticTestComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule.class b/compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule.class
new file mode 100644
index 000000000..5cabd6846
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule_ContributeAnIntFactory.class b/compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule_ContributeAnIntFactory.class
new file mode 100644
index 000000000..c60b25f22
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule_ContributeAnIntFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule_ContributeAnotherIntFactory.class b/compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule_ContributeAnotherIntFactory.class
new file mode 100644
index 000000000..b82189255
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule_ContributeAnotherIntFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule_ContributeSomeIntsFactory.class b/compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule_ContributeSomeIntsFactory.class
new file mode 100644
index 000000000..19430b58c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/ContributionsModule_ContributeSomeIntsFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/DaggerGenericComponent_PackageProxy.class b/compiler/src/it/functional-tests/target/classes/test/sub/DaggerGenericComponent_PackageProxy.class
new file mode 100644
index 000000000..0c4664256
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/DaggerGenericComponent_PackageProxy.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/Exposed.class b/compiler/src/it/functional-tests/target/classes/test/sub/Exposed.class
new file mode 100644
index 000000000..36514decd
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/Exposed.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/Exposed_Factory.class b/compiler/src/it/functional-tests/target/classes/test/sub/Exposed_Factory.class
new file mode 100644
index 000000000..d3aab2285
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/Exposed_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/Exposed_MembersInjector.class b/compiler/src/it/functional-tests/target/classes/test/sub/Exposed_MembersInjector.class
new file mode 100644
index 000000000..81b2f64f7
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/Exposed_MembersInjector.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/OtherThing.class b/compiler/src/it/functional-tests/target/classes/test/sub/OtherThing.class
new file mode 100644
index 000000000..2a727d579
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/OtherThing.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/OtherThing_Factory.class b/compiler/src/it/functional-tests/target/classes/test/sub/OtherThing_Factory.class
new file mode 100644
index 000000000..cc9285abf
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/OtherThing_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivate.class b/compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivate.class
new file mode 100644
index 000000000..bc12412c6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivate.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivateContainer$PublicEnclosed.class b/compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivateContainer$PublicEnclosed.class
new file mode 100644
index 000000000..c24c3adc3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivateContainer$PublicEnclosed.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivateContainer$PublicEnclosed_Factory.class b/compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivateContainer$PublicEnclosed_Factory.class
new file mode 100644
index 000000000..89a293b22
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivateContainer$PublicEnclosed_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivateContainer.class b/compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivateContainer.class
new file mode 100644
index 000000000..4f325e603
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivateContainer.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivate_Factory.class b/compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivate_Factory.class
new file mode 100644
index 000000000..472d079f4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/PackagePrivate_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass.class b/compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass.class
new file mode 100644
index 000000000..ba723ca84
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass2.class b/compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass2.class
new file mode 100644
index 000000000..c09b83d77
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass2.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass2_Factory.class b/compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass2_Factory.class
new file mode 100644
index 000000000..942ba3db3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass2_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass_Factory.class b/compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass_Factory.class
new file mode 100644
index 000000000..20a2642c6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/sub/PublicSubclass_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/AnInterface.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/AnInterface.class
new file mode 100644
index 000000000..77ca460ca
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/AnInterface.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/BoundAsSingleton.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/BoundAsSingleton.class
new file mode 100644
index 000000000..f265a15c6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/BoundAsSingleton.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildAbstractClassComponent.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildAbstractClassComponent.class
new file mode 100644
index 000000000..0a6e67a37
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildAbstractClassComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildComponent.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildComponent.class
new file mode 100644
index 000000000..5075baa71
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildComponentRequiringModules.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildComponentRequiringModules.class
new file mode 100644
index 000000000..0ec97391c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildComponentRequiringModules.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModule$1.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModule$1.class
new file mode 100644
index 000000000..03217f454
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModule$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModule.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModule.class
new file mode 100644
index 000000000..90de24748
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModuleWithParameters.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModuleWithParameters.class
new file mode 100644
index 000000000..b56dc2558
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModuleWithParameters.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModuleWithState.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModuleWithState.class
new file mode 100644
index 000000000..955327972
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModuleWithState.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModuleWithState_ProvideIntFactory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModuleWithState_ProvideIntFactory.class
new file mode 100644
index 000000000..1e2a0dff5
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModuleWithState_ProvideIntFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModule_ProvideUnscopedObjectFactory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModule_ProvideUnscopedObjectFactory.class
new file mode 100644
index 000000000..65139cafb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ChildModule_ProvideUnscopedObjectFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$1.class
new file mode 100644
index 000000000..8f711515b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$Builder.class
new file mode 100644
index 000000000..20c38e369
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildAbstractClassComponentImpl$GrandchildComponentImpl.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildAbstractClassComponentImpl$GrandchildComponentImpl.class
new file mode 100644
index 000000000..cb3420e4f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildAbstractClassComponentImpl$GrandchildComponentImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildAbstractClassComponentImpl.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildAbstractClassComponentImpl.class
new file mode 100644
index 000000000..3a9deefb4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildAbstractClassComponentImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildComponentImpl$GrandchildComponentImpl.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildComponentImpl$GrandchildComponentImpl.class
new file mode 100644
index 000000000..ed73304f2
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildComponentImpl$GrandchildComponentImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildComponentImpl.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildComponentImpl.class
new file mode 100644
index 000000000..bf1423745
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildComponentImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildComponentRequiringModulesImpl.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildComponentRequiringModulesImpl.class
new file mode 100644
index 000000000..0d174e6ed
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent$ChildComponentRequiringModulesImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent.class
new file mode 100644
index 000000000..2439a9460
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$1.class
new file mode 100644
index 000000000..2d281e59d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$Builder.class
new file mode 100644
index 000000000..b1f5d1d3c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$ChildComponentImpl$GrandchildComponentImpl.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$ChildComponentImpl$GrandchildComponentImpl.class
new file mode 100644
index 000000000..00af3fc4e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$ChildComponentImpl$GrandchildComponentImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$ChildComponentImpl.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$ChildComponentImpl.class
new file mode 100644
index 000000000..a130a3e08
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent$ChildComponentImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent.class
new file mode 100644
index 000000000..5653e5b2f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/DaggerParentOfGenericComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/GenericParentComponent.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/GenericParentComponent.class
new file mode 100644
index 000000000..dfa9b0fdb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/GenericParentComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildComponent.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildComponent.class
new file mode 100644
index 000000000..390f0e566
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule$1.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule$1.class
new file mode 100644
index 000000000..c6ac188cb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule.class
new file mode 100644
index 000000000..4d275e9b3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule_ProvideAnInterfaceFactory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule_ProvideAnInterfaceFactory.class
new file mode 100644
index 000000000..e6a1f1dcb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule_ProvideAnInterfaceFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule_ProvideNeedsAnInterfaceFactory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule_ProvideNeedsAnInterfaceFactory.class
new file mode 100644
index 000000000..1d79a804f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule_ProvideNeedsAnInterfaceFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule_ProvideUnscopedObjectFactory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule_ProvideUnscopedObjectFactory.class
new file mode 100644
index 000000000..75893a16a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/GrandchildModule_ProvideUnscopedObjectFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ImplementsAnInterface.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ImplementsAnInterface.class
new file mode 100644
index 000000000..efd6574e1
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ImplementsAnInterface.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ImplementsAnInterface_Factory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ImplementsAnInterface_Factory.class
new file mode 100644
index 000000000..f36c98c68
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ImplementsAnInterface_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/NeedsAnInterface.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/NeedsAnInterface.class
new file mode 100644
index 000000000..ed949d4da
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/NeedsAnInterface.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentComponent.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentComponent.class
new file mode 100644
index 000000000..c7bffc5c7
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentGetters.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentGetters.class
new file mode 100644
index 000000000..7ce269633
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentGetters.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule$1.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule$1.class
new file mode 100644
index 000000000..ae1d91e66
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule$2.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule$2.class
new file mode 100644
index 000000000..2aeb06bcf
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule$2.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule.class
new file mode 100644
index 000000000..2a25ee1e0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule_ProvideSingletonObjectFactory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule_ProvideSingletonObjectFactory.class
new file mode 100644
index 000000000..680e3a6c1
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule_ProvideSingletonObjectFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule_ProvideUnscopedObjectFactory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule_ProvideUnscopedObjectFactory.class
new file mode 100644
index 000000000..4ece42f63
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule_ProvideUnscopedObjectFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule_ProvideUnscopedTypeBoundAsSingletonFactory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule_ProvideUnscopedTypeBoundAsSingletonFactory.class
new file mode 100644
index 000000000..8e35c9426
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentModule_ProvideUnscopedTypeBoundAsSingletonFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentOfGenericComponent.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentOfGenericComponent.class
new file mode 100644
index 000000000..b40bbf853
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/ParentOfGenericComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/RequiresSingletons.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/RequiresSingletons.class
new file mode 100644
index 000000000..43c7104db
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/RequiresSingletons.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/RequiresSingletons_Factory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/RequiresSingletons_Factory.class
new file mode 100644
index 000000000..23be0210a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/RequiresSingletons_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/SingletonType.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/SingletonType.class
new file mode 100644
index 000000000..d716fe63b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/SingletonType.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/SingletonType_Factory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/SingletonType_Factory.class
new file mode 100644
index 000000000..63794ef99
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/SingletonType_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/UnscopedType.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/UnscopedType.class
new file mode 100644
index 000000000..54272acd3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/UnscopedType.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/UnscopedType_Factory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/UnscopedType_Factory.class
new file mode 100644
index 000000000..85ab954b2
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/UnscopedType_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/ChildComponent.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/ChildComponent.class
new file mode 100644
index 000000000..e6f3594d3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/ChildComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent$1.class
new file mode 100644
index 000000000..1c5649a25
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent$Builder.class
new file mode 100644
index 000000000..536e4b27d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent$ChildComponentImpl.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent$ChildComponentImpl.class
new file mode 100644
index 000000000..873a34871
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent$ChildComponentImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent.class
new file mode 100644
index 000000000..acf4107e7
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/DaggerParentComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/ParentComponent.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/ParentComponent.class
new file mode 100644
index 000000000..5ad576eeb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/ParentComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonModuleName.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonModuleName.class
new file mode 100644
index 000000000..6b2607534
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonModuleName.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonModuleName_ProvideStringFactory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonModuleName_ProvideStringFactory.class
new file mode 100644
index 000000000..30f90da6b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonModuleName_ProvideStringFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonName.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonName.class
new file mode 100644
index 000000000..ff32b8318
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonName.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonName_Factory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonName_Factory.class
new file mode 100644
index 000000000..8a6d851a4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/a/CommonName_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonModuleName.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonModuleName.class
new file mode 100644
index 000000000..9310d9d0f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonModuleName.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonModuleName_ProvideStringFactory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonModuleName_ProvideStringFactory.class
new file mode 100644
index 000000000..61965facc
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonModuleName_ProvideStringFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonName.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonName.class
new file mode 100644
index 000000000..2cec405dd
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonName.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonName_Factory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonName_Factory.class
new file mode 100644
index 000000000..ecff3a31f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/hiding/b/CommonName_Factory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/ChildComponent.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/ChildComponent.class
new file mode 100644
index 000000000..90a566ff0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/ChildComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent$1.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent$1.class
new file mode 100644
index 000000000..dfadab303
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent$Builder.class
new file mode 100644
index 000000000..7e777cd56
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent$ChildComponentImpl.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent$ChildComponentImpl.class
new file mode 100644
index 000000000..d70259668
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent$ChildComponentImpl.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent.class
new file mode 100644
index 000000000..74e36c166
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/DaggerParentComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/OnlyUsedInChild.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/OnlyUsedInChild.class
new file mode 100644
index 000000000..a621dee34
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/OnlyUsedInChild.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/OnlyUsedInParent.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/OnlyUsedInParent.class
new file mode 100644
index 000000000..403929149
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/OnlyUsedInParent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/ParentComponent$Builder.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/ParentComponent$Builder.class
new file mode 100644
index 000000000..b20830de7
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/ParentComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/ParentComponent.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/ParentComponent.class
new file mode 100644
index 000000000..726575bba
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/ParentComponent.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule$1.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule$1.class
new file mode 100644
index 000000000..0051bb506
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule$2.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule$2.class
new file mode 100644
index 000000000..9974b8dbe
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule$2.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule.class
new file mode 100644
index 000000000..19c8865fb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ContributeStringFactory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ContributeStringFactory.class
new file mode 100644
index 000000000..475538dea
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ContributeStringFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInChildFactory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInChildFactory.class
new file mode 100644
index 000000000..a47f2071d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInChildFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInParentFactory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInParentFactory.class
new file mode 100644
index 000000000..7ab4a8ec0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInParentFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ProvideStringFactory.class b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ProvideStringFactory.class
new file mode 100644
index 000000000..80ab0a828
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/classes/test/subcomponent/repeat/RepeatedModule_ProvideStringFactory.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/A_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/A_Factory.java
new file mode 100644
index 000000000..2ef60bf9d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/A_Factory.java
@@ -0,0 +1,19 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum A_Factory implements Factory<A> {
+INSTANCE;
+
+ @Override
+ public A get() {
+ return new A();
+ }
+
+ public static Factory<A> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/AbstractMembersInjectingBaseClass_MembersInjector.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/AbstractMembersInjectingBaseClass_MembersInjector.java
new file mode 100644
index 000000000..bcc27e590
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/AbstractMembersInjectingBaseClass_MembersInjector.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.MembersInjector;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class AbstractMembersInjectingBaseClass_MembersInjector implements MembersInjector<AbstractMembersInjectingBaseClass> {
+ private final Provider<Thing> thingProvider;
+
+ public AbstractMembersInjectingBaseClass_MembersInjector(Provider<Thing> thingProvider) {
+ assert thingProvider != null;
+ this.thingProvider = thingProvider;
+ }
+
+ @Override
+ public void injectMembers(AbstractMembersInjectingBaseClass instance) {
+ if (instance == null) {
+ throw new NullPointerException("Cannot inject members into a null reference");
+ }
+ instance.thing = thingProvider.get();
+ }
+
+ public static MembersInjector<AbstractMembersInjectingBaseClass> create(Provider<Thing> thingProvider) {
+ return new AbstractMembersInjectingBaseClass_MembersInjector(thingProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestStringKey$NestedWrappedKeyCreator_createNestedWrappedKey.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestStringKey$NestedWrappedKeyCreator_createNestedWrappedKey.java
new file mode 100644
index 000000000..8ebfacdd0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestStringKey$NestedWrappedKeyCreator_createNestedWrappedKey.java
@@ -0,0 +1,55 @@
+
+package test;
+
+import javax.annotation.Generated;
+
+@Generated("com.google.auto.value.processor.AutoAnnotationProcessor")
+final class AutoAnnotation_TestStringKey$NestedWrappedKeyCreator_createNestedWrappedKey implements TestStringKey.NestedWrappedKey {
+
+ private final Class<?> value;
+
+ AutoAnnotation_TestStringKey$NestedWrappedKeyCreator_createNestedWrappedKey(
+ Class<?> value) {
+ if (value == null) {
+ throw new NullPointerException("Null value");
+ }
+ this.value = value;
+ }
+
+ @Override
+ public Class<? extends TestStringKey.NestedWrappedKey> annotationType() {
+ return TestStringKey.NestedWrappedKey.class;
+ }
+
+ @Override
+ public Class<?> value() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("@test.TestStringKey.NestedWrappedKey(");
+ sb.append(value);
+ return sb.append(')').toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof TestStringKey.NestedWrappedKey) {
+ TestStringKey.NestedWrappedKey that = (TestStringKey.NestedWrappedKey) o;
+ return (value.equals(that.value()));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return
+ ((127 * 111972721) ^ (value.hashCode()));
+ // 111972721 is "value".hashCode()
+ }
+
+}
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestUnwrappedAnnotationKeyCreator_createTestStringKey.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestUnwrappedAnnotationKeyCreator_createTestStringKey.java
new file mode 100644
index 000000000..29a3ac41c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestUnwrappedAnnotationKeyCreator_createTestStringKey.java
@@ -0,0 +1,90 @@
+
+package test;
+
+import javax.annotation.Generated;
+
+@Generated("com.google.auto.value.processor.AutoAnnotationProcessor")
+final class AutoAnnotation_TestUnwrappedAnnotationKeyCreator_createTestStringKey implements TestStringKey {
+
+ private final String value;
+
+ AutoAnnotation_TestUnwrappedAnnotationKeyCreator_createTestStringKey(
+ String value) {
+ if (value == null) {
+ throw new NullPointerException("Null value");
+ }
+ this.value = value;
+ }
+
+ @Override
+ public Class<? extends TestStringKey> annotationType() {
+ return TestStringKey.class;
+ }
+
+ @Override
+ public String value() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("@test.TestStringKey(");
+ appendQuoted(sb, value);
+ return sb.append(')').toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof TestStringKey) {
+ TestStringKey that = (TestStringKey) o;
+ return (value.equals(that.value()));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return
+ ((127 * 111972721) ^ (value.hashCode()));
+ // 111972721 is "value".hashCode()
+ }
+
+ private static void appendQuoted(StringBuilder sb, String s) {
+ sb.append('"');
+ for (int i = 0; i < s.length(); i++) {
+ appendEscaped(sb, s.charAt(i));
+ }
+ sb.append('"');
+ }
+
+ private static void appendEscaped(StringBuilder sb, char c) {
+ switch (c) {
+ case '\\':
+ case '"':
+ case '\'':
+ sb.append('\\').append(c);
+ break;
+ case '\n':
+ sb.append("\\n");
+ break;
+ case '\r':
+ sb.append("\\r");
+ break;
+ case '\t':
+ sb.append("\\t");
+ break;
+ default:
+ if (c < 0x20) {
+ sb.append(String.format("\\%03o", (int) c));
+ } else if (c < 0x7f || Character.isLetter(c)) {
+ sb.append(c);
+ } else {
+ sb.append(String.format("\\u%04x", (int) c));
+ }
+ break;
+ }
+ }
+}
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestStringKey.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestStringKey.java
new file mode 100644
index 000000000..f156d97a3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestStringKey.java
@@ -0,0 +1,90 @@
+
+package test;
+
+import javax.annotation.Generated;
+
+@Generated("com.google.auto.value.processor.AutoAnnotationProcessor")
+final class AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestStringKey implements TestStringKey {
+
+ private final String value;
+
+ AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestStringKey(
+ String value) {
+ if (value == null) {
+ throw new NullPointerException("Null value");
+ }
+ this.value = value;
+ }
+
+ @Override
+ public Class<? extends TestStringKey> annotationType() {
+ return TestStringKey.class;
+ }
+
+ @Override
+ public String value() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("@test.TestStringKey(");
+ appendQuoted(sb, value);
+ return sb.append(')').toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof TestStringKey) {
+ TestStringKey that = (TestStringKey) o;
+ return (value.equals(that.value()));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return
+ ((127 * 111972721) ^ (value.hashCode()));
+ // 111972721 is "value".hashCode()
+ }
+
+ private static void appendQuoted(StringBuilder sb, String s) {
+ sb.append('"');
+ for (int i = 0; i < s.length(); i++) {
+ appendEscaped(sb, s.charAt(i));
+ }
+ sb.append('"');
+ }
+
+ private static void appendEscaped(StringBuilder sb, char c) {
+ switch (c) {
+ case '\\':
+ case '"':
+ case '\'':
+ sb.append('\\').append(c);
+ break;
+ case '\n':
+ sb.append("\\n");
+ break;
+ case '\r':
+ sb.append("\\r");
+ break;
+ case '\t':
+ sb.append("\\t");
+ break;
+ default:
+ if (c < 0x20) {
+ sb.append(String.format("\\%03o", (int) c));
+ } else if (c < 0x7f || Character.isLetter(c)) {
+ sb.append(c);
+ } else {
+ sb.append(String.format("\\u%04x", (int) c));
+ }
+ break;
+ }
+ }
+}
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey.java
new file mode 100644
index 000000000..73deb28a1
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey.java
@@ -0,0 +1,120 @@
+
+package test;
+
+import java.util.Arrays;
+import javax.annotation.Generated;
+
+@Generated("com.google.auto.value.processor.AutoAnnotationProcessor")
+final class AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey implements TestWrappedAnnotationKey {
+
+ private final TestStringKey value;
+
+ private final int[] integers;
+
+ private final TestClassKey[] annotations;
+
+ private final Class<? extends Number>[] classes;
+
+ AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey(
+ TestStringKey value,
+ int[] integers,
+ TestClassKey[] annotations,
+ Class<? extends Number>[] classes) {
+ if (value == null) {
+ throw new NullPointerException("Null value");
+ }
+ this.value = value;
+ if (integers == null) {
+ throw new NullPointerException("Null integers");
+ }
+ this.integers = integers.clone();
+ if (annotations == null) {
+ throw new NullPointerException("Null annotations");
+ }
+ this.annotations = annotations.clone();
+ if (classes == null) {
+ throw new NullPointerException("Null classes");
+ }
+ this.classes = classes.clone();
+ }
+
+ @Override
+ public Class<? extends TestWrappedAnnotationKey> annotationType() {
+ return TestWrappedAnnotationKey.class;
+ }
+
+ @Override
+ public TestStringKey value() {
+ return value;
+ }
+
+ @Override
+ public int[] integers() {
+ return integers.clone();
+ }
+
+ @Override
+ public TestClassKey[] annotations() {
+ return annotations.clone();
+ }
+
+ @Override
+ public Class<? extends Number>[] classes() {
+ return classes.clone();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("@test.TestWrappedAnnotationKey(");
+ sb.append("value=");
+ sb.append(value);
+ sb.append(", ");
+ sb.append("integers=");
+ sb.append(Arrays.toString(integers));
+ sb.append(", ");
+ sb.append("annotations=");
+ sb.append(Arrays.toString(annotations));
+ sb.append(", ");
+ sb.append("classes=");
+ sb.append(Arrays.toString(classes));
+ return sb.append(')').toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof TestWrappedAnnotationKey) {
+ TestWrappedAnnotationKey that = (TestWrappedAnnotationKey) o;
+ return (value.equals(that.value()))
+ && (Arrays.equals(integers,
+ (that instanceof AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey)
+ ? ((AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey) that).integers
+ : that.integers()))
+ && (Arrays.equals(annotations,
+ (that instanceof AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey)
+ ? ((AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey) that).annotations
+ : that.annotations()))
+ && (Arrays.equals(classes,
+ (that instanceof AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey)
+ ? ((AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey) that).classes
+ : that.classes()));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return
+ ((127 * 111972721) ^ (value.hashCode())) +
+ ((127 * 570074869) ^ (Arrays.hashCode(integers))) +
+ ((127 * -961709276) ^ (Arrays.hashCode(annotations))) +
+ ((127 * 853620774) ^ (Arrays.hashCode(classes)));
+ // 111972721 is "value".hashCode()
+ // 570074869 is "integers".hashCode()
+ // -961709276 is "annotations".hashCode()
+ // 853620774 is "classes".hashCode()
+ }
+
+}
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/B_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/B_Factory.java
new file mode 100644
index 000000000..a4e32538f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/B_Factory.java
@@ -0,0 +1,19 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum B_Factory implements Factory<B> {
+INSTANCE;
+
+ @Override
+ public B get() {
+ return new B();
+ }
+
+ public static Factory<B> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideArrayListOfComparableStringFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideArrayListOfComparableStringFactory.java
new file mode 100644
index 000000000..365c32a6f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideArrayListOfComparableStringFactory.java
@@ -0,0 +1,29 @@
+package test;
+
+import dagger.internal.Factory;
+import java.util.LinkedList;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class BoundedGenericModule_ProvideArrayListOfComparableStringFactory implements Factory<LinkedList<Comparable<String>>> {
+ private final BoundedGenericModule module;
+
+ public BoundedGenericModule_ProvideArrayListOfComparableStringFactory(BoundedGenericModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public LinkedList<Comparable<String>> get() {
+ LinkedList<Comparable<String>> provided = module.provideArrayListOfComparableString();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<LinkedList<Comparable<String>>> create(BoundedGenericModule module) {
+ return new BoundedGenericModule_ProvideArrayListOfComparableStringFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideArrayListStringFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideArrayListStringFactory.java
new file mode 100644
index 000000000..f35ebe7fc
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideArrayListStringFactory.java
@@ -0,0 +1,29 @@
+package test;
+
+import dagger.internal.Factory;
+import java.util.ArrayList;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class BoundedGenericModule_ProvideArrayListStringFactory implements Factory<ArrayList<String>> {
+ private final BoundedGenericModule module;
+
+ public BoundedGenericModule_ProvideArrayListStringFactory(BoundedGenericModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public ArrayList<String> get() {
+ ArrayList<String> provided = module.provideArrayListString();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<ArrayList<String>> create(BoundedGenericModule module) {
+ return new BoundedGenericModule_ProvideArrayListStringFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideDoubleFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideDoubleFactory.java
new file mode 100644
index 000000000..0f28e8e78
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideDoubleFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class BoundedGenericModule_ProvideDoubleFactory implements Factory<Double> {
+ private final BoundedGenericModule module;
+
+ public BoundedGenericModule_ProvideDoubleFactory(BoundedGenericModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Double get() {
+ Double provided = module.provideDouble();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Double> create(BoundedGenericModule module) {
+ return new BoundedGenericModule_ProvideDoubleFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideIntegerFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideIntegerFactory.java
new file mode 100644
index 000000000..ebddc27c7
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideIntegerFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class BoundedGenericModule_ProvideIntegerFactory implements Factory<Integer> {
+ private final BoundedGenericModule module;
+
+ public BoundedGenericModule_ProvideIntegerFactory(BoundedGenericModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Integer get() {
+ Integer provided = module.provideInteger();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Integer> create(BoundedGenericModule module) {
+ return new BoundedGenericModule_ProvideIntegerFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideLinkedListCharSeqFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideLinkedListCharSeqFactory.java
new file mode 100644
index 000000000..3acfb315e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideLinkedListCharSeqFactory.java
@@ -0,0 +1,29 @@
+package test;
+
+import dagger.internal.Factory;
+import java.util.LinkedList;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class BoundedGenericModule_ProvideLinkedListCharSeqFactory implements Factory<LinkedList<CharSequence>> {
+ private final BoundedGenericModule module;
+
+ public BoundedGenericModule_ProvideLinkedListCharSeqFactory(BoundedGenericModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public LinkedList<CharSequence> get() {
+ LinkedList<CharSequence> provided = module.provideLinkedListCharSeq();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<LinkedList<CharSequence>> create(BoundedGenericModule module) {
+ return new BoundedGenericModule_ProvideLinkedListCharSeqFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideLinkedListStringFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideLinkedListStringFactory.java
new file mode 100644
index 000000000..6064287e7
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideLinkedListStringFactory.java
@@ -0,0 +1,29 @@
+package test;
+
+import dagger.internal.Factory;
+import java.util.LinkedList;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class BoundedGenericModule_ProvideLinkedListStringFactory implements Factory<LinkedList<String>> {
+ private final BoundedGenericModule module;
+
+ public BoundedGenericModule_ProvideLinkedListStringFactory(BoundedGenericModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public LinkedList<String> get() {
+ LinkedList<String> provided = module.provideLinkedListString();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<LinkedList<String>> create(BoundedGenericModule module) {
+ return new BoundedGenericModule_ProvideLinkedListStringFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideListOfIntegerFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideListOfIntegerFactory.java
new file mode 100644
index 000000000..44f2d896d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideListOfIntegerFactory.java
@@ -0,0 +1,29 @@
+package test;
+
+import dagger.internal.Factory;
+import java.util.List;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class BoundedGenericModule_ProvideListOfIntegerFactory implements Factory<List<Integer>> {
+ private final BoundedGenericModule module;
+
+ public BoundedGenericModule_ProvideListOfIntegerFactory(BoundedGenericModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public List<Integer> get() {
+ List<Integer> provided = module.provideListOfInteger();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<List<Integer>> create(BoundedGenericModule module) {
+ return new BoundedGenericModule_ProvideListOfIntegerFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideSetOfDoubleFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideSetOfDoubleFactory.java
new file mode 100644
index 000000000..94d569375
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenericModule_ProvideSetOfDoubleFactory.java
@@ -0,0 +1,29 @@
+package test;
+
+import dagger.internal.Factory;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class BoundedGenericModule_ProvideSetOfDoubleFactory implements Factory<Set<Double>> {
+ private final BoundedGenericModule module;
+
+ public BoundedGenericModule_ProvideSetOfDoubleFactory(BoundedGenericModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Set<Double> get() {
+ Set<Double> provided = module.provideSetOfDouble();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Set<Double>> create(BoundedGenericModule module) {
+ return new BoundedGenericModule_ProvideSetOfDoubleFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenerics_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenerics_Factory.java
new file mode 100644
index 000000000..d48cfa5c3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/BoundedGenerics_Factory.java
@@ -0,0 +1,38 @@
+package test;
+
+import dagger.internal.Factory;
+import java.util.List;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class BoundedGenerics_Factory<A extends Number & Comparable<? super A>, B extends List<? extends CharSequence>, C extends List<? super String>, D extends A, E extends Iterable<D>> implements Factory<BoundedGenerics<A, B, C, D, E>> {
+ private final Provider<A> aProvider;
+ private final Provider<B> bProvider;
+ private final Provider<C> cProvider;
+ private final Provider<D> dProvider;
+ private final Provider<E> eProvider;
+
+ public BoundedGenerics_Factory(Provider<A> aProvider, Provider<B> bProvider, Provider<C> cProvider, Provider<D> dProvider, Provider<E> eProvider) {
+ assert aProvider != null;
+ this.aProvider = aProvider;
+ assert bProvider != null;
+ this.bProvider = bProvider;
+ assert cProvider != null;
+ this.cProvider = cProvider;
+ assert dProvider != null;
+ this.dProvider = dProvider;
+ assert eProvider != null;
+ this.eProvider = eProvider;
+ }
+
+ @Override
+ public BoundedGenerics<A, B, C, D, E> get() {
+ return new BoundedGenerics<A, B, C, D, E>(aProvider.get(), bProvider.get(), cProvider.get(), dProvider.get(), eProvider.get());
+ }
+
+ public static <A extends Number & Comparable<? super A>, B extends List<? extends CharSequence>, C extends List<? super String>, D extends A, E extends Iterable<D>> Factory<BoundedGenerics<A, B, C, D, E>> create(Provider<A> aProvider, Provider<B> bProvider, Provider<C> cProvider, Provider<D> dProvider, Provider<E> eProvider) {
+ return new BoundedGenerics_Factory<A, B, C, D, E>(aProvider, bProvider, cProvider, dProvider, eProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildDoubleModule_ProvideDoubleFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildDoubleModule_ProvideDoubleFactory.java
new file mode 100644
index 000000000..093c0048f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildDoubleModule_ProvideDoubleFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ChildDoubleModule_ProvideDoubleFactory implements Factory<Double> {
+ private final ChildDoubleModule module;
+
+ public ChildDoubleModule_ProvideDoubleFactory(ChildDoubleModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Double get() {
+ Double provided = module.provideDouble();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Double> create(ChildDoubleModule module) {
+ return new ChildDoubleModule_ProvideDoubleFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildDoubleModule_ProvideListOfDoubleFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildDoubleModule_ProvideListOfDoubleFactory.java
new file mode 100644
index 000000000..d75e8778b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildDoubleModule_ProvideListOfDoubleFactory.java
@@ -0,0 +1,29 @@
+package test;
+
+import dagger.internal.Factory;
+import java.util.List;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ChildDoubleModule_ProvideListOfDoubleFactory implements Factory<List<Double>> {
+ private final ChildDoubleModule module;
+
+ public ChildDoubleModule_ProvideListOfDoubleFactory(ChildDoubleModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public List<Double> get() {
+ List<Double> provided = module.provideListOfDouble();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<List<Double>> create(ChildDoubleModule module) {
+ return new ChildDoubleModule_ProvideListOfDoubleFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildIntegerModule_ProvideIntegerFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildIntegerModule_ProvideIntegerFactory.java
new file mode 100644
index 000000000..607eafa1e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildIntegerModule_ProvideIntegerFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ChildIntegerModule_ProvideIntegerFactory implements Factory<Integer> {
+ private final ChildIntegerModule module;
+
+ public ChildIntegerModule_ProvideIntegerFactory(ChildIntegerModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Integer get() {
+ Integer provided = module.provideInteger();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Integer> create(ChildIntegerModule module) {
+ return new ChildIntegerModule_ProvideIntegerFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildIntegerModule_ProvideListOfIntegerFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildIntegerModule_ProvideListOfIntegerFactory.java
new file mode 100644
index 000000000..23ba97f49
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ChildIntegerModule_ProvideListOfIntegerFactory.java
@@ -0,0 +1,29 @@
+package test;
+
+import dagger.internal.Factory;
+import java.util.List;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ChildIntegerModule_ProvideListOfIntegerFactory implements Factory<List<Integer>> {
+ private final ChildIntegerModule module;
+
+ public ChildIntegerModule_ProvideListOfIntegerFactory(ChildIntegerModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public List<Integer> get() {
+ List<Integer> provided = module.provideListOfInteger();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<List<Integer>> create(ChildIntegerModule module) {
+ return new ChildIntegerModule_ProvideListOfIntegerFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ComplexGenerics_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ComplexGenerics_Factory.java
new file mode 100644
index 000000000..60d33693d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ComplexGenerics_Factory.java
@@ -0,0 +1,38 @@
+package test;
+
+import dagger.internal.DoubleCheckLazy;
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ComplexGenerics_Factory implements Factory<ComplexGenerics> {
+ private final Provider<Generic2<Generic<A>>> g2gaAndG2gaLazyProvider;
+ private final Provider<Generic2<Generic<B>>> g2gbAndG2gbLazyProvider;
+ private final Provider<Generic2<A>> g2aProvider;
+ private final Provider<Generic<Generic2<A>>> gg2aProvider;
+ private final Provider<Generic<Generic2<B>>> gg2bProvider;
+
+ public ComplexGenerics_Factory(Provider<Generic2<Generic<A>>> g2gaAndG2gaLazyProvider, Provider<Generic2<Generic<B>>> g2gbAndG2gbLazyProvider, Provider<Generic2<A>> g2aProvider, Provider<Generic<Generic2<A>>> gg2aProvider, Provider<Generic<Generic2<B>>> gg2bProvider) {
+ assert g2gaAndG2gaLazyProvider != null;
+ this.g2gaAndG2gaLazyProvider = g2gaAndG2gaLazyProvider;
+ assert g2gbAndG2gbLazyProvider != null;
+ this.g2gbAndG2gbLazyProvider = g2gbAndG2gbLazyProvider;
+ assert g2aProvider != null;
+ this.g2aProvider = g2aProvider;
+ assert gg2aProvider != null;
+ this.gg2aProvider = gg2aProvider;
+ assert gg2bProvider != null;
+ this.gg2bProvider = gg2bProvider;
+ }
+
+ @Override
+ public ComplexGenerics get() {
+ return new ComplexGenerics(g2gaAndG2gaLazyProvider.get(), DoubleCheckLazy.create(g2gaAndG2gaLazyProvider), g2gaAndG2gaLazyProvider, g2gbAndG2gbLazyProvider.get(), DoubleCheckLazy.create(g2gbAndG2gbLazyProvider), g2gbAndG2gbLazyProvider, g2aProvider.get(), gg2aProvider.get(), gg2bProvider.get());
+ }
+
+ public static Factory<ComplexGenerics> create(Provider<Generic2<Generic<A>>> g2gaAndG2gaLazyProvider, Provider<Generic2<Generic<B>>> g2gbAndG2gbLazyProvider, Provider<Generic2<A>> g2aProvider, Provider<Generic<Generic2<A>>> gg2aProvider, Provider<Generic<Generic2<B>>> gg2bProvider) {
+ return new ComplexGenerics_Factory(g2gaAndG2gaLazyProvider, g2gbAndG2gbLazyProvider, g2aProvider, gg2aProvider, gg2bProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerBasicAbstractClassComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerBasicAbstractClassComponent.java
new file mode 100644
index 000000000..2aaa08650
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerBasicAbstractClassComponent.java
@@ -0,0 +1,341 @@
+package test;
+
+import dagger.Lazy;
+import dagger.MembersInjector;
+import dagger.internal.DoubleCheckLazy;
+import dagger.internal.MembersInjectors;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.sub.OtherThing;
+import test.sub.OtherThing_Factory;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerBasicAbstractClassComponent extends BasicAbstractClassComponent {
+ private Provider<OtherThing> otherThingProvider;
+ private Provider<Thing> thingProvider;
+ private MembersInjector<InjectedThing> injectedThingMembersInjector;
+ private Provider<InjectedThing> injectedThingProvider;
+ private MembersInjector<AbstractMembersInjectingBaseClass> abstractMembersInjectingBaseClassMembersInjector;
+ private MembersInjector<AbstractMiddleClassWithoutMembers> abstractMiddleClassWithoutMembersMembersInjector;
+ private MembersInjector<TypeWithInheritedMembersInjection> typeWithInheritedMembersInjectionMembersInjector;
+ private Provider<TypeWithInheritedMembersInjection> typeWithInheritedMembersInjectionProvider;
+
+ private DaggerBasicAbstractClassComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static BasicAbstractClassComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.otherThingProvider = OtherThing_Factory.create(PrimitivesModule_ProvideIntFactory.create());
+ this.thingProvider = Thing_Factory.create(otherThingProvider);
+ this.injectedThingMembersInjector = InjectedThing_MembersInjector.create(PrimitivesModule_ProvideByteFactory.create(), PrimitivesModule_ProvideCharFactory.create(), PrimitivesModule_ProvideShortFactory.create(), PrimitivesModule_ProvideIntFactory.create(), PrimitivesModule_ProvideLongFactory.create(), PrimitivesModule_ProvideBooleanFactory.create(), PrimitivesModule_ProvideFloatFactory.create(), PrimitivesModule_BoundDoubleFactory.create(), PrimitivesModule_ProvideByteArrayFactory.create(), PrimitivesModule_ProvideCharArrayFactory.create(), PrimitivesModule_ProvideShortArrayFactory.create(), PrimitivesModule_ProvideIntArrayFactory.create(), PrimitivesModule_ProvideLongArrayFactory.create(), PrimitivesModule_ProvideBooleanArrayFactory.create(), PrimitivesModule_ProvideFloatArrayFactory.create(), PrimitivesModule_BoundDoubleArrayFactory.create(), thingProvider, (MembersInjector) MembersInjectors.noOp());
+ this.injectedThingProvider = InjectedThing_Factory.create(injectedThingMembersInjector, PrimitivesModule_ProvideByteFactory.create(), PrimitivesModule_ProvideCharFactory.create(), PrimitivesModule_ProvideShortFactory.create(), PrimitivesModule_ProvideIntFactory.create(), PrimitivesModule_ProvideLongFactory.create(), PrimitivesModule_ProvideBooleanFactory.create(), PrimitivesModule_ProvideFloatFactory.create(), PrimitivesModule_BoundDoubleFactory.create(), PrimitivesModule_ProvideByteArrayFactory.create(), PrimitivesModule_ProvideCharArrayFactory.create(), PrimitivesModule_ProvideShortArrayFactory.create(), PrimitivesModule_ProvideIntArrayFactory.create(), PrimitivesModule_ProvideLongArrayFactory.create(), PrimitivesModule_ProvideBooleanArrayFactory.create(), PrimitivesModule_ProvideFloatArrayFactory.create(), PrimitivesModule_BoundDoubleArrayFactory.create(), thingProvider, (MembersInjector) MembersInjectors.noOp());
+ this.abstractMembersInjectingBaseClassMembersInjector = AbstractMembersInjectingBaseClass_MembersInjector.create(thingProvider);
+ this.abstractMiddleClassWithoutMembersMembersInjector = MembersInjectors.delegatingTo(abstractMembersInjectingBaseClassMembersInjector);
+ this.typeWithInheritedMembersInjectionMembersInjector = MembersInjectors.delegatingTo(abstractMiddleClassWithoutMembersMembersInjector);
+ this.typeWithInheritedMembersInjectionProvider = TypeWithInheritedMembersInjection_Factory.create(typeWithInheritedMembersInjectionMembersInjector);
+ }
+
+ @Override
+ public Thing instance() {
+ return thingProvider.get();
+ }
+
+ @Override
+ public Provider<Thing> provider() {
+ return thingProvider;
+ }
+
+ @Override
+ public Lazy<Thing> lazy() {
+ return DoubleCheckLazy.create(thingProvider);
+ }
+
+ @Override
+ public MembersInjector<Thing> membersInjector() {
+ return MembersInjectors.noOp();
+ }
+
+ @Override
+ public void injectMembers(Thing t) {
+ MembersInjectors.noOp().injectMembers(t);
+ }
+
+ @Override
+ public Thing injectMembersAndReturn(Thing t) {
+ MembersInjectors.noOp().injectMembers(t);
+ return t;
+ }
+
+ @Override
+ public byte getByte() {
+ return PrimitivesModule_ProvideByteFactory.create().get();
+ }
+
+ @Override
+ public char getChar() {
+ return PrimitivesModule_ProvideCharFactory.create().get();
+ }
+
+ @Override
+ public short getShort() {
+ return PrimitivesModule_ProvideShortFactory.create().get();
+ }
+
+ @Override
+ public int getInt() {
+ return PrimitivesModule_ProvideIntFactory.create().get();
+ }
+
+ @Override
+ public long getLong() {
+ return PrimitivesModule_ProvideLongFactory.create().get();
+ }
+
+ @Override
+ public boolean getBoolean() {
+ return PrimitivesModule_ProvideBooleanFactory.create().get();
+ }
+
+ @Override
+ public float getFloat() {
+ return PrimitivesModule_ProvideFloatFactory.create().get();
+ }
+
+ @Override
+ public double getDouble() {
+ return PrimitivesModule_BoundDoubleFactory.create().get();
+ }
+
+ @Override
+ public Byte getBoxedByte() {
+ return PrimitivesModule_ProvideByteFactory.create().get();
+ }
+
+ @Override
+ public Character getBoxedChar() {
+ return PrimitivesModule_ProvideCharFactory.create().get();
+ }
+
+ @Override
+ public Short getBoxedShort() {
+ return PrimitivesModule_ProvideShortFactory.create().get();
+ }
+
+ @Override
+ public Integer getBoxedInt() {
+ return PrimitivesModule_ProvideIntFactory.create().get();
+ }
+
+ @Override
+ public Long getBoxedLong() {
+ return PrimitivesModule_ProvideLongFactory.create().get();
+ }
+
+ @Override
+ public Boolean getBoxedBoolean() {
+ return PrimitivesModule_ProvideBooleanFactory.create().get();
+ }
+
+ @Override
+ public Float getBoxedFloat() {
+ return PrimitivesModule_ProvideFloatFactory.create().get();
+ }
+
+ @Override
+ public Double getBoxedDouble() {
+ return PrimitivesModule_BoundDoubleFactory.create().get();
+ }
+
+ @Override
+ public Provider<Byte> getByteProvider() {
+ return PrimitivesModule_ProvideByteFactory.create();
+ }
+
+ @Override
+ public Provider<Character> getCharProvider() {
+ return PrimitivesModule_ProvideCharFactory.create();
+ }
+
+ @Override
+ public Provider<Short> getShortProvider() {
+ return PrimitivesModule_ProvideShortFactory.create();
+ }
+
+ @Override
+ public Provider<Integer> getIntProvider() {
+ return PrimitivesModule_ProvideIntFactory.create();
+ }
+
+ @Override
+ public Provider<Long> getLongProvider() {
+ return PrimitivesModule_ProvideLongFactory.create();
+ }
+
+ @Override
+ public Provider<Boolean> getBooleanProvider() {
+ return PrimitivesModule_ProvideBooleanFactory.create();
+ }
+
+ @Override
+ public Provider<Float> getFloatProvider() {
+ return PrimitivesModule_ProvideFloatFactory.create();
+ }
+
+ @Override
+ public Provider<Double> getDoubleProvider() {
+ return PrimitivesModule_BoundDoubleFactory.create();
+ }
+
+ @Override
+ public byte[] getByteArray() {
+ return PrimitivesModule_ProvideByteArrayFactory.create().get();
+ }
+
+ @Override
+ public char[] getCharArray() {
+ return PrimitivesModule_ProvideCharArrayFactory.create().get();
+ }
+
+ @Override
+ public short[] getShortArray() {
+ return PrimitivesModule_ProvideShortArrayFactory.create().get();
+ }
+
+ @Override
+ public int[] getIntArray() {
+ return PrimitivesModule_ProvideIntArrayFactory.create().get();
+ }
+
+ @Override
+ public long[] getLongArray() {
+ return PrimitivesModule_ProvideLongArrayFactory.create().get();
+ }
+
+ @Override
+ public boolean[] getBooleanArray() {
+ return PrimitivesModule_ProvideBooleanArrayFactory.create().get();
+ }
+
+ @Override
+ public float[] getFloatArray() {
+ return PrimitivesModule_ProvideFloatArrayFactory.create().get();
+ }
+
+ @Override
+ public double[] getDoubleArray() {
+ return PrimitivesModule_BoundDoubleArrayFactory.create().get();
+ }
+
+ @Override
+ public Provider<byte[]> getByteArrayProvider() {
+ return PrimitivesModule_ProvideByteArrayFactory.create();
+ }
+
+ @Override
+ public Provider<char[]> getCharArrayProvider() {
+ return PrimitivesModule_ProvideCharArrayFactory.create();
+ }
+
+ @Override
+ public Provider<short[]> getShortArrayProvider() {
+ return PrimitivesModule_ProvideShortArrayFactory.create();
+ }
+
+ @Override
+ public Provider<int[]> getIntArrayProvider() {
+ return PrimitivesModule_ProvideIntArrayFactory.create();
+ }
+
+ @Override
+ public Provider<long[]> getLongArrayProvider() {
+ return PrimitivesModule_ProvideLongArrayFactory.create();
+ }
+
+ @Override
+ public Provider<boolean[]> getBooleanArrayProvider() {
+ return PrimitivesModule_ProvideBooleanArrayFactory.create();
+ }
+
+ @Override
+ public Provider<float[]> getFloatArrayProvider() {
+ return PrimitivesModule_ProvideFloatArrayFactory.create();
+ }
+
+ @Override
+ public Provider<double[]> getDoubleArrayProvider() {
+ return PrimitivesModule_BoundDoubleArrayFactory.create();
+ }
+
+ @Override
+ public Object noOpMembersInjection(Object obviouslyDoesNotHaveMembersToInject) {
+ MembersInjectors.noOp().injectMembers(obviouslyDoesNotHaveMembersToInject);
+ return obviouslyDoesNotHaveMembersToInject;
+ }
+
+ @Override
+ public Thing thing() {
+ return thingProvider.get();
+ }
+
+ @Override
+ public InjectedThing injectedThing() {
+ return injectedThingProvider.get();
+ }
+
+ @Override
+ public Provider<InjectedThing> injectedThingProvider() {
+ return injectedThingProvider;
+ }
+
+ @Override
+ public Lazy<InjectedThing> lazyInjectedThing() {
+ return DoubleCheckLazy.create(injectedThingProvider);
+ }
+
+ @Override
+ public MembersInjector<InjectedThing> injectedThingMembersInjector() {
+ return injectedThingMembersInjector;
+ }
+
+ @Override
+ public TypeWithInheritedMembersInjection typeWithInheritedMembersInjection() {
+ return typeWithInheritedMembersInjectionProvider.get();
+ }
+
+ @Override
+ public MembersInjector<TypeWithInheritedMembersInjection> typeWithInheritedMembersInjectionMembersInjector() {
+ return typeWithInheritedMembersInjectionMembersInjector;
+ }
+
+ public static final class Builder {
+ private PrimitivesModule primitivesModule;
+
+ private Builder() {
+ }
+
+ public BasicAbstractClassComponent build() {
+ if (primitivesModule == null) {
+ this.primitivesModule = new PrimitivesModule();
+ }
+ return new DaggerBasicAbstractClassComponent(this);
+ }
+
+ public Builder primitivesModule(PrimitivesModule primitivesModule) {
+ if (primitivesModule == null) {
+ throw new NullPointerException("primitivesModule");
+ }
+ this.primitivesModule = primitivesModule;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerBasicComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerBasicComponent.java
new file mode 100644
index 000000000..a72440a19
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerBasicComponent.java
@@ -0,0 +1,341 @@
+package test;
+
+import dagger.Lazy;
+import dagger.MembersInjector;
+import dagger.internal.DoubleCheckLazy;
+import dagger.internal.MembersInjectors;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.sub.OtherThing;
+import test.sub.OtherThing_Factory;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerBasicComponent implements BasicComponent {
+ private Provider<OtherThing> otherThingProvider;
+ private Provider<Thing> thingProvider;
+ private MembersInjector<InjectedThing> injectedThingMembersInjector;
+ private Provider<InjectedThing> injectedThingProvider;
+ private MembersInjector<AbstractMembersInjectingBaseClass> abstractMembersInjectingBaseClassMembersInjector;
+ private MembersInjector<AbstractMiddleClassWithoutMembers> abstractMiddleClassWithoutMembersMembersInjector;
+ private MembersInjector<TypeWithInheritedMembersInjection> typeWithInheritedMembersInjectionMembersInjector;
+ private Provider<TypeWithInheritedMembersInjection> typeWithInheritedMembersInjectionProvider;
+
+ private DaggerBasicComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static BasicComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.otherThingProvider = OtherThing_Factory.create(PrimitivesModule_ProvideIntFactory.create());
+ this.thingProvider = Thing_Factory.create(otherThingProvider);
+ this.injectedThingMembersInjector = InjectedThing_MembersInjector.create(PrimitivesModule_ProvideByteFactory.create(), PrimitivesModule_ProvideCharFactory.create(), PrimitivesModule_ProvideShortFactory.create(), PrimitivesModule_ProvideIntFactory.create(), PrimitivesModule_ProvideLongFactory.create(), PrimitivesModule_ProvideBooleanFactory.create(), PrimitivesModule_ProvideFloatFactory.create(), PrimitivesModule_BoundDoubleFactory.create(), PrimitivesModule_ProvideByteArrayFactory.create(), PrimitivesModule_ProvideCharArrayFactory.create(), PrimitivesModule_ProvideShortArrayFactory.create(), PrimitivesModule_ProvideIntArrayFactory.create(), PrimitivesModule_ProvideLongArrayFactory.create(), PrimitivesModule_ProvideBooleanArrayFactory.create(), PrimitivesModule_ProvideFloatArrayFactory.create(), PrimitivesModule_BoundDoubleArrayFactory.create(), thingProvider, (MembersInjector) MembersInjectors.noOp());
+ this.injectedThingProvider = InjectedThing_Factory.create(injectedThingMembersInjector, PrimitivesModule_ProvideByteFactory.create(), PrimitivesModule_ProvideCharFactory.create(), PrimitivesModule_ProvideShortFactory.create(), PrimitivesModule_ProvideIntFactory.create(), PrimitivesModule_ProvideLongFactory.create(), PrimitivesModule_ProvideBooleanFactory.create(), PrimitivesModule_ProvideFloatFactory.create(), PrimitivesModule_BoundDoubleFactory.create(), PrimitivesModule_ProvideByteArrayFactory.create(), PrimitivesModule_ProvideCharArrayFactory.create(), PrimitivesModule_ProvideShortArrayFactory.create(), PrimitivesModule_ProvideIntArrayFactory.create(), PrimitivesModule_ProvideLongArrayFactory.create(), PrimitivesModule_ProvideBooleanArrayFactory.create(), PrimitivesModule_ProvideFloatArrayFactory.create(), PrimitivesModule_BoundDoubleArrayFactory.create(), thingProvider, (MembersInjector) MembersInjectors.noOp());
+ this.abstractMembersInjectingBaseClassMembersInjector = AbstractMembersInjectingBaseClass_MembersInjector.create(thingProvider);
+ this.abstractMiddleClassWithoutMembersMembersInjector = MembersInjectors.delegatingTo(abstractMembersInjectingBaseClassMembersInjector);
+ this.typeWithInheritedMembersInjectionMembersInjector = MembersInjectors.delegatingTo(abstractMiddleClassWithoutMembersMembersInjector);
+ this.typeWithInheritedMembersInjectionProvider = TypeWithInheritedMembersInjection_Factory.create(typeWithInheritedMembersInjectionMembersInjector);
+ }
+
+ @Override
+ public Thing instance() {
+ return thingProvider.get();
+ }
+
+ @Override
+ public Provider<Thing> provider() {
+ return thingProvider;
+ }
+
+ @Override
+ public Lazy<Thing> lazy() {
+ return DoubleCheckLazy.create(thingProvider);
+ }
+
+ @Override
+ public MembersInjector<Thing> membersInjector() {
+ return MembersInjectors.noOp();
+ }
+
+ @Override
+ public void injectMembers(Thing t) {
+ MembersInjectors.noOp().injectMembers(t);
+ }
+
+ @Override
+ public Thing injectMembersAndReturn(Thing t) {
+ MembersInjectors.noOp().injectMembers(t);
+ return t;
+ }
+
+ @Override
+ public byte getByte() {
+ return PrimitivesModule_ProvideByteFactory.create().get();
+ }
+
+ @Override
+ public char getChar() {
+ return PrimitivesModule_ProvideCharFactory.create().get();
+ }
+
+ @Override
+ public short getShort() {
+ return PrimitivesModule_ProvideShortFactory.create().get();
+ }
+
+ @Override
+ public int getInt() {
+ return PrimitivesModule_ProvideIntFactory.create().get();
+ }
+
+ @Override
+ public long getLong() {
+ return PrimitivesModule_ProvideLongFactory.create().get();
+ }
+
+ @Override
+ public boolean getBoolean() {
+ return PrimitivesModule_ProvideBooleanFactory.create().get();
+ }
+
+ @Override
+ public float getFloat() {
+ return PrimitivesModule_ProvideFloatFactory.create().get();
+ }
+
+ @Override
+ public double getDouble() {
+ return PrimitivesModule_BoundDoubleFactory.create().get();
+ }
+
+ @Override
+ public Byte getBoxedByte() {
+ return PrimitivesModule_ProvideByteFactory.create().get();
+ }
+
+ @Override
+ public Character getBoxedChar() {
+ return PrimitivesModule_ProvideCharFactory.create().get();
+ }
+
+ @Override
+ public Short getBoxedShort() {
+ return PrimitivesModule_ProvideShortFactory.create().get();
+ }
+
+ @Override
+ public Integer getBoxedInt() {
+ return PrimitivesModule_ProvideIntFactory.create().get();
+ }
+
+ @Override
+ public Long getBoxedLong() {
+ return PrimitivesModule_ProvideLongFactory.create().get();
+ }
+
+ @Override
+ public Boolean getBoxedBoolean() {
+ return PrimitivesModule_ProvideBooleanFactory.create().get();
+ }
+
+ @Override
+ public Float getBoxedFloat() {
+ return PrimitivesModule_ProvideFloatFactory.create().get();
+ }
+
+ @Override
+ public Double getBoxedDouble() {
+ return PrimitivesModule_BoundDoubleFactory.create().get();
+ }
+
+ @Override
+ public Provider<Byte> getByteProvider() {
+ return PrimitivesModule_ProvideByteFactory.create();
+ }
+
+ @Override
+ public Provider<Character> getCharProvider() {
+ return PrimitivesModule_ProvideCharFactory.create();
+ }
+
+ @Override
+ public Provider<Short> getShortProvider() {
+ return PrimitivesModule_ProvideShortFactory.create();
+ }
+
+ @Override
+ public Provider<Integer> getIntProvider() {
+ return PrimitivesModule_ProvideIntFactory.create();
+ }
+
+ @Override
+ public Provider<Long> getLongProvider() {
+ return PrimitivesModule_ProvideLongFactory.create();
+ }
+
+ @Override
+ public Provider<Boolean> getBooleanProvider() {
+ return PrimitivesModule_ProvideBooleanFactory.create();
+ }
+
+ @Override
+ public Provider<Float> getFloatProvider() {
+ return PrimitivesModule_ProvideFloatFactory.create();
+ }
+
+ @Override
+ public Provider<Double> getDoubleProvider() {
+ return PrimitivesModule_BoundDoubleFactory.create();
+ }
+
+ @Override
+ public byte[] getByteArray() {
+ return PrimitivesModule_ProvideByteArrayFactory.create().get();
+ }
+
+ @Override
+ public char[] getCharArray() {
+ return PrimitivesModule_ProvideCharArrayFactory.create().get();
+ }
+
+ @Override
+ public short[] getShortArray() {
+ return PrimitivesModule_ProvideShortArrayFactory.create().get();
+ }
+
+ @Override
+ public int[] getIntArray() {
+ return PrimitivesModule_ProvideIntArrayFactory.create().get();
+ }
+
+ @Override
+ public long[] getLongArray() {
+ return PrimitivesModule_ProvideLongArrayFactory.create().get();
+ }
+
+ @Override
+ public boolean[] getBooleanArray() {
+ return PrimitivesModule_ProvideBooleanArrayFactory.create().get();
+ }
+
+ @Override
+ public float[] getFloatArray() {
+ return PrimitivesModule_ProvideFloatArrayFactory.create().get();
+ }
+
+ @Override
+ public double[] getDoubleArray() {
+ return PrimitivesModule_BoundDoubleArrayFactory.create().get();
+ }
+
+ @Override
+ public Provider<byte[]> getByteArrayProvider() {
+ return PrimitivesModule_ProvideByteArrayFactory.create();
+ }
+
+ @Override
+ public Provider<char[]> getCharArrayProvider() {
+ return PrimitivesModule_ProvideCharArrayFactory.create();
+ }
+
+ @Override
+ public Provider<short[]> getShortArrayProvider() {
+ return PrimitivesModule_ProvideShortArrayFactory.create();
+ }
+
+ @Override
+ public Provider<int[]> getIntArrayProvider() {
+ return PrimitivesModule_ProvideIntArrayFactory.create();
+ }
+
+ @Override
+ public Provider<long[]> getLongArrayProvider() {
+ return PrimitivesModule_ProvideLongArrayFactory.create();
+ }
+
+ @Override
+ public Provider<boolean[]> getBooleanArrayProvider() {
+ return PrimitivesModule_ProvideBooleanArrayFactory.create();
+ }
+
+ @Override
+ public Provider<float[]> getFloatArrayProvider() {
+ return PrimitivesModule_ProvideFloatArrayFactory.create();
+ }
+
+ @Override
+ public Provider<double[]> getDoubleArrayProvider() {
+ return PrimitivesModule_BoundDoubleArrayFactory.create();
+ }
+
+ @Override
+ public Object noOpMembersInjection(Object obviouslyDoesNotHaveMembersToInject) {
+ MembersInjectors.noOp().injectMembers(obviouslyDoesNotHaveMembersToInject);
+ return obviouslyDoesNotHaveMembersToInject;
+ }
+
+ @Override
+ public Thing thing() {
+ return thingProvider.get();
+ }
+
+ @Override
+ public InjectedThing injectedThing() {
+ return injectedThingProvider.get();
+ }
+
+ @Override
+ public Provider<InjectedThing> injectedThingProvider() {
+ return injectedThingProvider;
+ }
+
+ @Override
+ public Lazy<InjectedThing> lazyInjectedThing() {
+ return DoubleCheckLazy.create(injectedThingProvider);
+ }
+
+ @Override
+ public MembersInjector<InjectedThing> injectedThingMembersInjector() {
+ return injectedThingMembersInjector;
+ }
+
+ @Override
+ public TypeWithInheritedMembersInjection typeWithInheritedMembersInjection() {
+ return typeWithInheritedMembersInjectionProvider.get();
+ }
+
+ @Override
+ public MembersInjector<TypeWithInheritedMembersInjection> typeWithInheritedMembersInjectionMembersInjector() {
+ return typeWithInheritedMembersInjectionMembersInjector;
+ }
+
+ public static final class Builder {
+ private PrimitivesModule primitivesModule;
+
+ private Builder() {
+ }
+
+ public BasicComponent build() {
+ if (primitivesModule == null) {
+ this.primitivesModule = new PrimitivesModule();
+ }
+ return new DaggerBasicComponent(this);
+ }
+
+ public Builder primitivesModule(PrimitivesModule primitivesModule) {
+ if (primitivesModule == null) {
+ throw new NullPointerException("primitivesModule");
+ }
+ this.primitivesModule = primitivesModule;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerBoundedGenericComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerBoundedGenericComponent.java
new file mode 100644
index 000000000..4ce853ed6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerBoundedGenericComponent.java
@@ -0,0 +1,81 @@
+package test;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerBoundedGenericComponent implements BoundedGenericComponent {
+ private Provider<Integer> provideIntegerProvider;
+ private Provider<ArrayList<String>> provideArrayListStringProvider;
+ private Provider<LinkedList<CharSequence>> provideLinkedListCharSeqProvider;
+ private Provider<List<Integer>> provideListOfIntegerProvider;
+ private Provider<BoundedGenerics<Integer, ArrayList<String>, LinkedList<CharSequence>, Integer, List<Integer>>> boundedGenericsProvider;
+ private Provider<Double> provideDoubleProvider;
+ private Provider<LinkedList<String>> provideLinkedListStringProvider;
+ private Provider<LinkedList<Comparable<String>>> provideArrayListOfComparableStringProvider;
+ private Provider<Set<Double>> provideSetOfDoubleProvider;
+ private Provider<BoundedGenerics<Double, LinkedList<String>, LinkedList<Comparable<String>>, Double, Set<Double>>> boundedGenericsProvider1;
+
+ private DaggerBoundedGenericComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static BoundedGenericComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.provideIntegerProvider = BoundedGenericModule_ProvideIntegerFactory.create(builder.boundedGenericModule);
+ this.provideArrayListStringProvider = BoundedGenericModule_ProvideArrayListStringFactory.create(builder.boundedGenericModule);
+ this.provideLinkedListCharSeqProvider = BoundedGenericModule_ProvideLinkedListCharSeqFactory.create(builder.boundedGenericModule);
+ this.provideListOfIntegerProvider = BoundedGenericModule_ProvideListOfIntegerFactory.create(builder.boundedGenericModule);
+ this.boundedGenericsProvider = BoundedGenerics_Factory.create(provideIntegerProvider, provideArrayListStringProvider, provideLinkedListCharSeqProvider, provideIntegerProvider, provideListOfIntegerProvider);
+ this.provideDoubleProvider = BoundedGenericModule_ProvideDoubleFactory.create(builder.boundedGenericModule);
+ this.provideLinkedListStringProvider = BoundedGenericModule_ProvideLinkedListStringFactory.create(builder.boundedGenericModule);
+ this.provideArrayListOfComparableStringProvider = BoundedGenericModule_ProvideArrayListOfComparableStringFactory.create(builder.boundedGenericModule);
+ this.provideSetOfDoubleProvider = BoundedGenericModule_ProvideSetOfDoubleFactory.create(builder.boundedGenericModule);
+ this.boundedGenericsProvider1 = BoundedGenerics_Factory.create(provideDoubleProvider, provideLinkedListStringProvider, provideArrayListOfComparableStringProvider, provideDoubleProvider, provideSetOfDoubleProvider);
+ }
+
+ @Override
+ public BoundedGenerics<Integer, ArrayList<String>, LinkedList<CharSequence>, Integer, List<Integer>> bounds1() {
+ return boundedGenericsProvider.get();
+ }
+
+ @Override
+ public BoundedGenerics<Double, LinkedList<String>, LinkedList<Comparable<String>>, Double, Set<Double>> bounds2() {
+ return boundedGenericsProvider1.get();
+ }
+
+ public static final class Builder {
+ private BoundedGenericModule boundedGenericModule;
+
+ private Builder() {
+ }
+
+ public BoundedGenericComponent build() {
+ if (boundedGenericModule == null) {
+ this.boundedGenericModule = new BoundedGenericModule();
+ }
+ return new DaggerBoundedGenericComponent(this);
+ }
+
+ public Builder boundedGenericModule(BoundedGenericModule boundedGenericModule) {
+ if (boundedGenericModule == null) {
+ throw new NullPointerException("boundedGenericModule");
+ }
+ this.boundedGenericModule = boundedGenericModule;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerComponentDependsOnGeneratedCode.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerComponentDependsOnGeneratedCode.java
new file mode 100644
index 000000000..848f7b6dd
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerComponentDependsOnGeneratedCode.java
@@ -0,0 +1,41 @@
+package test;
+
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerComponentDependsOnGeneratedCode implements ComponentDependsOnGeneratedCode {
+ private Provider<NeedsFactory> needsFactoryProvider;
+
+ private DaggerComponentDependsOnGeneratedCode(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static ComponentDependsOnGeneratedCode create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.needsFactoryProvider = NeedsFactory_Factory.create(NeedsFactory_SomethingFactory_Factory.create());
+ }
+
+ @Override
+ public NeedsFactory needsFactory() {
+ return needsFactoryProvider.get();
+ }
+
+ public static final class Builder {
+ private Builder() {
+ }
+
+ public ComponentDependsOnGeneratedCode build() {
+ return new DaggerComponentDependsOnGeneratedCode(this);
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerGenericComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerGenericComponent.java
new file mode 100644
index 000000000..3e7848939
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerGenericComponent.java
@@ -0,0 +1,193 @@
+package test;
+
+import dagger.MembersInjector;
+import dagger.internal.MembersInjectors;
+import java.util.List;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.sub.DaggerGenericComponent_PackageProxy;
+import test.sub.Exposed;
+import test.sub.Exposed_Factory;
+import test.sub.Exposed_MembersInjector;
+import test.sub.OtherThing;
+import test.sub.OtherThing_Factory;
+import test.sub.PackagePrivateContainer$PublicEnclosed_Factory;
+import test.sub.PackagePrivate_Factory;
+import test.sub.PublicSubclass;
+import test.sub.PublicSubclass_Factory;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerGenericComponent implements GenericComponent {
+ private Provider<Generic<A>> genericProvider;
+ private Provider<ReferencesGeneric> referencesGenericProvider;
+ private Provider<Integer> provideIntegerProvider;
+ private Provider<OtherThing> otherThingProvider;
+ private Provider<Thing> thingProvider;
+ private Provider<GenericDoubleReferences<A>> genericDoubleReferencesProvider;
+ private Provider<GenericDoubleReferences<B>> genericDoubleReferencesProvider1;
+ private Provider<Generic2<Generic<A>>> generic2Provider;
+ private Provider<Generic<B>> genericProvider1;
+ private Provider<Generic2<Generic<B>>> generic2Provider1;
+ private Provider<Generic2<A>> generic2Provider2;
+ private Provider<Generic<Generic2<A>>> genericProvider2;
+ private Provider<Generic2<B>> generic2Provider3;
+ private Provider<Generic<Generic2<B>>> genericProvider3;
+ private Provider<ComplexGenerics> complexGenericsProvider;
+ private MembersInjector<GenericParent<A, B>> genericParentMembersInjector;
+ private MembersInjector<GenericChild<A>> genericChildMembersInjector;
+ private MembersInjector<GenericParent<B, B>> genericParentMembersInjector1;
+ private MembersInjector<GenericChild<B>> genericChildMembersInjector1;
+ private final DaggerGenericComponent_PackageProxy test_sub_Proxy = new DaggerGenericComponent_PackageProxy();
+ private MembersInjector<Exposed> exposedMembersInjector;
+ private Provider<Exposed> exposedProvider;
+ private Provider<PublicSubclass> publicSubclassProvider;
+ private Provider<List<Integer>> provideListOfIntegerProvider;
+ private Provider<Iterable<Integer>> provideIterableOfAWithCProvider;
+ private Provider<Double> provideDoubleProvider;
+ private Provider<List<Double>> provideListOfDoubleProvider;
+ private Provider<Iterable<Double>> provideIterableOfAWithCProvider1;
+
+ private DaggerGenericComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static GenericComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.genericProvider = Generic_Factory.create(A_Factory.create());
+ this.referencesGenericProvider = ReferencesGeneric_Factory.create(genericProvider);
+ this.provideIntegerProvider = ChildIntegerModule_ProvideIntegerFactory.create(builder.childIntegerModule);
+ this.otherThingProvider = OtherThing_Factory.create(provideIntegerProvider);
+ this.thingProvider = Thing_Factory.create(otherThingProvider);
+ this.genericDoubleReferencesProvider = GenericDoubleReferences_Factory.create(A_Factory.create(), thingProvider);
+ this.genericDoubleReferencesProvider1 = GenericDoubleReferences_Factory.create(B_Factory.create(), thingProvider);
+ this.generic2Provider = Generic2_Factory.create(genericProvider);
+ this.genericProvider1 = Generic_Factory.create(B_Factory.create());
+ this.generic2Provider1 = Generic2_Factory.create(genericProvider1);
+ this.generic2Provider2 = Generic2_Factory.create(A_Factory.create());
+ this.genericProvider2 = Generic_Factory.create(generic2Provider2);
+ this.generic2Provider3 = Generic2_Factory.create(B_Factory.create());
+ this.genericProvider3 = Generic_Factory.create(generic2Provider3);
+ this.complexGenericsProvider = ComplexGenerics_Factory.create(generic2Provider, generic2Provider1, generic2Provider2, genericProvider2, genericProvider3);
+ this.genericParentMembersInjector = GenericParent_MembersInjector.create(A_Factory.create(), B_Factory.create(), B_Factory.create());
+ this.genericChildMembersInjector = GenericChild_MembersInjector.create(genericParentMembersInjector, A_Factory.create(), A_Factory.create());
+ this.genericParentMembersInjector1 = GenericParent_MembersInjector.create(B_Factory.create(), B_Factory.create(), B_Factory.create());
+ this.genericChildMembersInjector1 = GenericChild_MembersInjector.create(genericParentMembersInjector1, A_Factory.create(), B_Factory.create());
+ this.test_sub_Proxy.generic2Provider = Generic2_Factory.create(PackagePrivate_Factory.create());
+ this.test_sub_Proxy.generic2Provider1 = Generic2_Factory.create(PackagePrivateContainer$PublicEnclosed_Factory.create());
+ this.exposedMembersInjector = Exposed_MembersInjector.create(test_sub_Proxy.generic2Provider, test_sub_Proxy.generic2Provider1);
+ this.test_sub_Proxy.genericProvider = Generic_Factory.create(PackagePrivate_Factory.create());
+ this.test_sub_Proxy.genericProvider1 = Generic_Factory.create(PackagePrivateContainer$PublicEnclosed_Factory.create());
+ this.exposedProvider = Exposed_Factory.create(exposedMembersInjector, test_sub_Proxy.genericProvider, test_sub_Proxy.genericProvider1);
+ this.publicSubclassProvider = PublicSubclass_Factory.create((MembersInjector) MembersInjectors.noOp(), PackagePrivate_Factory.create());
+ this.provideListOfIntegerProvider = ChildIntegerModule_ProvideListOfIntegerFactory.create(builder.childIntegerModule);
+ this.provideIterableOfAWithCProvider = ParentModule_ProvideIterableOfAWithCFactory.create(builder.childIntegerModule, provideIntegerProvider, provideListOfIntegerProvider);
+ this.provideDoubleProvider = ChildDoubleModule_ProvideDoubleFactory.create(builder.childDoubleModule);
+ this.provideListOfDoubleProvider = ChildDoubleModule_ProvideListOfDoubleFactory.create(builder.childDoubleModule);
+ this.provideIterableOfAWithCProvider1 = ParentModule_ProvideIterableOfAWithCFactory.create(builder.childDoubleModule, provideDoubleProvider, provideListOfDoubleProvider);
+ }
+
+ @Override
+ public ReferencesGeneric referencesGeneric() {
+ return referencesGenericProvider.get();
+ }
+
+ @Override
+ public GenericDoubleReferences<A> doubleGenericA() {
+ return genericDoubleReferencesProvider.get();
+ }
+
+ @Override
+ public GenericDoubleReferences<B> doubleGenericB() {
+ return genericDoubleReferencesProvider1.get();
+ }
+
+ @Override
+ public ComplexGenerics complexGenerics() {
+ return complexGenericsProvider.get();
+ }
+
+ @Override
+ public GenericNoDeps<A> noDepsA() {
+ Provider<GenericNoDeps<A>> factory = GenericNoDeps_Factory.create();
+ return factory.get();
+ }
+
+ @Override
+ public GenericNoDeps<B> noDepsB() {
+ Provider<GenericNoDeps<B>> factory = GenericNoDeps_Factory.create();
+ return factory.get();
+ }
+
+ @Override
+ public void injectA(GenericChild<A> childA) {
+ genericChildMembersInjector.injectMembers(childA);
+ }
+
+ @Override
+ public void injectB(GenericChild<B> childB) {
+ genericChildMembersInjector1.injectMembers(childB);
+ }
+
+ @Override
+ public Exposed exposed() {
+ return exposedProvider.get();
+ }
+
+ @Override
+ public PublicSubclass publicSubclass() {
+ return publicSubclassProvider.get();
+ }
+
+ @Override
+ public Iterable<Integer> iterableInt() {
+ return provideIterableOfAWithCProvider.get();
+ }
+
+ @Override
+ public Iterable<Double> iterableDouble() {
+ return provideIterableOfAWithCProvider1.get();
+ }
+
+ public static final class Builder {
+ private ChildDoubleModule childDoubleModule;
+ private ChildIntegerModule childIntegerModule;
+
+ private Builder() {
+ }
+
+ public GenericComponent build() {
+ if (childDoubleModule == null) {
+ this.childDoubleModule = new ChildDoubleModule();
+ }
+ if (childIntegerModule == null) {
+ this.childIntegerModule = new ChildIntegerModule();
+ }
+ return new DaggerGenericComponent(this);
+ }
+
+ public Builder childDoubleModule(ChildDoubleModule childDoubleModule) {
+ if (childDoubleModule == null) {
+ throw new NullPointerException("childDoubleModule");
+ }
+ this.childDoubleModule = childDoubleModule;
+ return this;
+ }
+
+ public Builder childIntegerModule(ChildIntegerModule childIntegerModule) {
+ if (childIntegerModule == null) {
+ throw new NullPointerException("childIntegerModule");
+ }
+ this.childIntegerModule = childIntegerModule;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerMultibindingComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerMultibindingComponent.java
new file mode 100644
index 000000000..563a6aaa6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerMultibindingComponent.java
@@ -0,0 +1,299 @@
+package test;
+
+import dagger.internal.Factory;
+import dagger.internal.MapFactory;
+import dagger.internal.MapProviderFactory;
+import dagger.internal.SetFactory;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.TestStringKey.NestedWrappedKey;
+import test.sub.ContributionsModule;
+import test.sub.ContributionsModule_ContributeAnIntFactory;
+import test.sub.ContributionsModule_ContributeAnotherIntFactory;
+import test.sub.ContributionsModule_ContributeSomeIntsFactory;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerMultibindingComponent implements MultibindingComponent {
+ private Provider<Double> doubleDependencyProvider;
+ private Provider<String> mapOfStringAndProviderOfStringContribution1;
+ private Provider<String> mapOfStringAndProviderOfStringContribution2;
+ private Provider<Map<String, Provider<String>>> mapOfStringAndProviderOfStringProvider;
+ private Provider<Map<String, String>> mapOfStringAndStringProvider;
+ private Provider<Set<String>> provideMapKeysProvider;
+ private Provider<Collection<String>> provideMapValuesProvider;
+ private Provider<Set<Integer>> setOfIntegerContribution1Provider;
+ private Provider<Set<Integer>> setOfIntegerContribution2Provider;
+ private Provider<Set<Integer>> setOfIntegerContribution3Provider;
+ private Provider<Set<Integer>> setOfIntegerContribution4Provider;
+ private Provider<Set<Integer>> setOfIntegerContribution5Provider;
+ private Provider<Set<Integer>> setOfIntegerProvider;
+ private Provider<String> mapOfNestedWrappedKeyAndProviderOfStringContribution1;
+ private Provider<String> mapOfNestedWrappedKeyAndProviderOfStringContribution2;
+ private Provider<Map<NestedWrappedKey, Provider<String>>> mapOfNestedWrappedKeyAndProviderOfStringProvider;
+ private Provider<Map<NestedWrappedKey, String>> mapOfNestedWrappedKeyAndStringProvider;
+ private Provider<String> mapOfClassOfAndProviderOfStringContribution1;
+ private Provider<String> mapOfClassOfAndProviderOfStringContribution2;
+ private Provider<Map<Class<? extends Number>, Provider<String>>> mapOfClassOfAndProviderOfStringProvider;
+ private Provider<Map<Class<? extends Number>, String>> mapOfClassOfAndStringProvider;
+ private Provider<String> mapOfClassOfAndProviderOfStringContribution11;
+ private Provider<String> mapOfClassOfAndProviderOfStringContribution21;
+ private Provider<Map<Class<?>, Provider<String>>> mapOfClassOfAndProviderOfStringProvider1;
+ private Provider<Map<Class<?>, String>> mapOfClassOfAndStringProvider1;
+ private Provider<String> mapOfLongAndProviderOfStringContribution1;
+ private Provider<Map<Long, Provider<String>>> mapOfLongAndProviderOfStringProvider;
+ private Provider<Map<Long, String>> mapOfLongAndStringProvider;
+ private Provider<String> mapOfIntegerAndProviderOfStringContribution1;
+ private Provider<Map<Integer, Provider<String>>> mapOfIntegerAndProviderOfStringProvider;
+ private Provider<Map<Integer, String>> mapOfIntegerAndStringProvider;
+ private Provider<String> mapOfShortAndProviderOfStringContribution1;
+ private Provider<Map<Short, Provider<String>>> mapOfShortAndProviderOfStringProvider;
+ private Provider<Map<Short, String>> mapOfShortAndStringProvider;
+ private Provider<String> mapOfByteAndProviderOfStringContribution1;
+ private Provider<Map<Byte, Provider<String>>> mapOfByteAndProviderOfStringProvider;
+ private Provider<Map<Byte, String>> mapOfByteAndStringProvider;
+ private Provider<String> mapOfBooleanAndProviderOfStringContribution1;
+ private Provider<Map<Boolean, Provider<String>>> mapOfBooleanAndProviderOfStringProvider;
+ private Provider<Map<Boolean, String>> mapOfBooleanAndStringProvider;
+ private Provider<String> mapOfCharacterAndProviderOfStringContribution1;
+ private Provider<String> mapOfCharacterAndProviderOfStringContribution2;
+ private Provider<Map<Character, Provider<String>>> mapOfCharacterAndProviderOfStringProvider;
+ private Provider<Map<Character, String>> mapOfCharacterAndStringProvider;
+ private Provider<String> mapOfTestStringKeyAndProviderOfStringContribution1;
+ private Provider<Map<TestStringKey, Provider<String>>> mapOfTestStringKeyAndProviderOfStringProvider;
+ private Provider<Map<TestStringKey, String>> mapOfTestStringKeyAndStringProvider;
+ private Provider<String> mapOfTestWrappedAnnotationKeyAndProviderOfStringContribution1;
+ private Provider<Map<TestWrappedAnnotationKey, Provider<String>>> mapOfTestWrappedAnnotationKeyAndProviderOfStringProvider;
+ private Provider<Map<TestWrappedAnnotationKey, String>> mapOfTestWrappedAnnotationKeyAndStringProvider;
+
+ private DaggerMultibindingComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private void initialize(final Builder builder) {
+ this.doubleDependencyProvider = new Factory<Double>() {
+ private final MultibindingDependency multibindingDependency = builder.multibindingDependency;
+ @Override public Double get() {
+ Double provided = multibindingDependency.doubleDependency();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable component method");
+ }
+ return provided;
+ }
+ };
+ this.mapOfStringAndProviderOfStringContribution1 = MultibindingModule_ProvideFooKeyFactory.create(builder.multibindingModule, doubleDependencyProvider);
+ this.mapOfStringAndProviderOfStringContribution2 = MultibindingModule_ProvideBarKeyFactory.create(builder.multibindingModule);
+ this.mapOfStringAndProviderOfStringProvider = MapProviderFactory.<String, String>builder(2)
+ .put("foo", mapOfStringAndProviderOfStringContribution1)
+ .put("bar", mapOfStringAndProviderOfStringContribution2)
+ .build();
+ this.mapOfStringAndStringProvider = MapFactory.create(mapOfStringAndProviderOfStringProvider);
+ this.provideMapKeysProvider = MultibindingModule_ProvideMapKeysFactory.create(builder.multibindingModule, mapOfStringAndProviderOfStringProvider);
+ this.provideMapValuesProvider = MultibindingModule_ProvideMapValuesFactory.create(builder.multibindingModule, mapOfStringAndStringProvider);
+ this.setOfIntegerContribution1Provider = MultibindingModule_ProvideFiveToSetFactory.create(builder.multibindingModule);
+ this.setOfIntegerContribution2Provider = MultibindingModule_ProvideSixToSetFactory.create(builder.multibindingModule);
+ this.setOfIntegerContribution3Provider = ContributionsModule_ContributeAnIntFactory.create(builder.contributionsModule, doubleDependencyProvider);
+ this.setOfIntegerContribution4Provider = ContributionsModule_ContributeAnotherIntFactory.create(builder.contributionsModule);
+ this.setOfIntegerContribution5Provider = ContributionsModule_ContributeSomeIntsFactory.create(builder.contributionsModule);
+ this.setOfIntegerProvider = SetFactory.create(setOfIntegerContribution1Provider, setOfIntegerContribution2Provider, setOfIntegerContribution3Provider, setOfIntegerContribution4Provider, setOfIntegerContribution5Provider);
+ this.mapOfNestedWrappedKeyAndProviderOfStringContribution1 = MultibindingModule_ValueForIntegerFactory.create(builder.multibindingModule);
+ this.mapOfNestedWrappedKeyAndProviderOfStringContribution2 = MultibindingModule_ValueForLongFactory.create(builder.multibindingModule);
+ this.mapOfNestedWrappedKeyAndProviderOfStringProvider = MapProviderFactory.<NestedWrappedKey, String>builder(2)
+ .put(TestStringKey$NestedWrappedKeyCreator.createNestedWrappedKey(Integer.class), mapOfNestedWrappedKeyAndProviderOfStringContribution1)
+ .put(TestStringKey$NestedWrappedKeyCreator.createNestedWrappedKey(Long.class), mapOfNestedWrappedKeyAndProviderOfStringContribution2)
+ .build();
+ this.mapOfNestedWrappedKeyAndStringProvider = MapFactory.create(mapOfNestedWrappedKeyAndProviderOfStringProvider);
+ this.mapOfClassOfAndProviderOfStringContribution1 = MultibindingModule_ValueForNumberClassBigDecimalFactory.create(builder.multibindingModule);
+ this.mapOfClassOfAndProviderOfStringContribution2 = MultibindingModule_ValueForNumberClassBigIntegerFactory.create(builder.multibindingModule);
+ this.mapOfClassOfAndProviderOfStringProvider = MapProviderFactory.<Class<? extends Number>, String>builder(2)
+ .put(BigDecimal.class, mapOfClassOfAndProviderOfStringContribution1)
+ .put(BigInteger.class, mapOfClassOfAndProviderOfStringContribution2)
+ .build();
+ this.mapOfClassOfAndStringProvider = MapFactory.create(mapOfClassOfAndProviderOfStringProvider);
+ this.mapOfClassOfAndProviderOfStringContribution11 = MultibindingModule_ValueForClassIntegerFactory.create(builder.multibindingModule);
+ this.mapOfClassOfAndProviderOfStringContribution21 = MultibindingModule_ValueForClassLongFactory.create(builder.multibindingModule);
+ this.mapOfClassOfAndProviderOfStringProvider1 = MapProviderFactory.<Class<?>, String>builder(2)
+ .put(Integer.class, mapOfClassOfAndProviderOfStringContribution11)
+ .put(Long.class, mapOfClassOfAndProviderOfStringContribution21)
+ .build();
+ this.mapOfClassOfAndStringProvider1 = MapFactory.create(mapOfClassOfAndProviderOfStringProvider1);
+ this.mapOfLongAndProviderOfStringContribution1 = MultibindingModule_ValueFor100LongFactory.create(builder.multibindingModule);
+ this.mapOfLongAndProviderOfStringProvider = MapProviderFactory.<Long, String>builder(1)
+ .put(100L, mapOfLongAndProviderOfStringContribution1)
+ .build();
+ this.mapOfLongAndStringProvider = MapFactory.create(mapOfLongAndProviderOfStringProvider);
+ this.mapOfIntegerAndProviderOfStringContribution1 = MultibindingModule_ValueFor100IntFactory.create(builder.multibindingModule);
+ this.mapOfIntegerAndProviderOfStringProvider = MapProviderFactory.<Integer, String>builder(1)
+ .put((int) 100, mapOfIntegerAndProviderOfStringContribution1)
+ .build();
+ this.mapOfIntegerAndStringProvider = MapFactory.create(mapOfIntegerAndProviderOfStringProvider);
+ this.mapOfShortAndProviderOfStringContribution1 = MultibindingModule_ValueFor100ShortFactory.create(builder.multibindingModule);
+ this.mapOfShortAndProviderOfStringProvider = MapProviderFactory.<Short, String>builder(1)
+ .put((short) 100, mapOfShortAndProviderOfStringContribution1)
+ .build();
+ this.mapOfShortAndStringProvider = MapFactory.create(mapOfShortAndProviderOfStringProvider);
+ this.mapOfByteAndProviderOfStringContribution1 = MultibindingModule_ValueFor100ByteFactory.create(builder.multibindingModule);
+ this.mapOfByteAndProviderOfStringProvider = MapProviderFactory.<Byte, String>builder(1)
+ .put((byte) 100, mapOfByteAndProviderOfStringContribution1)
+ .build();
+ this.mapOfByteAndStringProvider = MapFactory.create(mapOfByteAndProviderOfStringProvider);
+ this.mapOfBooleanAndProviderOfStringContribution1 = MultibindingModule_ValueForTrueFactory.create(builder.multibindingModule);
+ this.mapOfBooleanAndProviderOfStringProvider = MapProviderFactory.<Boolean, String>builder(1)
+ .put(true, mapOfBooleanAndProviderOfStringContribution1)
+ .build();
+ this.mapOfBooleanAndStringProvider = MapFactory.create(mapOfBooleanAndProviderOfStringProvider);
+ this.mapOfCharacterAndProviderOfStringContribution1 = MultibindingModule_ValueForAFactory.create(builder.multibindingModule);
+ this.mapOfCharacterAndProviderOfStringContribution2 = MultibindingModule_ValueForNewlineFactory.create(builder.multibindingModule);
+ this.mapOfCharacterAndProviderOfStringProvider = MapProviderFactory.<Character, String>builder(2)
+ .put('a', mapOfCharacterAndProviderOfStringContribution1)
+ .put('\n', mapOfCharacterAndProviderOfStringContribution2)
+ .build();
+ this.mapOfCharacterAndStringProvider = MapFactory.create(mapOfCharacterAndProviderOfStringProvider);
+ this.mapOfTestStringKeyAndProviderOfStringContribution1 = MultibindingModule_ValueForUnwrappedAnnotationKeyFooFactory.create(builder.multibindingModule);
+ this.mapOfTestStringKeyAndProviderOfStringProvider = MapProviderFactory.<TestStringKey, String>builder(1)
+ .put(TestUnwrappedAnnotationKeyCreator.createTestStringKey("foo\n"), mapOfTestStringKeyAndProviderOfStringContribution1)
+ .build();
+ this.mapOfTestStringKeyAndStringProvider = MapFactory.create(mapOfTestStringKeyAndProviderOfStringProvider);
+ this.mapOfTestWrappedAnnotationKeyAndProviderOfStringContribution1 = MultibindingModule_ValueForWrappedAnnotationKeyFooFactory.create(builder.multibindingModule);
+ this.mapOfTestWrappedAnnotationKeyAndProviderOfStringProvider = MapProviderFactory.<TestWrappedAnnotationKey, String>builder(1)
+ .put(TestWrappedAnnotationKeyCreator.createTestWrappedAnnotationKey(TestWrappedAnnotationKeyCreator.createTestStringKey("foo"), new int[] {(int) 1, (int) 2, (int) 3}, new TestClassKey[] {}, new Class[] {Long.class, Integer.class}), mapOfTestWrappedAnnotationKeyAndProviderOfStringContribution1)
+ .build();
+ this.mapOfTestWrappedAnnotationKeyAndStringProvider = MapFactory.create(mapOfTestWrappedAnnotationKeyAndProviderOfStringProvider);
+ }
+
+ @Override
+ public Map<String, String> map() {
+ return mapOfStringAndStringProvider.get();
+ }
+
+ @Override
+ public Map<String, Provider<String>> mapOfProviders() {
+ return mapOfStringAndProviderOfStringProvider.get();
+ }
+
+ @Override
+ public Set<String> mapKeys() {
+ return provideMapKeysProvider.get();
+ }
+
+ @Override
+ public Collection<String> mapValues() {
+ return provideMapValuesProvider.get();
+ }
+
+ @Override
+ public Set<Integer> set() {
+ return setOfIntegerProvider.get();
+ }
+
+ @Override
+ public Map<NestedWrappedKey, String> nestedKeyMap() {
+ return mapOfNestedWrappedKeyAndStringProvider.get();
+ }
+
+ @Override
+ public Map<Class<? extends Number>, String> numberClassKeyMap() {
+ return mapOfClassOfAndStringProvider.get();
+ }
+
+ @Override
+ public Map<Class<?>, String> classKeyMap() {
+ return mapOfClassOfAndStringProvider1.get();
+ }
+
+ @Override
+ public Map<Long, String> longKeyMap() {
+ return mapOfLongAndStringProvider.get();
+ }
+
+ @Override
+ public Map<Integer, String> integerKeyMap() {
+ return mapOfIntegerAndStringProvider.get();
+ }
+
+ @Override
+ public Map<Short, String> shortKeyMap() {
+ return mapOfShortAndStringProvider.get();
+ }
+
+ @Override
+ public Map<Byte, String> byteKeyMap() {
+ return mapOfByteAndStringProvider.get();
+ }
+
+ @Override
+ public Map<Boolean, String> booleanKeyMap() {
+ return mapOfBooleanAndStringProvider.get();
+ }
+
+ @Override
+ public Map<Character, String> characterKeyMap() {
+ return mapOfCharacterAndStringProvider.get();
+ }
+
+ @Override
+ public Map<TestStringKey, String> unwrappedAnnotationKeyMap() {
+ return mapOfTestStringKeyAndStringProvider.get();
+ }
+
+ @Override
+ public Map<TestWrappedAnnotationKey, String> wrappedAnnotationKeyMap() {
+ return mapOfTestWrappedAnnotationKeyAndStringProvider.get();
+ }
+
+ public static final class Builder {
+ private MultibindingModule multibindingModule;
+ private ContributionsModule contributionsModule;
+ private MultibindingDependency multibindingDependency;
+
+ private Builder() {
+ }
+
+ public MultibindingComponent build() {
+ if (multibindingModule == null) {
+ this.multibindingModule = new MultibindingModule();
+ }
+ if (contributionsModule == null) {
+ this.contributionsModule = new ContributionsModule();
+ }
+ if (multibindingDependency == null) {
+ throw new IllegalStateException("multibindingDependency must be set");
+ }
+ return new DaggerMultibindingComponent(this);
+ }
+
+ public Builder multibindingModule(MultibindingModule multibindingModule) {
+ if (multibindingModule == null) {
+ throw new NullPointerException("multibindingModule");
+ }
+ this.multibindingModule = multibindingModule;
+ return this;
+ }
+
+ public Builder contributionsModule(ContributionsModule contributionsModule) {
+ if (contributionsModule == null) {
+ throw new NullPointerException("contributionsModule");
+ }
+ this.contributionsModule = contributionsModule;
+ return this;
+ }
+
+ public Builder multibindingDependency(MultibindingDependency multibindingDependency) {
+ if (multibindingDependency == null) {
+ throw new NullPointerException("multibindingDependency");
+ }
+ this.multibindingDependency = multibindingDependency;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerNonComponentDependencyComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerNonComponentDependencyComponent.java
new file mode 100644
index 000000000..3d90c737b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerNonComponentDependencyComponent.java
@@ -0,0 +1,69 @@
+package test;
+
+import dagger.internal.Factory;
+import dagger.internal.InstanceFactory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.NonComponentDependencyComponent.ThingComponent;
+import test.NonComponentDependencyComponent.ThingTwo;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerNonComponentDependencyComponent implements NonComponentDependencyComponent {
+ private Provider<Thing> thingProvider;
+ private Provider<NonComponentDependencyComponent> nonComponentDependencyComponentProvider;
+ private Provider<ThingComponent> thingComponentProvider;
+ private Provider<ThingTwo> thingTwoProvider;
+
+ private DaggerNonComponentDependencyComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private void initialize(final Builder builder) {
+ this.thingProvider = new Factory<Thing>() {
+ private final ThingComponent thingComponent = builder.thingComponent;
+ @Override public Thing get() {
+ Thing provided = thingComponent.thing();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable component method");
+ }
+ return provided;
+ }
+ };
+ this.nonComponentDependencyComponentProvider = InstanceFactory.<NonComponentDependencyComponent>create(this);
+ this.thingComponentProvider = InstanceFactory.<ThingComponent>create(builder.thingComponent);
+ this.thingTwoProvider = NonComponentDependencyComponent$ThingTwo_Factory.create(thingProvider, nonComponentDependencyComponentProvider, thingComponentProvider);
+ }
+
+ @Override
+ public ThingTwo thingTwo() {
+ return thingTwoProvider.get();
+ }
+
+ public static final class Builder {
+ private ThingComponent thingComponent;
+
+ private Builder() {
+ }
+
+ public NonComponentDependencyComponent build() {
+ if (thingComponent == null) {
+ throw new IllegalStateException("thingComponent must be set");
+ }
+ return new DaggerNonComponentDependencyComponent(this);
+ }
+
+ public Builder thingComponent(ThingComponent thingComponent) {
+ if (thingComponent == null) {
+ throw new NullPointerException("thingComponent");
+ }
+ this.thingComponent = thingComponent;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerOuterClassBar_NestedComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerOuterClassBar_NestedComponent.java
new file mode 100644
index 000000000..1d6191408
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerOuterClassBar_NestedComponent.java
@@ -0,0 +1,65 @@
+package test;
+
+import dagger.MembersInjector;
+import dagger.internal.MembersInjectors;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.OuterClassBar.NestedComponent;
+import test.sub.OtherThing;
+import test.sub.OtherThing_Factory;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerOuterClassBar_NestedComponent implements NestedComponent {
+ private Provider<OtherThing> otherThingProvider;
+ private Provider<Thing> thingProvider;
+ private MembersInjector<InjectedThing> injectedThingMembersInjector;
+ private Provider<InjectedThing> injectedThingProvider;
+
+ private DaggerOuterClassBar_NestedComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static NestedComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.otherThingProvider = OtherThing_Factory.create(PrimitivesModule_ProvideIntFactory.create());
+ this.thingProvider = Thing_Factory.create(otherThingProvider);
+ this.injectedThingMembersInjector = InjectedThing_MembersInjector.create(PrimitivesModule_ProvideByteFactory.create(), PrimitivesModule_ProvideCharFactory.create(), PrimitivesModule_ProvideShortFactory.create(), PrimitivesModule_ProvideIntFactory.create(), PrimitivesModule_ProvideLongFactory.create(), PrimitivesModule_ProvideBooleanFactory.create(), PrimitivesModule_ProvideFloatFactory.create(), PrimitivesModule_BoundDoubleFactory.create(), PrimitivesModule_ProvideByteArrayFactory.create(), PrimitivesModule_ProvideCharArrayFactory.create(), PrimitivesModule_ProvideShortArrayFactory.create(), PrimitivesModule_ProvideIntArrayFactory.create(), PrimitivesModule_ProvideLongArrayFactory.create(), PrimitivesModule_ProvideBooleanArrayFactory.create(), PrimitivesModule_ProvideFloatArrayFactory.create(), PrimitivesModule_BoundDoubleArrayFactory.create(), thingProvider, (MembersInjector) MembersInjectors.noOp());
+ this.injectedThingProvider = InjectedThing_Factory.create(injectedThingMembersInjector, PrimitivesModule_ProvideByteFactory.create(), PrimitivesModule_ProvideCharFactory.create(), PrimitivesModule_ProvideShortFactory.create(), PrimitivesModule_ProvideIntFactory.create(), PrimitivesModule_ProvideLongFactory.create(), PrimitivesModule_ProvideBooleanFactory.create(), PrimitivesModule_ProvideFloatFactory.create(), PrimitivesModule_BoundDoubleFactory.create(), PrimitivesModule_ProvideByteArrayFactory.create(), PrimitivesModule_ProvideCharArrayFactory.create(), PrimitivesModule_ProvideShortArrayFactory.create(), PrimitivesModule_ProvideIntArrayFactory.create(), PrimitivesModule_ProvideLongArrayFactory.create(), PrimitivesModule_ProvideBooleanArrayFactory.create(), PrimitivesModule_ProvideFloatArrayFactory.create(), PrimitivesModule_BoundDoubleArrayFactory.create(), thingProvider, (MembersInjector) MembersInjectors.noOp());
+ }
+
+ @Override
+ public InjectedThing injectedThing() {
+ return injectedThingProvider.get();
+ }
+
+ public static final class Builder {
+ private PrimitivesModule primitivesModule;
+
+ private Builder() {
+ }
+
+ public NestedComponent build() {
+ if (primitivesModule == null) {
+ this.primitivesModule = new PrimitivesModule();
+ }
+ return new DaggerOuterClassBar_NestedComponent(this);
+ }
+
+ public Builder primitivesModule(PrimitivesModule primitivesModule) {
+ if (primitivesModule == null) {
+ throw new NullPointerException("primitivesModule");
+ }
+ this.primitivesModule = primitivesModule;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerOuterClassFoo_NestedComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerOuterClassFoo_NestedComponent.java
new file mode 100644
index 000000000..a307b9490
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerOuterClassFoo_NestedComponent.java
@@ -0,0 +1,59 @@
+package test;
+
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.OuterClassFoo.NestedComponent;
+import test.sub.OtherThing;
+import test.sub.OtherThing_Factory;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerOuterClassFoo_NestedComponent implements NestedComponent {
+ private Provider<OtherThing> otherThingProvider;
+ private Provider<Thing> thingProvider;
+
+ private DaggerOuterClassFoo_NestedComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static NestedComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.otherThingProvider = OtherThing_Factory.create(PrimitivesModule_ProvideIntFactory.create());
+ this.thingProvider = Thing_Factory.create(otherThingProvider);
+ }
+
+ @Override
+ public Thing thing() {
+ return thingProvider.get();
+ }
+
+ public static final class Builder {
+ private PrimitivesModule primitivesModule;
+
+ private Builder() {
+ }
+
+ public NestedComponent build() {
+ if (primitivesModule == null) {
+ this.primitivesModule = new PrimitivesModule();
+ }
+ return new DaggerOuterClassFoo_NestedComponent(this);
+ }
+
+ public Builder primitivesModule(PrimitivesModule primitivesModule) {
+ if (primitivesModule == null) {
+ throw new NullPointerException("primitivesModule");
+ }
+ this.primitivesModule = primitivesModule;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerSingletonGenericComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerSingletonGenericComponent.java
new file mode 100644
index 000000000..f08ad4296
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/DaggerSingletonGenericComponent.java
@@ -0,0 +1,49 @@
+package test;
+
+import dagger.internal.ScopedProvider;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerSingletonGenericComponent implements SingletonGenericComponent {
+ private Provider<ScopedGeneric<A>> scopedGenericProvider;
+ private Provider<ScopedGeneric<B>> scopedGenericProvider1;
+
+ private DaggerSingletonGenericComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static SingletonGenericComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.scopedGenericProvider = ScopedProvider.create(ScopedGeneric_Factory.create(A_Factory.create()));
+ this.scopedGenericProvider1 = ScopedProvider.create(ScopedGeneric_Factory.create(B_Factory.create()));
+ }
+
+ @Override
+ public ScopedGeneric<A> scopedGenericA() {
+ return scopedGenericProvider.get();
+ }
+
+ @Override
+ public ScopedGeneric<B> scopedGenericB() {
+ return scopedGenericProvider1.get();
+ }
+
+ public static final class Builder {
+ private Builder() {
+ }
+
+ public SingletonGenericComponent build() {
+ return new DaggerSingletonGenericComponent(this);
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/Generic2_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/Generic2_Factory.java
new file mode 100644
index 000000000..0f5b13dbf
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/Generic2_Factory.java
@@ -0,0 +1,25 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class Generic2_Factory<T> implements Factory<Generic2<T>> {
+ private final Provider<T> tProvider;
+
+ public Generic2_Factory(Provider<T> tProvider) {
+ assert tProvider != null;
+ this.tProvider = tProvider;
+ }
+
+ @Override
+ public Generic2<T> get() {
+ return new Generic2<T>(tProvider.get());
+ }
+
+ public static <T> Factory<Generic2<T>> create(Provider<T> tProvider) {
+ return new Generic2_Factory<T>(tProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericChild_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericChild_Factory.java
new file mode 100644
index 000000000..95500275c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericChild_Factory.java
@@ -0,0 +1,27 @@
+package test;
+
+import dagger.MembersInjector;
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class GenericChild_Factory<T> implements Factory<GenericChild<T>> {
+ private final MembersInjector<GenericChild<T>> membersInjector;
+
+ public GenericChild_Factory(MembersInjector<GenericChild<T>> membersInjector) {
+ assert membersInjector != null;
+ this.membersInjector = membersInjector;
+ }
+
+ @Override
+ public GenericChild<T> get() {
+ GenericChild<T> instance = new GenericChild<T>();
+ membersInjector.injectMembers(instance);
+ return instance;
+ }
+
+ public static <T> Factory<GenericChild<T>> create(MembersInjector<GenericChild<T>> membersInjector) {
+ return new GenericChild_Factory<T>(membersInjector);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericChild_MembersInjector.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericChild_MembersInjector.java
new file mode 100644
index 000000000..5b734a587
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericChild_MembersInjector.java
@@ -0,0 +1,38 @@
+package test;
+
+import dagger.MembersInjector;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class GenericChild_MembersInjector<T> implements MembersInjector<GenericChild<T>> {
+ private final MembersInjector<GenericParent<T, B>> supertypeInjector;
+ private final Provider<A> aProvider;
+ private final Provider<T> tProvider;
+
+ public GenericChild_MembersInjector(MembersInjector<GenericParent<T, B>> supertypeInjector, Provider<A> aProvider, Provider<T> tProvider) {
+ assert supertypeInjector != null;
+ this.supertypeInjector = supertypeInjector;
+ assert aProvider != null;
+ this.aProvider = aProvider;
+ assert tProvider != null;
+ this.tProvider = tProvider;
+ }
+
+ @Override
+ public void injectMembers(GenericChild<T> instance) {
+ if (instance == null) {
+ throw new NullPointerException("Cannot inject members into a null reference");
+ }
+ supertypeInjector.injectMembers(instance);
+ instance.a = aProvider.get();
+ instance.t = tProvider.get();
+ instance.registerA(aProvider.get());
+ instance.registerT(tProvider.get());
+ }
+
+ public static <T> MembersInjector<GenericChild<T>> create(MembersInjector<GenericParent<T, B>> supertypeInjector, Provider<A> aProvider, Provider<T> tProvider) {
+ return new GenericChild_MembersInjector<T>(supertypeInjector, aProvider, tProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericDoubleReferences_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericDoubleReferences_Factory.java
new file mode 100644
index 000000000..4e763fb25
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericDoubleReferences_Factory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class GenericDoubleReferences_Factory<T> implements Factory<GenericDoubleReferences<T>> {
+ private final Provider<T> tAndT2Provider;
+ private final Provider<Thing> aAndA2Provider;
+
+ public GenericDoubleReferences_Factory(Provider<T> tAndT2Provider, Provider<Thing> aAndA2Provider) {
+ assert tAndT2Provider != null;
+ this.tAndT2Provider = tAndT2Provider;
+ assert aAndA2Provider != null;
+ this.aAndA2Provider = aAndA2Provider;
+ }
+
+ @Override
+ public GenericDoubleReferences<T> get() {
+ return new GenericDoubleReferences<T>(tAndT2Provider.get(), aAndA2Provider.get(), tAndT2Provider.get(), aAndA2Provider.get());
+ }
+
+ public static <T> Factory<GenericDoubleReferences<T>> create(Provider<T> tAndT2Provider, Provider<Thing> aAndA2Provider) {
+ return new GenericDoubleReferences_Factory<T>(tAndT2Provider, aAndA2Provider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericNoDeps_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericNoDeps_Factory.java
new file mode 100644
index 000000000..97ac2ee80
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericNoDeps_Factory.java
@@ -0,0 +1,21 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@SuppressWarnings("rawtypes")
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum GenericNoDeps_Factory implements Factory<GenericNoDeps> {
+INSTANCE;
+
+ @Override
+ public GenericNoDeps get() {
+ return new GenericNoDeps();
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> Factory<GenericNoDeps<T>> create() {
+ return (Factory) INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericParent_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericParent_Factory.java
new file mode 100644
index 000000000..2e2e62c40
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericParent_Factory.java
@@ -0,0 +1,27 @@
+package test;
+
+import dagger.MembersInjector;
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class GenericParent_Factory<X, Y> implements Factory<GenericParent<X, Y>> {
+ private final MembersInjector<GenericParent<X, Y>> membersInjector;
+
+ public GenericParent_Factory(MembersInjector<GenericParent<X, Y>> membersInjector) {
+ assert membersInjector != null;
+ this.membersInjector = membersInjector;
+ }
+
+ @Override
+ public GenericParent<X, Y> get() {
+ GenericParent<X, Y> instance = new GenericParent<X, Y>();
+ membersInjector.injectMembers(instance);
+ return instance;
+ }
+
+ public static <X, Y> Factory<GenericParent<X, Y>> create(MembersInjector<GenericParent<X, Y>> membersInjector) {
+ return new GenericParent_Factory<X, Y>(membersInjector);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericParent_MembersInjector.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericParent_MembersInjector.java
new file mode 100644
index 000000000..5b11ab9e8
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/GenericParent_MembersInjector.java
@@ -0,0 +1,39 @@
+package test;
+
+import dagger.MembersInjector;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class GenericParent_MembersInjector<X, Y> implements MembersInjector<GenericParent<X, Y>> {
+ private final Provider<X> xProvider;
+ private final Provider<Y> yProvider;
+ private final Provider<B> bProvider;
+
+ public GenericParent_MembersInjector(Provider<X> xProvider, Provider<Y> yProvider, Provider<B> bProvider) {
+ assert xProvider != null;
+ this.xProvider = xProvider;
+ assert yProvider != null;
+ this.yProvider = yProvider;
+ assert bProvider != null;
+ this.bProvider = bProvider;
+ }
+
+ @Override
+ public void injectMembers(GenericParent<X, Y> instance) {
+ if (instance == null) {
+ throw new NullPointerException("Cannot inject members into a null reference");
+ }
+ instance.x = xProvider.get();
+ instance.y = yProvider.get();
+ instance.b = bProvider.get();
+ instance.registerX(xProvider.get());
+ instance.registerY(yProvider.get());
+ instance.registerB(bProvider.get());
+ }
+
+ public static <X, Y> MembersInjector<GenericParent<X, Y>> create(Provider<X> xProvider, Provider<Y> yProvider, Provider<B> bProvider) {
+ return new GenericParent_MembersInjector<X, Y>(xProvider, yProvider, bProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/Generic_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/Generic_Factory.java
new file mode 100644
index 000000000..e06ad23ad
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/Generic_Factory.java
@@ -0,0 +1,25 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class Generic_Factory<T> implements Factory<Generic<T>> {
+ private final Provider<T> tProvider;
+
+ public Generic_Factory(Provider<T> tProvider) {
+ assert tProvider != null;
+ this.tProvider = tProvider;
+ }
+
+ @Override
+ public Generic<T> get() {
+ return new Generic<T>(tProvider.get());
+ }
+
+ public static <T> Factory<Generic<T>> create(Provider<T> tProvider) {
+ return new Generic_Factory<T>(tProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/InjectedThing_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/InjectedThing_Factory.java
new file mode 100644
index 000000000..65a361f27
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/InjectedThing_Factory.java
@@ -0,0 +1,83 @@
+package test;
+
+import dagger.MembersInjector;
+import dagger.internal.DoubleCheckLazy;
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class InjectedThing_Factory implements Factory<InjectedThing> {
+ private final MembersInjector<InjectedThing> membersInjector;
+ private final Provider<Byte> boxedBypeAndPrimitiveByteAndByteProvider;
+ private final Provider<Character> boxedCharAndPrimitiveCharAndCharProvider;
+ private final Provider<Short> boxedShortAndPrimitiveShortAndShortProvider;
+ private final Provider<Integer> boxedIntAndPrimitiveIntAndIntProvider;
+ private final Provider<Long> boxedLongAndPrimitiveLongAndLongProvider;
+ private final Provider<Boolean> boxedBooleanAndPrimitiveBooleanAndBooleanProvider;
+ private final Provider<Float> boxedFloatAndPrimitiveFloatAndFloatProvider;
+ private final Provider<Double> boxedDoubleAndPrimitiveDoubleAndDoubleProvider;
+ private final Provider<byte[]> byteArrayProvider;
+ private final Provider<char[]> charArrayProvider;
+ private final Provider<short[]> shortArrayProvider;
+ private final Provider<int[]> intArrayProvider;
+ private final Provider<long[]> longArrayProvider;
+ private final Provider<boolean[]> booleanArrayProvider;
+ private final Provider<float[]> floatArrayAndLazyProvider;
+ private final Provider<double[]> doubleArrayProvider;
+ private final Provider<Thing> thingProvider;
+ private final MembersInjector<Thing> thingMembersInjector;
+
+ public InjectedThing_Factory(MembersInjector<InjectedThing> membersInjector, Provider<Byte> boxedBypeAndPrimitiveByteAndByteProvider, Provider<Character> boxedCharAndPrimitiveCharAndCharProvider, Provider<Short> boxedShortAndPrimitiveShortAndShortProvider, Provider<Integer> boxedIntAndPrimitiveIntAndIntProvider, Provider<Long> boxedLongAndPrimitiveLongAndLongProvider, Provider<Boolean> boxedBooleanAndPrimitiveBooleanAndBooleanProvider, Provider<Float> boxedFloatAndPrimitiveFloatAndFloatProvider, Provider<Double> boxedDoubleAndPrimitiveDoubleAndDoubleProvider, Provider<byte[]> byteArrayProvider, Provider<char[]> charArrayProvider, Provider<short[]> shortArrayProvider, Provider<int[]> intArrayProvider, Provider<long[]> longArrayProvider, Provider<boolean[]> booleanArrayProvider, Provider<float[]> floatArrayAndLazyProvider, Provider<double[]> doubleArrayProvider, Provider<Thing> thingProvider, MembersInjector<Thing> thingMembersInjector) {
+ assert membersInjector != null;
+ this.membersInjector = membersInjector;
+ assert boxedBypeAndPrimitiveByteAndByteProvider != null;
+ this.boxedBypeAndPrimitiveByteAndByteProvider = boxedBypeAndPrimitiveByteAndByteProvider;
+ assert boxedCharAndPrimitiveCharAndCharProvider != null;
+ this.boxedCharAndPrimitiveCharAndCharProvider = boxedCharAndPrimitiveCharAndCharProvider;
+ assert boxedShortAndPrimitiveShortAndShortProvider != null;
+ this.boxedShortAndPrimitiveShortAndShortProvider = boxedShortAndPrimitiveShortAndShortProvider;
+ assert boxedIntAndPrimitiveIntAndIntProvider != null;
+ this.boxedIntAndPrimitiveIntAndIntProvider = boxedIntAndPrimitiveIntAndIntProvider;
+ assert boxedLongAndPrimitiveLongAndLongProvider != null;
+ this.boxedLongAndPrimitiveLongAndLongProvider = boxedLongAndPrimitiveLongAndLongProvider;
+ assert boxedBooleanAndPrimitiveBooleanAndBooleanProvider != null;
+ this.boxedBooleanAndPrimitiveBooleanAndBooleanProvider = boxedBooleanAndPrimitiveBooleanAndBooleanProvider;
+ assert boxedFloatAndPrimitiveFloatAndFloatProvider != null;
+ this.boxedFloatAndPrimitiveFloatAndFloatProvider = boxedFloatAndPrimitiveFloatAndFloatProvider;
+ assert boxedDoubleAndPrimitiveDoubleAndDoubleProvider != null;
+ this.boxedDoubleAndPrimitiveDoubleAndDoubleProvider = boxedDoubleAndPrimitiveDoubleAndDoubleProvider;
+ assert byteArrayProvider != null;
+ this.byteArrayProvider = byteArrayProvider;
+ assert charArrayProvider != null;
+ this.charArrayProvider = charArrayProvider;
+ assert shortArrayProvider != null;
+ this.shortArrayProvider = shortArrayProvider;
+ assert intArrayProvider != null;
+ this.intArrayProvider = intArrayProvider;
+ assert longArrayProvider != null;
+ this.longArrayProvider = longArrayProvider;
+ assert booleanArrayProvider != null;
+ this.booleanArrayProvider = booleanArrayProvider;
+ assert floatArrayAndLazyProvider != null;
+ this.floatArrayAndLazyProvider = floatArrayAndLazyProvider;
+ assert doubleArrayProvider != null;
+ this.doubleArrayProvider = doubleArrayProvider;
+ assert thingProvider != null;
+ this.thingProvider = thingProvider;
+ assert thingMembersInjector != null;
+ this.thingMembersInjector = thingMembersInjector;
+ }
+
+ @Override
+ public InjectedThing get() {
+ InjectedThing instance = new InjectedThing(boxedBypeAndPrimitiveByteAndByteProvider.get(), boxedCharAndPrimitiveCharAndCharProvider.get(), boxedShortAndPrimitiveShortAndShortProvider.get(), boxedIntAndPrimitiveIntAndIntProvider.get(), boxedLongAndPrimitiveLongAndLongProvider.get(), boxedBooleanAndPrimitiveBooleanAndBooleanProvider.get(), boxedFloatAndPrimitiveFloatAndFloatProvider.get(), boxedDoubleAndPrimitiveDoubleAndDoubleProvider.get(), boxedBypeAndPrimitiveByteAndByteProvider, boxedCharAndPrimitiveCharAndCharProvider, boxedShortAndPrimitiveShortAndShortProvider, boxedIntAndPrimitiveIntAndIntProvider, boxedLongAndPrimitiveLongAndLongProvider, boxedBooleanAndPrimitiveBooleanAndBooleanProvider, boxedFloatAndPrimitiveFloatAndFloatProvider, boxedDoubleAndPrimitiveDoubleAndDoubleProvider, DoubleCheckLazy.create(boxedBypeAndPrimitiveByteAndByteProvider), DoubleCheckLazy.create(boxedCharAndPrimitiveCharAndCharProvider), DoubleCheckLazy.create(boxedShortAndPrimitiveShortAndShortProvider), DoubleCheckLazy.create(boxedIntAndPrimitiveIntAndIntProvider), DoubleCheckLazy.create(boxedLongAndPrimitiveLongAndLongProvider), DoubleCheckLazy.create(boxedBooleanAndPrimitiveBooleanAndBooleanProvider), DoubleCheckLazy.create(boxedFloatAndPrimitiveFloatAndFloatProvider), DoubleCheckLazy.create(boxedDoubleAndPrimitiveDoubleAndDoubleProvider), boxedBypeAndPrimitiveByteAndByteProvider.get(), boxedCharAndPrimitiveCharAndCharProvider.get(), boxedShortAndPrimitiveShortAndShortProvider.get(), boxedIntAndPrimitiveIntAndIntProvider.get(), boxedLongAndPrimitiveLongAndLongProvider.get(), boxedBooleanAndPrimitiveBooleanAndBooleanProvider.get(), boxedFloatAndPrimitiveFloatAndFloatProvider.get(), boxedDoubleAndPrimitiveDoubleAndDoubleProvider.get(), byteArrayProvider.get(), charArrayProvider.get(), shortArrayProvider.get(), intArrayProvider.get(), longArrayProvider.get(), booleanArrayProvider.get(), floatArrayAndLazyProvider.get(), doubleArrayProvider.get(), byteArrayProvider, charArrayProvider, shortArrayProvider, intArrayProvider, longArrayProvider, booleanArrayProvider, floatArrayAndLazyProvider, doubleArrayProvider, DoubleCheckLazy.create(byteArrayProvider), DoubleCheckLazy.create(charArrayProvider), DoubleCheckLazy.create(shortArrayProvider), DoubleCheckLazy.create(intArrayProvider), DoubleCheckLazy.create(longArrayProvider), DoubleCheckLazy.create(booleanArrayProvider), DoubleCheckLazy.create(floatArrayAndLazyProvider), DoubleCheckLazy.create(doubleArrayProvider), thingProvider.get(), thingProvider, DoubleCheckLazy.create(thingProvider), thingMembersInjector);
+ membersInjector.injectMembers(instance);
+ return instance;
+ }
+
+ public static Factory<InjectedThing> create(MembersInjector<InjectedThing> membersInjector, Provider<Byte> boxedBypeAndPrimitiveByteAndByteProvider, Provider<Character> boxedCharAndPrimitiveCharAndCharProvider, Provider<Short> boxedShortAndPrimitiveShortAndShortProvider, Provider<Integer> boxedIntAndPrimitiveIntAndIntProvider, Provider<Long> boxedLongAndPrimitiveLongAndLongProvider, Provider<Boolean> boxedBooleanAndPrimitiveBooleanAndBooleanProvider, Provider<Float> boxedFloatAndPrimitiveFloatAndFloatProvider, Provider<Double> boxedDoubleAndPrimitiveDoubleAndDoubleProvider, Provider<byte[]> byteArrayProvider, Provider<char[]> charArrayProvider, Provider<short[]> shortArrayProvider, Provider<int[]> intArrayProvider, Provider<long[]> longArrayProvider, Provider<boolean[]> booleanArrayProvider, Provider<float[]> floatArrayAndLazyProvider, Provider<double[]> doubleArrayProvider, Provider<Thing> thingProvider, MembersInjector<Thing> thingMembersInjector) {
+ return new InjectedThing_Factory(membersInjector, boxedBypeAndPrimitiveByteAndByteProvider, boxedCharAndPrimitiveCharAndCharProvider, boxedShortAndPrimitiveShortAndShortProvider, boxedIntAndPrimitiveIntAndIntProvider, boxedLongAndPrimitiveLongAndLongProvider, boxedBooleanAndPrimitiveBooleanAndBooleanProvider, boxedFloatAndPrimitiveFloatAndFloatProvider, boxedDoubleAndPrimitiveDoubleAndDoubleProvider, byteArrayProvider, charArrayProvider, shortArrayProvider, intArrayProvider, longArrayProvider, booleanArrayProvider, floatArrayAndLazyProvider, doubleArrayProvider, thingProvider, thingMembersInjector);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/InjectedThing_MembersInjector.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/InjectedThing_MembersInjector.java
new file mode 100644
index 000000000..00f265d4c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/InjectedThing_MembersInjector.java
@@ -0,0 +1,199 @@
+package test;
+
+import dagger.MembersInjector;
+import dagger.internal.DoubleCheckLazy;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class InjectedThing_MembersInjector implements MembersInjector<InjectedThing> {
+ private final Provider<Byte> boxedBypeAndPrimitiveByteAndByteProvider;
+ private final Provider<Character> boxedCharAndPrimitiveCharAndCharProvider;
+ private final Provider<Short> boxedShortAndPrimitiveShortAndShortProvider;
+ private final Provider<Integer> boxedIntAndPrimitiveIntAndIntProvider;
+ private final Provider<Long> boxedLongAndPrimitiveLongAndLongProvider;
+ private final Provider<Boolean> boxedBooleanAndPrimitiveBooleanAndBooleanProvider;
+ private final Provider<Float> boxedFloatAndPrimitiveFloatAndFloatProvider;
+ private final Provider<Double> boxedDoubleAndPrimitiveDoubleAndDoubleProvider;
+ private final Provider<byte[]> byteArrayProvider;
+ private final Provider<char[]> charArrayProvider;
+ private final Provider<short[]> shortArrayProvider;
+ private final Provider<int[]> intArrayProvider;
+ private final Provider<long[]> longArrayProvider;
+ private final Provider<boolean[]> booleanArrayProvider;
+ private final Provider<float[]> floatArrayAndLazyProvider;
+ private final Provider<double[]> doubleArrayProvider;
+ private final Provider<Thing> thingProvider;
+ private final MembersInjector<Thing> thingMembersInjector;
+
+ public InjectedThing_MembersInjector(Provider<Byte> boxedBypeAndPrimitiveByteAndByteProvider, Provider<Character> boxedCharAndPrimitiveCharAndCharProvider, Provider<Short> boxedShortAndPrimitiveShortAndShortProvider, Provider<Integer> boxedIntAndPrimitiveIntAndIntProvider, Provider<Long> boxedLongAndPrimitiveLongAndLongProvider, Provider<Boolean> boxedBooleanAndPrimitiveBooleanAndBooleanProvider, Provider<Float> boxedFloatAndPrimitiveFloatAndFloatProvider, Provider<Double> boxedDoubleAndPrimitiveDoubleAndDoubleProvider, Provider<byte[]> byteArrayProvider, Provider<char[]> charArrayProvider, Provider<short[]> shortArrayProvider, Provider<int[]> intArrayProvider, Provider<long[]> longArrayProvider, Provider<boolean[]> booleanArrayProvider, Provider<float[]> floatArrayAndLazyProvider, Provider<double[]> doubleArrayProvider, Provider<Thing> thingProvider, MembersInjector<Thing> thingMembersInjector) {
+ assert boxedBypeAndPrimitiveByteAndByteProvider != null;
+ this.boxedBypeAndPrimitiveByteAndByteProvider = boxedBypeAndPrimitiveByteAndByteProvider;
+ assert boxedCharAndPrimitiveCharAndCharProvider != null;
+ this.boxedCharAndPrimitiveCharAndCharProvider = boxedCharAndPrimitiveCharAndCharProvider;
+ assert boxedShortAndPrimitiveShortAndShortProvider != null;
+ this.boxedShortAndPrimitiveShortAndShortProvider = boxedShortAndPrimitiveShortAndShortProvider;
+ assert boxedIntAndPrimitiveIntAndIntProvider != null;
+ this.boxedIntAndPrimitiveIntAndIntProvider = boxedIntAndPrimitiveIntAndIntProvider;
+ assert boxedLongAndPrimitiveLongAndLongProvider != null;
+ this.boxedLongAndPrimitiveLongAndLongProvider = boxedLongAndPrimitiveLongAndLongProvider;
+ assert boxedBooleanAndPrimitiveBooleanAndBooleanProvider != null;
+ this.boxedBooleanAndPrimitiveBooleanAndBooleanProvider = boxedBooleanAndPrimitiveBooleanAndBooleanProvider;
+ assert boxedFloatAndPrimitiveFloatAndFloatProvider != null;
+ this.boxedFloatAndPrimitiveFloatAndFloatProvider = boxedFloatAndPrimitiveFloatAndFloatProvider;
+ assert boxedDoubleAndPrimitiveDoubleAndDoubleProvider != null;
+ this.boxedDoubleAndPrimitiveDoubleAndDoubleProvider = boxedDoubleAndPrimitiveDoubleAndDoubleProvider;
+ assert byteArrayProvider != null;
+ this.byteArrayProvider = byteArrayProvider;
+ assert charArrayProvider != null;
+ this.charArrayProvider = charArrayProvider;
+ assert shortArrayProvider != null;
+ this.shortArrayProvider = shortArrayProvider;
+ assert intArrayProvider != null;
+ this.intArrayProvider = intArrayProvider;
+ assert longArrayProvider != null;
+ this.longArrayProvider = longArrayProvider;
+ assert booleanArrayProvider != null;
+ this.booleanArrayProvider = booleanArrayProvider;
+ assert floatArrayAndLazyProvider != null;
+ this.floatArrayAndLazyProvider = floatArrayAndLazyProvider;
+ assert doubleArrayProvider != null;
+ this.doubleArrayProvider = doubleArrayProvider;
+ assert thingProvider != null;
+ this.thingProvider = thingProvider;
+ assert thingMembersInjector != null;
+ this.thingMembersInjector = thingMembersInjector;
+ }
+
+ @Override
+ public void injectMembers(InjectedThing instance) {
+ if (instance == null) {
+ throw new NullPointerException("Cannot inject members into a null reference");
+ }
+ instance.primitiveByte = boxedBypeAndPrimitiveByteAndByteProvider.get();
+ instance.primitiveChar = boxedCharAndPrimitiveCharAndCharProvider.get();
+ instance.primitiveShort = boxedShortAndPrimitiveShortAndShortProvider.get();
+ instance.primitiveInt = boxedIntAndPrimitiveIntAndIntProvider.get();
+ instance.primitiveLong = boxedLongAndPrimitiveLongAndLongProvider.get();
+ instance.primitiveBoolean = boxedBooleanAndPrimitiveBooleanAndBooleanProvider.get();
+ instance.primitiveFloat = boxedFloatAndPrimitiveFloatAndFloatProvider.get();
+ instance.primitiveDouble = boxedDoubleAndPrimitiveDoubleAndDoubleProvider.get();
+ instance.byteProvider = boxedBypeAndPrimitiveByteAndByteProvider;
+ instance.charProvider = boxedCharAndPrimitiveCharAndCharProvider;
+ instance.shortProvider = boxedShortAndPrimitiveShortAndShortProvider;
+ instance.intProvider = boxedIntAndPrimitiveIntAndIntProvider;
+ instance.longProvider = boxedLongAndPrimitiveLongAndLongProvider;
+ instance.booleanProvider = boxedBooleanAndPrimitiveBooleanAndBooleanProvider;
+ instance.floatProvider = boxedFloatAndPrimitiveFloatAndFloatProvider;
+ instance.doubleProvider = boxedDoubleAndPrimitiveDoubleAndDoubleProvider;
+ instance.lazyByte = DoubleCheckLazy.create(boxedBypeAndPrimitiveByteAndByteProvider);
+ instance.lazyChar = DoubleCheckLazy.create(boxedCharAndPrimitiveCharAndCharProvider);
+ instance.lazyShort = DoubleCheckLazy.create(boxedShortAndPrimitiveShortAndShortProvider);
+ instance.lazyInt = DoubleCheckLazy.create(boxedIntAndPrimitiveIntAndIntProvider);
+ instance.lazyLong = DoubleCheckLazy.create(boxedLongAndPrimitiveLongAndLongProvider);
+ instance.lazyBoolean = DoubleCheckLazy.create(boxedBooleanAndPrimitiveBooleanAndBooleanProvider);
+ instance.lazyFloat = DoubleCheckLazy.create(boxedFloatAndPrimitiveFloatAndFloatProvider);
+ instance.lazyDouble = DoubleCheckLazy.create(boxedDoubleAndPrimitiveDoubleAndDoubleProvider);
+ instance.boxedBype = boxedBypeAndPrimitiveByteAndByteProvider.get();
+ instance.boxedChar = boxedCharAndPrimitiveCharAndCharProvider.get();
+ instance.boxedShort = boxedShortAndPrimitiveShortAndShortProvider.get();
+ instance.boxedInt = boxedIntAndPrimitiveIntAndIntProvider.get();
+ instance.boxedLong = boxedLongAndPrimitiveLongAndLongProvider.get();
+ instance.boxedBoolean = boxedBooleanAndPrimitiveBooleanAndBooleanProvider.get();
+ instance.boxedFloat = boxedFloatAndPrimitiveFloatAndFloatProvider.get();
+ instance.boxedDouble = boxedDoubleAndPrimitiveDoubleAndDoubleProvider.get();
+ instance.byteArray = byteArrayProvider.get();
+ instance.charArray = charArrayProvider.get();
+ instance.shortArray = shortArrayProvider.get();
+ instance.intArray = intArrayProvider.get();
+ instance.longArray = longArrayProvider.get();
+ instance.booleanArray = booleanArrayProvider.get();
+ instance.floatArray = floatArrayAndLazyProvider.get();
+ instance.doubleArray = doubleArrayProvider.get();
+ instance.byteArrayProvider = byteArrayProvider;
+ instance.charArrayProvider = charArrayProvider;
+ instance.shortArrayProvider = shortArrayProvider;
+ instance.intArrayProvider = intArrayProvider;
+ instance.longArrayProvider = longArrayProvider;
+ instance.booleanArrayProvider = booleanArrayProvider;
+ instance.floatArrayProvider = floatArrayAndLazyProvider;
+ instance.doubleArrayProvider = doubleArrayProvider;
+ instance.lazyByteArray = DoubleCheckLazy.create(byteArrayProvider);
+ instance.lazyCharArray = DoubleCheckLazy.create(charArrayProvider);
+ instance.lazyShortArray = DoubleCheckLazy.create(shortArrayProvider);
+ instance.lazyIntArray = DoubleCheckLazy.create(intArrayProvider);
+ instance.lazyLongArray = DoubleCheckLazy.create(longArrayProvider);
+ instance.lazyBooleanArray = DoubleCheckLazy.create(booleanArrayProvider);
+ instance.lazy = DoubleCheckLazy.create(floatArrayAndLazyProvider);
+ instance.lazyDoubleArray = DoubleCheckLazy.create(doubleArrayProvider);
+ instance.thing = thingProvider.get();
+ instance.thingProvider = thingProvider;
+ instance.lazyThing = DoubleCheckLazy.create(thingProvider);
+ instance.thingMembersInjector = thingMembersInjector;
+ instance.primitiveByte(boxedBypeAndPrimitiveByteAndByteProvider.get());
+ instance.primitiveChar(boxedCharAndPrimitiveCharAndCharProvider.get());
+ instance.primitiveShort(boxedShortAndPrimitiveShortAndShortProvider.get());
+ instance.primitiveInt(boxedIntAndPrimitiveIntAndIntProvider.get());
+ instance.primitiveLong(boxedLongAndPrimitiveLongAndLongProvider.get());
+ instance.primitiveBoolean(boxedBooleanAndPrimitiveBooleanAndBooleanProvider.get());
+ instance.primitiveFloat(boxedFloatAndPrimitiveFloatAndFloatProvider.get());
+ instance.primitiveDouble(boxedDoubleAndPrimitiveDoubleAndDoubleProvider.get());
+ instance.byteProvider(boxedBypeAndPrimitiveByteAndByteProvider);
+ instance.charProvider(boxedCharAndPrimitiveCharAndCharProvider);
+ instance.shortProvider(boxedShortAndPrimitiveShortAndShortProvider);
+ instance.intProvider(boxedIntAndPrimitiveIntAndIntProvider);
+ instance.longProvider(boxedLongAndPrimitiveLongAndLongProvider);
+ instance.booleanProvider(boxedBooleanAndPrimitiveBooleanAndBooleanProvider);
+ instance.floatProvider(boxedFloatAndPrimitiveFloatAndFloatProvider);
+ instance.doubleProvider(boxedDoubleAndPrimitiveDoubleAndDoubleProvider);
+ instance.lazyByte(DoubleCheckLazy.create(boxedBypeAndPrimitiveByteAndByteProvider));
+ instance.lazyChar(DoubleCheckLazy.create(boxedCharAndPrimitiveCharAndCharProvider));
+ instance.lazyShort(DoubleCheckLazy.create(boxedShortAndPrimitiveShortAndShortProvider));
+ instance.lazyInt(DoubleCheckLazy.create(boxedIntAndPrimitiveIntAndIntProvider));
+ instance.lazyLong(DoubleCheckLazy.create(boxedLongAndPrimitiveLongAndLongProvider));
+ instance.lazyBoolean(DoubleCheckLazy.create(boxedBooleanAndPrimitiveBooleanAndBooleanProvider));
+ instance.lazyFloat(DoubleCheckLazy.create(boxedFloatAndPrimitiveFloatAndFloatProvider));
+ instance.lazyDouble(DoubleCheckLazy.create(boxedDoubleAndPrimitiveDoubleAndDoubleProvider));
+ instance.boxedBype(boxedBypeAndPrimitiveByteAndByteProvider.get());
+ instance.boxedChar(boxedCharAndPrimitiveCharAndCharProvider.get());
+ instance.boxedShort(boxedShortAndPrimitiveShortAndShortProvider.get());
+ instance.boxedInt(boxedIntAndPrimitiveIntAndIntProvider.get());
+ instance.boxedLong(boxedLongAndPrimitiveLongAndLongProvider.get());
+ instance.boxedBoolean(boxedBooleanAndPrimitiveBooleanAndBooleanProvider.get());
+ instance.boxedFloat(boxedFloatAndPrimitiveFloatAndFloatProvider.get());
+ instance.boxedDouble(boxedDoubleAndPrimitiveDoubleAndDoubleProvider.get());
+ instance.byteArray(byteArrayProvider.get());
+ instance.charArray(charArrayProvider.get());
+ instance.shortArray(shortArrayProvider.get());
+ instance.intArray(intArrayProvider.get());
+ instance.longArray(longArrayProvider.get());
+ instance.booleanArray(booleanArrayProvider.get());
+ instance.floatArray(floatArrayAndLazyProvider.get());
+ instance.doubleArray(doubleArrayProvider.get());
+ instance.byteArrayProvider(byteArrayProvider);
+ instance.charArrayProvider(charArrayProvider);
+ instance.shortArrayProvider(shortArrayProvider);
+ instance.intArrayProvider(intArrayProvider);
+ instance.longArrayProvider(longArrayProvider);
+ instance.booleanArrayProvider(booleanArrayProvider);
+ instance.floatArrayProvider(floatArrayAndLazyProvider);
+ instance.doubleArrayProvider(doubleArrayProvider);
+ instance.lazyByteArray(DoubleCheckLazy.create(byteArrayProvider));
+ instance.lazyCharArray(DoubleCheckLazy.create(charArrayProvider));
+ instance.lazyShortArray(DoubleCheckLazy.create(shortArrayProvider));
+ instance.lazyIntArray(DoubleCheckLazy.create(intArrayProvider));
+ instance.lazyLongArray(DoubleCheckLazy.create(longArrayProvider));
+ instance.lazyBooleanArray(DoubleCheckLazy.create(booleanArrayProvider));
+ instance.lazy(DoubleCheckLazy.create(floatArrayAndLazyProvider));
+ instance.lazyDoubleArray(DoubleCheckLazy.create(doubleArrayProvider));
+ instance.thing(thingProvider.get());
+ instance.thingProvider(thingProvider);
+ instance.lazyThing(DoubleCheckLazy.create(thingProvider));
+ instance.thingMembersInjector(thingMembersInjector);
+ }
+
+ public static MembersInjector<InjectedThing> create(Provider<Byte> boxedBypeAndPrimitiveByteAndByteProvider, Provider<Character> boxedCharAndPrimitiveCharAndCharProvider, Provider<Short> boxedShortAndPrimitiveShortAndShortProvider, Provider<Integer> boxedIntAndPrimitiveIntAndIntProvider, Provider<Long> boxedLongAndPrimitiveLongAndLongProvider, Provider<Boolean> boxedBooleanAndPrimitiveBooleanAndBooleanProvider, Provider<Float> boxedFloatAndPrimitiveFloatAndFloatProvider, Provider<Double> boxedDoubleAndPrimitiveDoubleAndDoubleProvider, Provider<byte[]> byteArrayProvider, Provider<char[]> charArrayProvider, Provider<short[]> shortArrayProvider, Provider<int[]> intArrayProvider, Provider<long[]> longArrayProvider, Provider<boolean[]> booleanArrayProvider, Provider<float[]> floatArrayAndLazyProvider, Provider<double[]> doubleArrayProvider, Provider<Thing> thingProvider, MembersInjector<Thing> thingMembersInjector) {
+ return new InjectedThing_MembersInjector(boxedBypeAndPrimitiveByteAndByteProvider, boxedCharAndPrimitiveCharAndCharProvider, boxedShortAndPrimitiveShortAndShortProvider, boxedIntAndPrimitiveIntAndIntProvider, boxedLongAndPrimitiveLongAndLongProvider, boxedBooleanAndPrimitiveBooleanAndBooleanProvider, boxedFloatAndPrimitiveFloatAndFloatProvider, boxedDoubleAndPrimitiveDoubleAndDoubleProvider, byteArrayProvider, charArrayProvider, shortArrayProvider, intArrayProvider, longArrayProvider, booleanArrayProvider, floatArrayAndLazyProvider, doubleArrayProvider, thingProvider, thingMembersInjector);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideBarKeyFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideBarKeyFactory.java
new file mode 100644
index 000000000..85e6c03ea
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideBarKeyFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ProvideBarKeyFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ProvideBarKeyFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.provideBarKey();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ProvideBarKeyFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideFiveToSetFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideFiveToSetFactory.java
new file mode 100644
index 000000000..5e6eb7465
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideFiveToSetFactory.java
@@ -0,0 +1,26 @@
+package test;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ProvideFiveToSetFactory implements Factory<Set<Integer>> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ProvideFiveToSetFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Set<Integer> get() {
+ return Collections.<Integer>singleton(module.provideFiveToSet());
+ }
+
+ public static Factory<Set<Integer>> create(MultibindingModule module) {
+ return new MultibindingModule_ProvideFiveToSetFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideFooKeyFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideFooKeyFactory.java
new file mode 100644
index 000000000..fc5765a5a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideFooKeyFactory.java
@@ -0,0 +1,32 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ProvideFooKeyFactory implements Factory<String> {
+ private final MultibindingModule module;
+ private final Provider<Double> doubleDependencyProvider;
+
+ public MultibindingModule_ProvideFooKeyFactory(MultibindingModule module, Provider<Double> doubleDependencyProvider) {
+ assert module != null;
+ this.module = module;
+ assert doubleDependencyProvider != null;
+ this.doubleDependencyProvider = doubleDependencyProvider;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.provideFooKey(doubleDependencyProvider.get());
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module, Provider<Double> doubleDependencyProvider) {
+ return new MultibindingModule_ProvideFooKeyFactory(module, doubleDependencyProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideMapKeysFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideMapKeysFactory.java
new file mode 100644
index 000000000..e77002741
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideMapKeysFactory.java
@@ -0,0 +1,34 @@
+package test;
+
+import dagger.internal.Factory;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ProvideMapKeysFactory implements Factory<Set<String>> {
+ private final MultibindingModule module;
+ private final Provider<Map<String, Provider<String>>> mapProvider;
+
+ public MultibindingModule_ProvideMapKeysFactory(MultibindingModule module, Provider<Map<String, Provider<String>>> mapProvider) {
+ assert module != null;
+ this.module = module;
+ assert mapProvider != null;
+ this.mapProvider = mapProvider;
+ }
+
+ @Override
+ public Set<String> get() {
+ Set<String> provided = module.provideMapKeys(mapProvider.get());
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Set<String>> create(MultibindingModule module, Provider<Map<String, Provider<String>>> mapProvider) {
+ return new MultibindingModule_ProvideMapKeysFactory(module, mapProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideMapValuesFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideMapValuesFactory.java
new file mode 100644
index 000000000..d38ff0177
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideMapValuesFactory.java
@@ -0,0 +1,34 @@
+package test;
+
+import dagger.internal.Factory;
+import java.util.Collection;
+import java.util.Map;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ProvideMapValuesFactory implements Factory<Collection<String>> {
+ private final MultibindingModule module;
+ private final Provider<Map<String, String>> mapProvider;
+
+ public MultibindingModule_ProvideMapValuesFactory(MultibindingModule module, Provider<Map<String, String>> mapProvider) {
+ assert module != null;
+ this.module = module;
+ assert mapProvider != null;
+ this.mapProvider = mapProvider;
+ }
+
+ @Override
+ public Collection<String> get() {
+ Collection<String> provided = module.provideMapValues(mapProvider.get());
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Collection<String>> create(MultibindingModule module, Provider<Map<String, String>> mapProvider) {
+ return new MultibindingModule_ProvideMapValuesFactory(module, mapProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideSixToSetFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideSixToSetFactory.java
new file mode 100644
index 000000000..ede45a90a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ProvideSixToSetFactory.java
@@ -0,0 +1,26 @@
+package test;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ProvideSixToSetFactory implements Factory<Set<Integer>> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ProvideSixToSetFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Set<Integer> get() {
+ return Collections.<Integer>singleton(module.provideSixToSet());
+ }
+
+ public static Factory<Set<Integer>> create(MultibindingModule module) {
+ return new MultibindingModule_ProvideSixToSetFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100ByteFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100ByteFactory.java
new file mode 100644
index 000000000..b56334ca9
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100ByteFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ValueFor100ByteFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ValueFor100ByteFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.valueFor100Byte();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ValueFor100ByteFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100IntFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100IntFactory.java
new file mode 100644
index 000000000..bd82beeeb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100IntFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ValueFor100IntFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ValueFor100IntFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.valueFor100Int();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ValueFor100IntFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100LongFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100LongFactory.java
new file mode 100644
index 000000000..9930a109b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100LongFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ValueFor100LongFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ValueFor100LongFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.valueFor100Long();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ValueFor100LongFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100ShortFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100ShortFactory.java
new file mode 100644
index 000000000..a4a7e3b11
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueFor100ShortFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ValueFor100ShortFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ValueFor100ShortFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.valueFor100Short();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ValueFor100ShortFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForAFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForAFactory.java
new file mode 100644
index 000000000..622feddd2
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForAFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ValueForAFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ValueForAFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.valueForA();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ValueForAFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForClassIntegerFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForClassIntegerFactory.java
new file mode 100644
index 000000000..be5081345
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForClassIntegerFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ValueForClassIntegerFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ValueForClassIntegerFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.valueForClassInteger();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ValueForClassIntegerFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForClassLongFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForClassLongFactory.java
new file mode 100644
index 000000000..c97cde628
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForClassLongFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ValueForClassLongFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ValueForClassLongFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.valueForClassLong();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ValueForClassLongFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForIntegerFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForIntegerFactory.java
new file mode 100644
index 000000000..cbdb2f9d3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForIntegerFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ValueForIntegerFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ValueForIntegerFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.valueForInteger();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ValueForIntegerFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForLongFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForLongFactory.java
new file mode 100644
index 000000000..dccab1af3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForLongFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ValueForLongFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ValueForLongFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.valueForLong();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ValueForLongFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForNewlineFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForNewlineFactory.java
new file mode 100644
index 000000000..7b55a13e6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForNewlineFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ValueForNewlineFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ValueForNewlineFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.valueForNewline();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ValueForNewlineFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForNumberClassBigDecimalFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForNumberClassBigDecimalFactory.java
new file mode 100644
index 000000000..c85c73af8
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForNumberClassBigDecimalFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ValueForNumberClassBigDecimalFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ValueForNumberClassBigDecimalFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.valueForNumberClassBigDecimal();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ValueForNumberClassBigDecimalFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForNumberClassBigIntegerFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForNumberClassBigIntegerFactory.java
new file mode 100644
index 000000000..38bf88093
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForNumberClassBigIntegerFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ValueForNumberClassBigIntegerFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ValueForNumberClassBigIntegerFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.valueForNumberClassBigInteger();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ValueForNumberClassBigIntegerFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForTrueFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForTrueFactory.java
new file mode 100644
index 000000000..155601d05
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForTrueFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ValueForTrueFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ValueForTrueFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.valueForTrue();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ValueForTrueFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForUnwrappedAnnotationKeyFooFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForUnwrappedAnnotationKeyFooFactory.java
new file mode 100644
index 000000000..bda513b3e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForUnwrappedAnnotationKeyFooFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ValueForUnwrappedAnnotationKeyFooFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ValueForUnwrappedAnnotationKeyFooFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.valueForUnwrappedAnnotationKeyFoo();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ValueForUnwrappedAnnotationKeyFooFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForWrappedAnnotationKeyFooFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForWrappedAnnotationKeyFooFactory.java
new file mode 100644
index 000000000..c92074ed5
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/MultibindingModule_ValueForWrappedAnnotationKeyFooFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingModule_ValueForWrappedAnnotationKeyFooFactory implements Factory<String> {
+ private final MultibindingModule module;
+
+ public MultibindingModule_ValueForWrappedAnnotationKeyFooFactory(MultibindingModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.valueForWrappedAnnotationKeyFoo();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(MultibindingModule module) {
+ return new MultibindingModule_ValueForWrappedAnnotationKeyFooFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/NeedsFactory_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/NeedsFactory_Factory.java
new file mode 100644
index 000000000..72282478e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/NeedsFactory_Factory.java
@@ -0,0 +1,25 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class NeedsFactory_Factory implements Factory<NeedsFactory> {
+ private final Provider<NeedsFactory_SomethingFactory> somethingFactoryProvider;
+
+ public NeedsFactory_Factory(Provider<NeedsFactory_SomethingFactory> somethingFactoryProvider) {
+ assert somethingFactoryProvider != null;
+ this.somethingFactoryProvider = somethingFactoryProvider;
+ }
+
+ @Override
+ public NeedsFactory get() {
+ return new NeedsFactory(somethingFactoryProvider.get());
+ }
+
+ public static Factory<NeedsFactory> create(Provider<NeedsFactory_SomethingFactory> somethingFactoryProvider) {
+ return new NeedsFactory_Factory(somethingFactoryProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/NeedsFactory_SomethingFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/NeedsFactory_SomethingFactory.java
new file mode 100644
index 000000000..e26f39804
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/NeedsFactory_SomethingFactory.java
@@ -0,0 +1,13 @@
+package test;
+
+import javax.annotation.Generated;
+import javax.inject.Inject;
+@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
+final class NeedsFactory_SomethingFactory {
+ @Inject
+ NeedsFactory_SomethingFactory() {
+ }
+ NeedsFactory.Something create() {
+ return new NeedsFactory.Something();
+ }
+}
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/NeedsFactory_SomethingFactory_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/NeedsFactory_SomethingFactory_Factory.java
new file mode 100644
index 000000000..471304a31
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/NeedsFactory_SomethingFactory_Factory.java
@@ -0,0 +1,19 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum NeedsFactory_SomethingFactory_Factory implements Factory<NeedsFactory_SomethingFactory> {
+INSTANCE;
+
+ @Override
+ public NeedsFactory_SomethingFactory get() {
+ return new NeedsFactory_SomethingFactory();
+ }
+
+ public static Factory<NeedsFactory_SomethingFactory> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/NonComponentDependencyComponent$ThingTwo_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/NonComponentDependencyComponent$ThingTwo_Factory.java
new file mode 100644
index 000000000..d0665558e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/NonComponentDependencyComponent$ThingTwo_Factory.java
@@ -0,0 +1,33 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.NonComponentDependencyComponent.ThingComponent;
+import test.NonComponentDependencyComponent.ThingTwo;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class NonComponentDependencyComponent$ThingTwo_Factory implements Factory<ThingTwo> {
+ private final Provider<Thing> thingProvider;
+ private final Provider<NonComponentDependencyComponent> nonComponentDependencyComponentProvider;
+ private final Provider<ThingComponent> thingComponentProvider;
+
+ public NonComponentDependencyComponent$ThingTwo_Factory(Provider<Thing> thingProvider, Provider<NonComponentDependencyComponent> nonComponentDependencyComponentProvider, Provider<ThingComponent> thingComponentProvider) {
+ assert thingProvider != null;
+ this.thingProvider = thingProvider;
+ assert nonComponentDependencyComponentProvider != null;
+ this.nonComponentDependencyComponentProvider = nonComponentDependencyComponentProvider;
+ assert thingComponentProvider != null;
+ this.thingComponentProvider = thingComponentProvider;
+ }
+
+ @Override
+ public ThingTwo get() {
+ return new ThingTwo(thingProvider.get(), nonComponentDependencyComponentProvider.get(), thingComponentProvider.get());
+ }
+
+ public static Factory<ThingTwo> create(Provider<Thing> thingProvider, Provider<NonComponentDependencyComponent> nonComponentDependencyComponentProvider, Provider<ThingComponent> thingComponentProvider) {
+ return new NonComponentDependencyComponent$ThingTwo_Factory(thingProvider, nonComponentDependencyComponentProvider, thingComponentProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ParentModule_ProvideIterableOfAWithCFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ParentModule_ProvideIterableOfAWithCFactory.java
new file mode 100644
index 000000000..89a013ca2
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ParentModule_ProvideIterableOfAWithCFactory.java
@@ -0,0 +1,35 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ParentModule_ProvideIterableOfAWithCFactory<A extends Number & Comparable<A>, B, C extends Iterable<A>> implements Factory<Iterable<A>> {
+ private final ParentModule<A, B, C> module;
+ private final Provider<A> aProvider;
+ private final Provider<C> cProvider;
+
+ public ParentModule_ProvideIterableOfAWithCFactory(ParentModule<A, B, C> module, Provider<A> aProvider, Provider<C> cProvider) {
+ assert module != null;
+ this.module = module;
+ assert aProvider != null;
+ this.aProvider = aProvider;
+ assert cProvider != null;
+ this.cProvider = cProvider;
+ }
+
+ @Override
+ public Iterable<A> get() {
+ Iterable<A> provided = module.provideIterableOfAWithC(aProvider.get(), cProvider.get());
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static <A extends Number & Comparable<A>, B, C extends Iterable<A>> Factory<Iterable<A>> create(ParentModule<A, B, C> module, Provider<A> aProvider, Provider<C> cProvider) {
+ return new ParentModule_ProvideIterableOfAWithCFactory<A, B, C>(module, aProvider, cProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_BoundDoubleArrayFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_BoundDoubleArrayFactory.java
new file mode 100644
index 000000000..adc286bff
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_BoundDoubleArrayFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_BoundDoubleArrayFactory implements Factory<double[]> {
+INSTANCE;
+
+ @Override
+ public double[] get() {
+ double[] provided = PrimitivesModule.boundDoubleArray();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<double[]> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_BoundDoubleFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_BoundDoubleFactory.java
new file mode 100644
index 000000000..dd6ec9fb8
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_BoundDoubleFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_BoundDoubleFactory implements Factory<Double> {
+INSTANCE;
+
+ @Override
+ public Double get() {
+ Double provided = PrimitivesModule.boundDouble();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Double> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideBooleanArrayFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideBooleanArrayFactory.java
new file mode 100644
index 000000000..886a13009
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideBooleanArrayFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_ProvideBooleanArrayFactory implements Factory<boolean[]> {
+INSTANCE;
+
+ @Override
+ public boolean[] get() {
+ boolean[] provided = PrimitivesModule.provideBooleanArray();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<boolean[]> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideBooleanFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideBooleanFactory.java
new file mode 100644
index 000000000..4f19803a0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideBooleanFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_ProvideBooleanFactory implements Factory<Boolean> {
+INSTANCE;
+
+ @Override
+ public Boolean get() {
+ Boolean provided = PrimitivesModule.provideBoolean();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Boolean> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideByteArrayFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideByteArrayFactory.java
new file mode 100644
index 000000000..0b2badc29
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideByteArrayFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_ProvideByteArrayFactory implements Factory<byte[]> {
+INSTANCE;
+
+ @Override
+ public byte[] get() {
+ byte[] provided = PrimitivesModule.provideByteArray();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<byte[]> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideByteFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideByteFactory.java
new file mode 100644
index 000000000..a3e07e2b6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideByteFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_ProvideByteFactory implements Factory<Byte> {
+INSTANCE;
+
+ @Override
+ public Byte get() {
+ Byte provided = PrimitivesModule.provideByte();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Byte> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideCharArrayFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideCharArrayFactory.java
new file mode 100644
index 000000000..91fe5f802
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideCharArrayFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_ProvideCharArrayFactory implements Factory<char[]> {
+INSTANCE;
+
+ @Override
+ public char[] get() {
+ char[] provided = PrimitivesModule.provideCharArray();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<char[]> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideCharFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideCharFactory.java
new file mode 100644
index 000000000..3bab0df7b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideCharFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_ProvideCharFactory implements Factory<Character> {
+INSTANCE;
+
+ @Override
+ public Character get() {
+ Character provided = PrimitivesModule.provideChar();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Character> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideFloatArrayFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideFloatArrayFactory.java
new file mode 100644
index 000000000..6a0a3d58c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideFloatArrayFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_ProvideFloatArrayFactory implements Factory<float[]> {
+INSTANCE;
+
+ @Override
+ public float[] get() {
+ float[] provided = PrimitivesModule.provideFloatArray();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<float[]> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideFloatFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideFloatFactory.java
new file mode 100644
index 000000000..c24913b9f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideFloatFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_ProvideFloatFactory implements Factory<Float> {
+INSTANCE;
+
+ @Override
+ public Float get() {
+ Float provided = PrimitivesModule.provideFloat();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Float> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideIntArrayFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideIntArrayFactory.java
new file mode 100644
index 000000000..37e594b63
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideIntArrayFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_ProvideIntArrayFactory implements Factory<int[]> {
+INSTANCE;
+
+ @Override
+ public int[] get() {
+ int[] provided = PrimitivesModule.provideIntArray();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<int[]> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideIntFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideIntFactory.java
new file mode 100644
index 000000000..8d8f83082
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideIntFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_ProvideIntFactory implements Factory<Integer> {
+INSTANCE;
+
+ @Override
+ public Integer get() {
+ Integer provided = PrimitivesModule.provideInt();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Integer> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideLongArrayFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideLongArrayFactory.java
new file mode 100644
index 000000000..190f69b31
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideLongArrayFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_ProvideLongArrayFactory implements Factory<long[]> {
+INSTANCE;
+
+ @Override
+ public long[] get() {
+ long[] provided = PrimitivesModule.provideLongArray();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<long[]> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideLongFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideLongFactory.java
new file mode 100644
index 000000000..9713a5642
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideLongFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_ProvideLongFactory implements Factory<Long> {
+INSTANCE;
+
+ @Override
+ public Long get() {
+ Long provided = PrimitivesModule.provideLong();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Long> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideShortArrayFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideShortArrayFactory.java
new file mode 100644
index 000000000..3d415e48d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideShortArrayFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_ProvideShortArrayFactory implements Factory<short[]> {
+INSTANCE;
+
+ @Override
+ public short[] get() {
+ short[] provided = PrimitivesModule.provideShortArray();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<short[]> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideShortFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideShortFactory.java
new file mode 100644
index 000000000..2a956f1f6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/PrimitivesModule_ProvideShortFactory.java
@@ -0,0 +1,23 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PrimitivesModule_ProvideShortFactory implements Factory<Short> {
+INSTANCE;
+
+ @Override
+ public Short get() {
+ Short provided = PrimitivesModule.provideShort();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Short> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ReferencesGeneric_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ReferencesGeneric_Factory.java
new file mode 100644
index 000000000..1378694bf
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ReferencesGeneric_Factory.java
@@ -0,0 +1,25 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ReferencesGeneric_Factory implements Factory<ReferencesGeneric> {
+ private final Provider<Generic<A>> genericAProvider;
+
+ public ReferencesGeneric_Factory(Provider<Generic<A>> genericAProvider) {
+ assert genericAProvider != null;
+ this.genericAProvider = genericAProvider;
+ }
+
+ @Override
+ public ReferencesGeneric get() {
+ return new ReferencesGeneric(genericAProvider.get());
+ }
+
+ public static Factory<ReferencesGeneric> create(Provider<Generic<A>> genericAProvider) {
+ return new ReferencesGeneric_Factory(genericAProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ScopedGeneric_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ScopedGeneric_Factory.java
new file mode 100644
index 000000000..5a5be87a3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/ScopedGeneric_Factory.java
@@ -0,0 +1,25 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ScopedGeneric_Factory<T> implements Factory<ScopedGeneric<T>> {
+ private final Provider<T> tProvider;
+
+ public ScopedGeneric_Factory(Provider<T> tProvider) {
+ assert tProvider != null;
+ this.tProvider = tProvider;
+ }
+
+ @Override
+ public ScopedGeneric<T> get() {
+ return new ScopedGeneric<T>(tProvider.get());
+ }
+
+ public static <T> Factory<ScopedGeneric<T>> create(Provider<T> tProvider) {
+ return new ScopedGeneric_Factory<T>(tProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/TestStringKey$NestedWrappedKeyCreator.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/TestStringKey$NestedWrappedKeyCreator.java
new file mode 100644
index 000000000..2c73118de
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/TestStringKey$NestedWrappedKeyCreator.java
@@ -0,0 +1,13 @@
+package test;
+
+import javax.annotation.Generated;
+import test.TestStringKey.NestedWrappedKey;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class TestStringKey$NestedWrappedKeyCreator {
+ @com.google.auto.value.AutoAnnotation
+ public static NestedWrappedKey createNestedWrappedKey(Class<?> value) {
+ return new AutoAnnotation_TestStringKey$NestedWrappedKeyCreator_createNestedWrappedKey(value);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/TestUnwrappedAnnotationKeyCreator.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/TestUnwrappedAnnotationKeyCreator.java
new file mode 100644
index 000000000..629fd91b4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/TestUnwrappedAnnotationKeyCreator.java
@@ -0,0 +1,12 @@
+package test;
+
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class TestUnwrappedAnnotationKeyCreator {
+ @com.google.auto.value.AutoAnnotation
+ public static TestStringKey createTestStringKey(String value) {
+ return new AutoAnnotation_TestUnwrappedAnnotationKeyCreator_createTestStringKey(value);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/TestWrappedAnnotationKeyCreator.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/TestWrappedAnnotationKeyCreator.java
new file mode 100644
index 000000000..a0e1a9b50
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/TestWrappedAnnotationKeyCreator.java
@@ -0,0 +1,17 @@
+package test;
+
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class TestWrappedAnnotationKeyCreator {
+ @com.google.auto.value.AutoAnnotation
+ public static TestWrappedAnnotationKey createTestWrappedAnnotationKey(TestStringKey value, int[] integers, TestClassKey[] annotations, Class<? extends Number>[] classes) {
+ return new AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestWrappedAnnotationKey(value, integers, annotations, classes);
+ }
+
+ @com.google.auto.value.AutoAnnotation
+ public static TestStringKey createTestStringKey(String value) {
+ return new AutoAnnotation_TestWrappedAnnotationKeyCreator_createTestStringKey(value);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/Thing_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/Thing_Factory.java
new file mode 100644
index 000000000..f05092217
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/Thing_Factory.java
@@ -0,0 +1,26 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.sub.OtherThing;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class Thing_Factory implements Factory<Thing> {
+ private final Provider<OtherThing> unusedProvider;
+
+ public Thing_Factory(Provider<OtherThing> unusedProvider) {
+ assert unusedProvider != null;
+ this.unusedProvider = unusedProvider;
+ }
+
+ @Override
+ public Thing get() {
+ return new Thing(unusedProvider.get());
+ }
+
+ public static Factory<Thing> create(Provider<OtherThing> unusedProvider) {
+ return new Thing_Factory(unusedProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/TypeWithInheritedMembersInjection_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/TypeWithInheritedMembersInjection_Factory.java
new file mode 100644
index 000000000..8540d629c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/TypeWithInheritedMembersInjection_Factory.java
@@ -0,0 +1,27 @@
+package test;
+
+import dagger.MembersInjector;
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class TypeWithInheritedMembersInjection_Factory implements Factory<TypeWithInheritedMembersInjection> {
+ private final MembersInjector<TypeWithInheritedMembersInjection> membersInjector;
+
+ public TypeWithInheritedMembersInjection_Factory(MembersInjector<TypeWithInheritedMembersInjection> membersInjector) {
+ assert membersInjector != null;
+ this.membersInjector = membersInjector;
+ }
+
+ @Override
+ public TypeWithInheritedMembersInjection get() {
+ TypeWithInheritedMembersInjection instance = new TypeWithInheritedMembersInjection();
+ membersInjector.injectMembers(instance);
+ return instance;
+ }
+
+ public static Factory<TypeWithInheritedMembersInjection> create(MembersInjector<TypeWithInheritedMembersInjection> membersInjector) {
+ return new TypeWithInheritedMembersInjection_Factory(membersInjector);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/ByteModule_BFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/ByteModule_BFactory.java
new file mode 100644
index 000000000..ca35d3902
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/ByteModule_BFactory.java
@@ -0,0 +1,28 @@
+package test.builder;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ByteModule_BFactory implements Factory<Byte> {
+ private final ByteModule module;
+
+ public ByteModule_BFactory(ByteModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Byte get() {
+ Byte provided = module.b();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Byte> create(ByteModule module) {
+ return new ByteModule_BFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerDepComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerDepComponent.java
new file mode 100644
index 000000000..f5ad9a558
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerDepComponent.java
@@ -0,0 +1,28 @@
+package test.builder;
+
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerDepComponent implements DepComponent {
+ private DaggerDepComponent(Builder builder) {
+ assert builder != null;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static DepComponent create() {
+ return builder().build();
+ }
+
+ public static final class Builder {
+ private Builder() {
+ }
+
+ public DepComponent build() {
+ return new DaggerDepComponent(this);
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerParentComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerParentComponent.java
new file mode 100644
index 000000000..42c668a0e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerParentComponent.java
@@ -0,0 +1,519 @@
+package test.builder;
+
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.builder.Grandchild;
+import test.builder.MiddleChild;
+import test.builder.OtherMiddleChild;
+import test.builder.TestChildComponentWithBuilderAbstractClass;
+import test.builder.TestChildComponentWithBuilderInterface;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerParentComponent implements ParentComponent {
+ private DaggerParentComponent(Builder builder) {
+ assert builder != null;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static ParentComponent create() {
+ return builder().build();
+ }
+
+ @Override
+ public TestChildComponentWithBuilderAbstractClass.Builder childAbstractClassBuilder() {
+ return new TestChildComponentWithBuilderAbstractClassBuilder();
+ }
+
+ @Override
+ public TestChildComponentWithBuilderInterface.Builder childInterfaceBuilder() {
+ return new TestChildComponentWithBuilderInterfaceBuilder();
+ }
+
+ @Override
+ public MiddleChild.Builder middleBuilder() {
+ return new MiddleChildBuilder();
+ }
+
+ @Override
+ public OtherMiddleChild.Builder otherBuilder() {
+ return new OtherMiddleChildBuilder();
+ }
+
+ public static final class Builder {
+ private Builder() {
+ }
+
+ public ParentComponent build() {
+ return new DaggerParentComponent(this);
+ }
+ }
+
+ private final class TestChildComponentWithBuilderAbstractClassImpl implements TestChildComponentWithBuilderAbstractClass {
+ private Provider<String> stringProvider;
+ private Provider<Integer> integerProvider;
+ private Provider<Long> lProvider;
+ private Provider<Float> fProvider;
+ private Provider<Double> dProvider;
+ private Provider<Byte> bProvider;
+
+ private TestChildComponentWithBuilderAbstractClassImpl(TestChildComponentWithBuilderAbstractClassBuilder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ private void initialize(final TestChildComponentWithBuilderAbstractClassBuilder builder) {
+ this.stringProvider = StringModule_StringFactory.create(builder.stringModule);
+ this.integerProvider = IntModuleIncludingDoubleAndFloat_IntegerFactory.create(builder.intModuleIncludingDoubleAndFloat);
+ this.lProvider = LongModule_LFactory.create(builder.longModule);
+ this.fProvider = FloatModule_FFactory.create(builder.floatModule);
+ this.dProvider = DoubleModule_DFactory.create(builder.doubleModule);
+ this.bProvider = ByteModule_BFactory.create(builder.byteModule);
+ }
+
+ @Override
+ public String s() {
+ return stringProvider.get();
+ }
+
+ @Override
+ public int i() {
+ return integerProvider.get();
+ }
+
+ @Override
+ public long l() {
+ return lProvider.get();
+ }
+
+ @Override
+ public float f() {
+ return fProvider.get();
+ }
+
+ @Override
+ public double d() {
+ return dProvider.get();
+ }
+
+ @Override
+ public byte b() {
+ return bProvider.get();
+ }
+ }
+
+ private final class TestChildComponentWithBuilderAbstractClassBuilder extends TestChildComponentWithBuilderAbstractClass.Builder {
+ private StringModule stringModule;
+ private IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat;
+ private DoubleModule doubleModule;
+ private FloatModule floatModule;
+ private LongModule longModule;
+ private ByteModule byteModule;
+
+
+ @Override
+ public TestChildComponentWithBuilderAbstractClass build() {
+ if (stringModule == null) {
+ throw new IllegalStateException("stringModule must be set");
+ }
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new IllegalStateException("intModuleIncludingDoubleAndFloat must be set");
+ }
+ if (doubleModule == null) {
+ this.doubleModule = new DoubleModule();
+ }
+ if (floatModule == null) {
+ this.floatModule = new FloatModule();
+ }
+ if (longModule == null) {
+ this.longModule = new LongModule();
+ }
+ if (byteModule == null) {
+ throw new IllegalStateException("byteModule must be set");
+ }
+ return new TestChildComponentWithBuilderAbstractClassImpl(this);
+ }
+
+ @Override
+ public TestChildComponentWithBuilderAbstractClassBuilder setM1(StringModule stringModule) {
+ if (stringModule == null) {
+ throw new NullPointerException("stringModule");
+ }
+ this.stringModule = stringModule;
+ return this;
+ }
+
+ @Override
+ public TestChildComponentWithBuilderAbstractClassBuilder setM2(IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat) {
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new NullPointerException("intModuleIncludingDoubleAndFloat");
+ }
+ this.intModuleIncludingDoubleAndFloat = intModuleIncludingDoubleAndFloat;
+ return this;
+ }
+
+ @Override
+ public void setM3(DoubleModule doubleModule) {
+ if (doubleModule == null) {
+ throw new NullPointerException("doubleModule");
+ }
+ this.doubleModule = doubleModule;
+ }
+
+ @Override
+ public TestChildComponentWithBuilderAbstractClassBuilder set(FloatModule floatModule) {
+ if (floatModule == null) {
+ throw new NullPointerException("floatModule");
+ }
+ this.floatModule = floatModule;
+ return this;
+ }
+
+ @Override
+ public void set(ByteModule byteModule) {
+ if (byteModule == null) {
+ throw new NullPointerException("byteModule");
+ }
+ this.byteModule = byteModule;
+ }
+ }
+
+ private final class TestChildComponentWithBuilderInterfaceImpl implements TestChildComponentWithBuilderInterface {
+ private Provider<String> stringProvider;
+ private Provider<Integer> integerProvider;
+ private Provider<Long> lProvider;
+ private Provider<Float> fProvider;
+ private Provider<Double> dProvider;
+ private Provider<Byte> bProvider;
+
+ private TestChildComponentWithBuilderInterfaceImpl(TestChildComponentWithBuilderInterfaceBuilder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ private void initialize(final TestChildComponentWithBuilderInterfaceBuilder builder) {
+ this.stringProvider = StringModule_StringFactory.create(builder.stringModule);
+ this.integerProvider = IntModuleIncludingDoubleAndFloat_IntegerFactory.create(builder.intModuleIncludingDoubleAndFloat);
+ this.lProvider = LongModule_LFactory.create(builder.longModule);
+ this.fProvider = FloatModule_FFactory.create(builder.floatModule);
+ this.dProvider = DoubleModule_DFactory.create(builder.doubleModule);
+ this.bProvider = ByteModule_BFactory.create(builder.byteModule);
+ }
+
+ @Override
+ public String s() {
+ return stringProvider.get();
+ }
+
+ @Override
+ public int i() {
+ return integerProvider.get();
+ }
+
+ @Override
+ public long l() {
+ return lProvider.get();
+ }
+
+ @Override
+ public float f() {
+ return fProvider.get();
+ }
+
+ @Override
+ public double d() {
+ return dProvider.get();
+ }
+
+ @Override
+ public byte b() {
+ return bProvider.get();
+ }
+ }
+
+ private final class TestChildComponentWithBuilderInterfaceBuilder implements TestChildComponentWithBuilderInterface.Builder {
+ private StringModule stringModule;
+ private IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat;
+ private DoubleModule doubleModule;
+ private FloatModule floatModule;
+ private LongModule longModule;
+ private ByteModule byteModule;
+
+
+ @Override
+ public TestChildComponentWithBuilderInterface build() {
+ if (stringModule == null) {
+ throw new IllegalStateException("stringModule must be set");
+ }
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new IllegalStateException("intModuleIncludingDoubleAndFloat must be set");
+ }
+ if (doubleModule == null) {
+ this.doubleModule = new DoubleModule();
+ }
+ if (floatModule == null) {
+ this.floatModule = new FloatModule();
+ }
+ if (longModule == null) {
+ this.longModule = new LongModule();
+ }
+ if (byteModule == null) {
+ throw new IllegalStateException("byteModule must be set");
+ }
+ return new TestChildComponentWithBuilderInterfaceImpl(this);
+ }
+
+ @Override
+ public TestChildComponentWithBuilderInterfaceBuilder setM1(StringModule stringModule) {
+ if (stringModule == null) {
+ throw new NullPointerException("stringModule");
+ }
+ this.stringModule = stringModule;
+ return this;
+ }
+
+ @Override
+ public TestChildComponentWithBuilderInterfaceBuilder setM2(IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat) {
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new NullPointerException("intModuleIncludingDoubleAndFloat");
+ }
+ this.intModuleIncludingDoubleAndFloat = intModuleIncludingDoubleAndFloat;
+ return this;
+ }
+
+ @Override
+ public void setM3(DoubleModule doubleModule) {
+ if (doubleModule == null) {
+ throw new NullPointerException("doubleModule");
+ }
+ this.doubleModule = doubleModule;
+ }
+
+ @Override
+ public TestChildComponentWithBuilderInterfaceBuilder set(FloatModule floatModule) {
+ if (floatModule == null) {
+ throw new NullPointerException("floatModule");
+ }
+ this.floatModule = floatModule;
+ return this;
+ }
+
+ @Override
+ public void set(ByteModule byteModule) {
+ if (byteModule == null) {
+ throw new NullPointerException("byteModule");
+ }
+ this.byteModule = byteModule;
+ }
+ }
+
+ private final class MiddleChildImpl implements MiddleChild {
+ private Provider<String> stringProvider;
+
+ private MiddleChildImpl(MiddleChildBuilder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ private void initialize(final MiddleChildBuilder builder) {
+ this.stringProvider = StringModule_StringFactory.create(builder.stringModule);
+ }
+
+ @Override
+ public String s() {
+ return stringProvider.get();
+ }
+
+ @Override
+ public Grandchild.Builder grandchildBuilder() {
+ return new GrandchildBuilder();
+ }
+
+ private final class GrandchildImpl implements Grandchild {
+ private Provider<Integer> integerProvider;
+
+ private GrandchildImpl(GrandchildBuilder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ private void initialize(final GrandchildBuilder builder) {
+ this.integerProvider = IntModuleIncludingDoubleAndFloat_IntegerFactory.create(builder.intModuleIncludingDoubleAndFloat);
+ }
+
+ @Override
+ public int i() {
+ return integerProvider.get();
+ }
+
+ @Override
+ public String s() {
+ return MiddleChildImpl.this.stringProvider.get();
+ }
+ }
+
+ private final class GrandchildBuilder implements Grandchild.Builder {
+ private IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat;
+ private DoubleModule doubleModule;
+ private FloatModule floatModule;
+
+
+ @Override
+ public Grandchild build() {
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new IllegalStateException("intModuleIncludingDoubleAndFloat must be set");
+ }
+ if (doubleModule == null) {
+ this.doubleModule = new DoubleModule();
+ }
+ if (floatModule == null) {
+ this.floatModule = new FloatModule();
+ }
+ return new GrandchildImpl(this);
+ }
+
+ @Override
+ public GrandchildBuilder set(IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat) {
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new NullPointerException("intModuleIncludingDoubleAndFloat");
+ }
+ this.intModuleIncludingDoubleAndFloat = intModuleIncludingDoubleAndFloat;
+ return this;
+ }
+ }
+ }
+
+ private final class MiddleChildBuilder implements MiddleChild.Builder {
+ private StringModule stringModule;
+
+
+ @Override
+ public MiddleChild build() {
+ if (stringModule == null) {
+ throw new IllegalStateException("stringModule must be set");
+ }
+ return new MiddleChildImpl(this);
+ }
+
+ @Override
+ public MiddleChildBuilder set(StringModule stringModule) {
+ if (stringModule == null) {
+ throw new NullPointerException("stringModule");
+ }
+ this.stringModule = stringModule;
+ return this;
+ }
+ }
+
+ private final class OtherMiddleChildImpl implements OtherMiddleChild {
+ private Provider<Long> lProvider;
+ private Provider<String> stringProvider;
+
+ private OtherMiddleChildImpl(OtherMiddleChildBuilder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ private void initialize(final OtherMiddleChildBuilder builder) {
+ this.lProvider = LongModule_LFactory.create(builder.longModule);
+ this.stringProvider = StringModule_StringFactory.create(builder.stringModule);
+ }
+
+ @Override
+ public long l() {
+ return lProvider.get();
+ }
+
+ @Override
+ public String s() {
+ return stringProvider.get();
+ }
+
+ @Override
+ public Grandchild.Builder grandchildBuilder() {
+ return new GrandchildBuilder();
+ }
+
+ private final class GrandchildImpl implements Grandchild {
+ private Provider<Integer> integerProvider;
+
+ private GrandchildImpl(GrandchildBuilder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ private void initialize(final GrandchildBuilder builder) {
+ this.integerProvider = IntModuleIncludingDoubleAndFloat_IntegerFactory.create(builder.intModuleIncludingDoubleAndFloat);
+ }
+
+ @Override
+ public int i() {
+ return integerProvider.get();
+ }
+
+ @Override
+ public String s() {
+ return OtherMiddleChildImpl.this.stringProvider.get();
+ }
+ }
+
+ private final class GrandchildBuilder implements Grandchild.Builder {
+ private IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat;
+ private DoubleModule doubleModule;
+ private FloatModule floatModule;
+
+
+ @Override
+ public Grandchild build() {
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new IllegalStateException("intModuleIncludingDoubleAndFloat must be set");
+ }
+ if (doubleModule == null) {
+ this.doubleModule = new DoubleModule();
+ }
+ if (floatModule == null) {
+ this.floatModule = new FloatModule();
+ }
+ return new GrandchildImpl(this);
+ }
+
+ @Override
+ public GrandchildBuilder set(IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat) {
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new NullPointerException("intModuleIncludingDoubleAndFloat");
+ }
+ this.intModuleIncludingDoubleAndFloat = intModuleIncludingDoubleAndFloat;
+ return this;
+ }
+ }
+ }
+
+ private final class OtherMiddleChildBuilder implements OtherMiddleChild.Builder {
+ private StringModule stringModule;
+ private LongModule longModule;
+
+
+ @Override
+ public OtherMiddleChild build() {
+ if (stringModule == null) {
+ throw new IllegalStateException("stringModule must be set");
+ }
+ if (longModule == null) {
+ this.longModule = new LongModule();
+ }
+ return new OtherMiddleChildImpl(this);
+ }
+
+ @Override
+ public OtherMiddleChildBuilder set(StringModule stringModule) {
+ if (stringModule == null) {
+ throw new NullPointerException("stringModule");
+ }
+ this.stringModule = stringModule;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerParentOfGenericComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerParentOfGenericComponent.java
new file mode 100644
index 000000000..d9f77a8cc
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerParentOfGenericComponent.java
@@ -0,0 +1,104 @@
+package test.builder;
+
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.builder.Grandchild;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerParentOfGenericComponent implements ParentOfGenericComponent {
+ private Provider<String> stringProvider;
+
+ private DaggerParentOfGenericComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private void initialize(final Builder builder) {
+ this.stringProvider = StringModule_StringFactory.create(builder.stringModule);
+ }
+
+ @Override
+ public Grandchild.Builder subcomponentBuilder() {
+ return new GrandchildBuilder();
+ }
+
+ public static final class Builder {
+ private StringModule stringModule;
+
+ private Builder() {
+ }
+
+ public ParentOfGenericComponent build() {
+ if (stringModule == null) {
+ throw new IllegalStateException("stringModule must be set");
+ }
+ return new DaggerParentOfGenericComponent(this);
+ }
+
+ public Builder stringModule(StringModule stringModule) {
+ if (stringModule == null) {
+ throw new NullPointerException("stringModule");
+ }
+ this.stringModule = stringModule;
+ return this;
+ }
+ }
+
+ private final class GrandchildImpl implements Grandchild {
+ private Provider<Integer> integerProvider;
+
+ private GrandchildImpl(GrandchildBuilder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ private void initialize(final GrandchildBuilder builder) {
+ this.integerProvider = IntModuleIncludingDoubleAndFloat_IntegerFactory.create(builder.intModuleIncludingDoubleAndFloat);
+ }
+
+ @Override
+ public int i() {
+ return integerProvider.get();
+ }
+
+ @Override
+ public String s() {
+ return DaggerParentOfGenericComponent.this.stringProvider.get();
+ }
+ }
+
+ private final class GrandchildBuilder implements Grandchild.Builder {
+ private IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat;
+ private DoubleModule doubleModule;
+ private FloatModule floatModule;
+
+
+ @Override
+ public Grandchild build() {
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new IllegalStateException("intModuleIncludingDoubleAndFloat must be set");
+ }
+ if (doubleModule == null) {
+ this.doubleModule = new DoubleModule();
+ }
+ if (floatModule == null) {
+ this.floatModule = new FloatModule();
+ }
+ return new GrandchildImpl(this);
+ }
+
+ @Override
+ public GrandchildBuilder set(IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat) {
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new NullPointerException("intModuleIncludingDoubleAndFloat");
+ }
+ this.intModuleIncludingDoubleAndFloat = intModuleIncludingDoubleAndFloat;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithBuilderAbstractClass.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithBuilderAbstractClass.java
new file mode 100644
index 000000000..fb9d9b5e4
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithBuilderAbstractClass.java
@@ -0,0 +1,124 @@
+package test.builder;
+
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.builder.TestComponentWithBuilderAbstractClass;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerTestComponentWithBuilderAbstractClass extends TestComponentWithBuilderAbstractClass {
+ private Provider<String> stringProvider;
+ private Provider<Integer> integerProvider;
+ private Provider<Long> lProvider;
+ private Provider<Float> fProvider;
+ private Provider<Double> dProvider;
+
+ private DaggerTestComponentWithBuilderAbstractClass(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static TestComponentWithBuilderAbstractClass.Builder builder() {
+ return new Builder();
+ }
+
+ private void initialize(final Builder builder) {
+ this.stringProvider = StringModule_StringFactory.create(builder.stringModule);
+ this.integerProvider = IntModuleIncludingDoubleAndFloat_IntegerFactory.create(builder.intModuleIncludingDoubleAndFloat);
+ this.lProvider = LongModule_LFactory.create(builder.longModule);
+ this.fProvider = FloatModule_FFactory.create(builder.floatModule);
+ this.dProvider = DoubleModule_DFactory.create(builder.doubleModule);
+ }
+
+ @Override
+ public String s() {
+ return stringProvider.get();
+ }
+
+ @Override
+ public int i() {
+ return integerProvider.get();
+ }
+
+ @Override
+ public long l() {
+ return lProvider.get();
+ }
+
+ @Override
+ public float f() {
+ return fProvider.get();
+ }
+
+ @Override
+ public double d() {
+ return dProvider.get();
+ }
+
+ private static final class Builder extends TestComponentWithBuilderAbstractClass.Builder {
+ private StringModule stringModule;
+ private IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat;
+ private DoubleModule doubleModule;
+ private FloatModule floatModule;
+ private LongModule longModule;
+ private DepComponent depComponent;
+
+
+ @Override
+ public TestComponentWithBuilderAbstractClass build() {
+ if (stringModule == null) {
+ throw new IllegalStateException("stringModule must be set");
+ }
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new IllegalStateException("intModuleIncludingDoubleAndFloat must be set");
+ }
+ if (doubleModule == null) {
+ this.doubleModule = new DoubleModule();
+ }
+ if (floatModule == null) {
+ this.floatModule = new FloatModule();
+ }
+ if (longModule == null) {
+ this.longModule = new LongModule();
+ }
+ if (depComponent == null) {
+ throw new IllegalStateException("depComponent must be set");
+ }
+ return new DaggerTestComponentWithBuilderAbstractClass(this);
+ }
+
+ @Override
+ public Builder stringModule(StringModule stringModule) {
+ if (stringModule == null) {
+ throw new NullPointerException("stringModule");
+ }
+ this.stringModule = stringModule;
+ return this;
+ }
+
+ @Override
+ public Builder intModule(IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat) {
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new NullPointerException("intModuleIncludingDoubleAndFloat");
+ }
+ this.intModuleIncludingDoubleAndFloat = intModuleIncludingDoubleAndFloat;
+ return this;
+ }
+
+ @Override
+ public void doubleModule(DoubleModule doubleModule) {
+ if (doubleModule == null) {
+ throw new NullPointerException("doubleModule");
+ }
+ this.doubleModule = doubleModule;
+ }
+
+ @Override
+ public void depComponent(DepComponent depComponent) {
+ if (depComponent == null) {
+ throw new NullPointerException("depComponent");
+ }
+ this.depComponent = depComponent;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithBuilderInterface.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithBuilderInterface.java
new file mode 100644
index 000000000..196019690
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithBuilderInterface.java
@@ -0,0 +1,124 @@
+package test.builder;
+
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.builder.TestComponentWithBuilderInterface;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerTestComponentWithBuilderInterface implements TestComponentWithBuilderInterface {
+ private Provider<String> stringProvider;
+ private Provider<Integer> integerProvider;
+ private Provider<Long> lProvider;
+ private Provider<Float> fProvider;
+ private Provider<Double> dProvider;
+
+ private DaggerTestComponentWithBuilderInterface(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static TestComponentWithBuilderInterface.Builder builder() {
+ return new Builder();
+ }
+
+ private void initialize(final Builder builder) {
+ this.stringProvider = StringModule_StringFactory.create(builder.stringModule);
+ this.integerProvider = IntModuleIncludingDoubleAndFloat_IntegerFactory.create(builder.intModuleIncludingDoubleAndFloat);
+ this.lProvider = LongModule_LFactory.create(builder.longModule);
+ this.fProvider = FloatModule_FFactory.create(builder.floatModule);
+ this.dProvider = DoubleModule_DFactory.create(builder.doubleModule);
+ }
+
+ @Override
+ public String s() {
+ return stringProvider.get();
+ }
+
+ @Override
+ public int i() {
+ return integerProvider.get();
+ }
+
+ @Override
+ public long l() {
+ return lProvider.get();
+ }
+
+ @Override
+ public float f() {
+ return fProvider.get();
+ }
+
+ @Override
+ public double d() {
+ return dProvider.get();
+ }
+
+ private static final class Builder implements TestComponentWithBuilderInterface.Builder {
+ private StringModule stringModule;
+ private IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat;
+ private DoubleModule doubleModule;
+ private FloatModule floatModule;
+ private LongModule longModule;
+ private DepComponent depComponent;
+
+
+ @Override
+ public TestComponentWithBuilderInterface build() {
+ if (stringModule == null) {
+ throw new IllegalStateException("stringModule must be set");
+ }
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new IllegalStateException("intModuleIncludingDoubleAndFloat must be set");
+ }
+ if (doubleModule == null) {
+ this.doubleModule = new DoubleModule();
+ }
+ if (floatModule == null) {
+ this.floatModule = new FloatModule();
+ }
+ if (longModule == null) {
+ this.longModule = new LongModule();
+ }
+ if (depComponent == null) {
+ throw new IllegalStateException("depComponent must be set");
+ }
+ return new DaggerTestComponentWithBuilderInterface(this);
+ }
+
+ @Override
+ public Builder stringModule(StringModule stringModule) {
+ if (stringModule == null) {
+ throw new NullPointerException("stringModule");
+ }
+ this.stringModule = stringModule;
+ return this;
+ }
+
+ @Override
+ public Builder intModule(IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat) {
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new NullPointerException("intModuleIncludingDoubleAndFloat");
+ }
+ this.intModuleIncludingDoubleAndFloat = intModuleIncludingDoubleAndFloat;
+ return this;
+ }
+
+ @Override
+ public void doubleModule(DoubleModule doubleModule) {
+ if (doubleModule == null) {
+ throw new NullPointerException("doubleModule");
+ }
+ this.doubleModule = doubleModule;
+ }
+
+ @Override
+ public void depComponent(DepComponent depComponent) {
+ if (depComponent == null) {
+ throw new NullPointerException("depComponent");
+ }
+ this.depComponent = depComponent;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass.java
new file mode 100644
index 000000000..53d87c24d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithGenericBuilderAbstractClass.java
@@ -0,0 +1,133 @@
+package test.builder;
+
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.builder.TestComponentWithGenericBuilderAbstractClass;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerTestComponentWithGenericBuilderAbstractClass implements TestComponentWithGenericBuilderAbstractClass {
+ private Provider<String> stringProvider;
+ private Provider<Integer> integerProvider;
+ private Provider<Long> lProvider;
+ private Provider<Float> fProvider;
+ private Provider<Double> dProvider;
+
+ private DaggerTestComponentWithGenericBuilderAbstractClass(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static TestComponentWithGenericBuilderAbstractClass.Builder builder() {
+ return new Builder();
+ }
+
+ private void initialize(final Builder builder) {
+ this.stringProvider = StringModule_StringFactory.create(builder.stringModule);
+ this.integerProvider = IntModuleIncludingDoubleAndFloat_IntegerFactory.create(builder.intModuleIncludingDoubleAndFloat);
+ this.lProvider = LongModule_LFactory.create(builder.longModule);
+ this.fProvider = FloatModule_FFactory.create(builder.floatModule);
+ this.dProvider = DoubleModule_DFactory.create(builder.doubleModule);
+ }
+
+ @Override
+ public String s() {
+ return stringProvider.get();
+ }
+
+ @Override
+ public int i() {
+ return integerProvider.get();
+ }
+
+ @Override
+ public long l() {
+ return lProvider.get();
+ }
+
+ @Override
+ public float f() {
+ return fProvider.get();
+ }
+
+ @Override
+ public double d() {
+ return dProvider.get();
+ }
+
+ private static final class Builder extends TestComponentWithGenericBuilderAbstractClass.Builder {
+ private StringModule stringModule;
+ private IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat;
+ private DoubleModule doubleModule;
+ private FloatModule floatModule;
+ private LongModule longModule;
+ private DepComponent depComponent;
+
+
+ @Override
+ public TestComponentWithGenericBuilderAbstractClass build() {
+ if (stringModule == null) {
+ throw new IllegalStateException("stringModule must be set");
+ }
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new IllegalStateException("intModuleIncludingDoubleAndFloat must be set");
+ }
+ if (doubleModule == null) {
+ this.doubleModule = new DoubleModule();
+ }
+ if (floatModule == null) {
+ this.floatModule = new FloatModule();
+ }
+ if (longModule == null) {
+ this.longModule = new LongModule();
+ }
+ if (depComponent == null) {
+ throw new IllegalStateException("depComponent must be set");
+ }
+ return new DaggerTestComponentWithGenericBuilderAbstractClass(this);
+ }
+
+ @Override
+ public Builder setM1(StringModule stringModule) {
+ if (stringModule == null) {
+ throw new NullPointerException("stringModule");
+ }
+ this.stringModule = stringModule;
+ return this;
+ }
+
+ @Override
+ public Builder setM2(IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat) {
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new NullPointerException("intModuleIncludingDoubleAndFloat");
+ }
+ this.intModuleIncludingDoubleAndFloat = intModuleIncludingDoubleAndFloat;
+ return this;
+ }
+
+ @Override
+ public void doubleModule(DoubleModule doubleModule) {
+ if (doubleModule == null) {
+ throw new NullPointerException("doubleModule");
+ }
+ this.doubleModule = doubleModule;
+ }
+
+ @Override
+ public Builder depComponent(FloatModule floatModule) {
+ if (floatModule == null) {
+ throw new NullPointerException("floatModule");
+ }
+ this.floatModule = floatModule;
+ return this;
+ }
+
+ @Override
+ public void depComponent(DepComponent depComponent) {
+ if (depComponent == null) {
+ throw new NullPointerException("depComponent");
+ }
+ this.depComponent = depComponent;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithGenericBuilderInterface.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithGenericBuilderInterface.java
new file mode 100644
index 000000000..89e92ab6f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DaggerTestComponentWithGenericBuilderInterface.java
@@ -0,0 +1,133 @@
+package test.builder;
+
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.builder.TestComponentWithGenericBuilderInterface;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerTestComponentWithGenericBuilderInterface implements TestComponentWithGenericBuilderInterface {
+ private Provider<String> stringProvider;
+ private Provider<Integer> integerProvider;
+ private Provider<Long> lProvider;
+ private Provider<Float> fProvider;
+ private Provider<Double> dProvider;
+
+ private DaggerTestComponentWithGenericBuilderInterface(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static TestComponentWithGenericBuilderInterface.Builder builder() {
+ return new Builder();
+ }
+
+ private void initialize(final Builder builder) {
+ this.stringProvider = StringModule_StringFactory.create(builder.stringModule);
+ this.integerProvider = IntModuleIncludingDoubleAndFloat_IntegerFactory.create(builder.intModuleIncludingDoubleAndFloat);
+ this.lProvider = LongModule_LFactory.create(builder.longModule);
+ this.fProvider = FloatModule_FFactory.create(builder.floatModule);
+ this.dProvider = DoubleModule_DFactory.create(builder.doubleModule);
+ }
+
+ @Override
+ public String s() {
+ return stringProvider.get();
+ }
+
+ @Override
+ public int i() {
+ return integerProvider.get();
+ }
+
+ @Override
+ public long l() {
+ return lProvider.get();
+ }
+
+ @Override
+ public float f() {
+ return fProvider.get();
+ }
+
+ @Override
+ public double d() {
+ return dProvider.get();
+ }
+
+ private static final class Builder implements TestComponentWithGenericBuilderInterface.Builder {
+ private StringModule stringModule;
+ private IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat;
+ private DoubleModule doubleModule;
+ private FloatModule floatModule;
+ private LongModule longModule;
+ private DepComponent depComponent;
+
+
+ @Override
+ public TestComponentWithGenericBuilderInterface build() {
+ if (stringModule == null) {
+ throw new IllegalStateException("stringModule must be set");
+ }
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new IllegalStateException("intModuleIncludingDoubleAndFloat must be set");
+ }
+ if (doubleModule == null) {
+ this.doubleModule = new DoubleModule();
+ }
+ if (floatModule == null) {
+ this.floatModule = new FloatModule();
+ }
+ if (longModule == null) {
+ this.longModule = new LongModule();
+ }
+ if (depComponent == null) {
+ throw new IllegalStateException("depComponent must be set");
+ }
+ return new DaggerTestComponentWithGenericBuilderInterface(this);
+ }
+
+ @Override
+ public Builder setM1(StringModule stringModule) {
+ if (stringModule == null) {
+ throw new NullPointerException("stringModule");
+ }
+ this.stringModule = stringModule;
+ return this;
+ }
+
+ @Override
+ public Builder setM2(IntModuleIncludingDoubleAndFloat intModuleIncludingDoubleAndFloat) {
+ if (intModuleIncludingDoubleAndFloat == null) {
+ throw new NullPointerException("intModuleIncludingDoubleAndFloat");
+ }
+ this.intModuleIncludingDoubleAndFloat = intModuleIncludingDoubleAndFloat;
+ return this;
+ }
+
+ @Override
+ public void doubleModule(DoubleModule doubleModule) {
+ if (doubleModule == null) {
+ throw new NullPointerException("doubleModule");
+ }
+ this.doubleModule = doubleModule;
+ }
+
+ @Override
+ public Builder set(FloatModule floatModule) {
+ if (floatModule == null) {
+ throw new NullPointerException("floatModule");
+ }
+ this.floatModule = floatModule;
+ return this;
+ }
+
+ @Override
+ public void depComponent(DepComponent depComponent) {
+ if (depComponent == null) {
+ throw new NullPointerException("depComponent");
+ }
+ this.depComponent = depComponent;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DoubleModule_DFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DoubleModule_DFactory.java
new file mode 100644
index 000000000..e5963cd9e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/DoubleModule_DFactory.java
@@ -0,0 +1,28 @@
+package test.builder;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DoubleModule_DFactory implements Factory<Double> {
+ private final DoubleModule module;
+
+ public DoubleModule_DFactory(DoubleModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Double get() {
+ Double provided = module.d();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Double> create(DoubleModule module) {
+ return new DoubleModule_DFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/FloatModule_FFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/FloatModule_FFactory.java
new file mode 100644
index 000000000..c8ba14cae
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/FloatModule_FFactory.java
@@ -0,0 +1,28 @@
+package test.builder;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class FloatModule_FFactory implements Factory<Float> {
+ private final FloatModule module;
+
+ public FloatModule_FFactory(FloatModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Float get() {
+ Float provided = module.f();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Float> create(FloatModule module) {
+ return new FloatModule_FFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/IntModuleIncludingDoubleAndFloat_IntegerFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/IntModuleIncludingDoubleAndFloat_IntegerFactory.java
new file mode 100644
index 000000000..2775053c9
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/IntModuleIncludingDoubleAndFloat_IntegerFactory.java
@@ -0,0 +1,28 @@
+package test.builder;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class IntModuleIncludingDoubleAndFloat_IntegerFactory implements Factory<Integer> {
+ private final IntModuleIncludingDoubleAndFloat module;
+
+ public IntModuleIncludingDoubleAndFloat_IntegerFactory(IntModuleIncludingDoubleAndFloat module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Integer get() {
+ Integer provided = module.integer();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Integer> create(IntModuleIncludingDoubleAndFloat module) {
+ return new IntModuleIncludingDoubleAndFloat_IntegerFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/LongModule_LFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/LongModule_LFactory.java
new file mode 100644
index 000000000..7f7220aeb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/LongModule_LFactory.java
@@ -0,0 +1,28 @@
+package test.builder;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class LongModule_LFactory implements Factory<Long> {
+ private final LongModule module;
+
+ public LongModule_LFactory(LongModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Long get() {
+ Long provided = module.l();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Long> create(LongModule module) {
+ return new LongModule_LFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/StringModule_StringFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/StringModule_StringFactory.java
new file mode 100644
index 000000000..ca1f00dbc
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/StringModule_StringFactory.java
@@ -0,0 +1,28 @@
+package test.builder;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class StringModule_StringFactory implements Factory<String> {
+ private final StringModule module;
+
+ public StringModule_StringFactory(StringModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.string();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(StringModule module) {
+ return new StringModule_StringFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/abstractinjectmethod/ContactDataStore_MembersInjector.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/abstractinjectmethod/ContactDataStore_MembersInjector.java
new file mode 100644
index 000000000..4590a8b01
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/abstractinjectmethod/ContactDataStore_MembersInjector.java
@@ -0,0 +1,28 @@
+package test.builder.abstractinjectmethod;
+
+import dagger.MembersInjector;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ContactDataStore_MembersInjector implements MembersInjector<ContactDataStore> {
+ private final Provider<RestClient> restClientProvider;
+
+ public ContactDataStore_MembersInjector(Provider<RestClient> restClientProvider) {
+ assert restClientProvider != null;
+ this.restClientProvider = restClientProvider;
+ }
+
+ @Override
+ public void injectMembers(ContactDataStore instance) {
+ if (instance == null) {
+ throw new NullPointerException("Cannot inject members into a null reference");
+ }
+ instance.setRestClient(restClientProvider.get());
+ }
+
+ public static MembersInjector<ContactDataStore> create(Provider<RestClient> restClientProvider) {
+ return new ContactDataStore_MembersInjector(restClientProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/abstractinjectmethod/DaggerApiComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/abstractinjectmethod/DaggerApiComponent.java
new file mode 100644
index 000000000..4fcb6e752
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/abstractinjectmethod/DaggerApiComponent.java
@@ -0,0 +1,49 @@
+package test.builder.abstractinjectmethod;
+
+import dagger.MembersInjector;
+import dagger.internal.MembersInjectors;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerApiComponent implements ApiComponent {
+ private MembersInjector<ContactDataStore> contactDataStoreMembersInjector;
+ private MembersInjector<CloudContactDataStore> cloudContactDataStoreMembersInjector;
+
+ private DaggerApiComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static ApiComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.contactDataStoreMembersInjector = ContactDataStore_MembersInjector.create(RestClient_Factory.create());
+ this.cloudContactDataStoreMembersInjector = MembersInjectors.delegatingTo(contactDataStoreMembersInjector);
+ }
+
+ @Override
+ public void inject(ContactDataStore contactDataStore) {
+ contactDataStoreMembersInjector.injectMembers(contactDataStore);
+ }
+
+ @Override
+ public void inject(CloudContactDataStore contactDataStore) {
+ cloudContactDataStoreMembersInjector.injectMembers(contactDataStore);
+ }
+
+ public static final class Builder {
+ private Builder() {
+ }
+
+ public ApiComponent build() {
+ return new DaggerApiComponent(this);
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/abstractinjectmethod/RestClient_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/abstractinjectmethod/RestClient_Factory.java
new file mode 100644
index 000000000..7e65f4945
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/abstractinjectmethod/RestClient_Factory.java
@@ -0,0 +1,19 @@
+package test.builder.abstractinjectmethod;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum RestClient_Factory implements Factory<RestClient> {
+INSTANCE;
+
+ @Override
+ public RestClient get() {
+ return new RestClient();
+ }
+
+ public static Factory<RestClient> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ContactDataStore_MembersInjector.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ContactDataStore_MembersInjector.java
new file mode 100644
index 000000000..4c28a2c41
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ContactDataStore_MembersInjector.java
@@ -0,0 +1,30 @@
+package test.builder.product;
+
+import dagger.MembersInjector;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.builder.abstractinjectmethod.ContactDataStore;
+import test.builder.abstractinjectmethod.RestClient;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ContactDataStore_MembersInjector implements MembersInjector<ContactDataStore> {
+ private final Provider<RestClient> restClientProvider;
+
+ public ContactDataStore_MembersInjector(Provider<RestClient> restClientProvider) {
+ assert restClientProvider != null;
+ this.restClientProvider = restClientProvider;
+ }
+
+ @Override
+ public void injectMembers(ContactDataStore instance) {
+ if (instance == null) {
+ throw new NullPointerException("Cannot inject members into a null reference");
+ }
+ instance.setRestClient(restClientProvider.get());
+ }
+
+ public static MembersInjector<ContactDataStore> create(Provider<RestClient> restClientProvider) {
+ return new ContactDataStore_MembersInjector(restClientProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/DaggerApiComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/DaggerApiComponent.java
new file mode 100644
index 000000000..d214e4645
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/DaggerApiComponent.java
@@ -0,0 +1,43 @@
+package test.builder.product;
+
+import dagger.MembersInjector;
+import javax.annotation.Generated;
+import test.builder.abstractinjectmethod.ApiComponent;
+import test.builder.abstractinjectmethod.ContactDataStore;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerApiComponent implements ApiComponent {
+ private MembersInjector<ContactDataStore> contactDataStoreMembersInjector;
+
+ private DaggerApiComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static ApiComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.contactDataStoreMembersInjector = ContactDataStore_MembersInjector.create(RestClient_Factory.create());
+ }
+
+ @Override
+ public void inject(ContactDataStore contactDataStore) {
+ contactDataStoreMembersInjector.injectMembers(contactDataStore);
+ }
+
+ public static final class Builder {
+ private Builder() {
+ }
+
+ public ApiComponent build() {
+ return new DaggerApiComponent(this);
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/DaggerPackagerOneComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/DaggerPackagerOneComponent.java
new file mode 100644
index 000000000..5e04ccc81
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/DaggerPackagerOneComponent.java
@@ -0,0 +1,56 @@
+package test.builder.product;
+
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerPackagerOneComponent implements PackagerOneComponent {
+ private Provider<Product> provideProductProvider;
+ private Provider<Packager> packagerProvider;
+
+ private DaggerPackagerOneComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static PackagerOneComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.provideProductProvider = ProductOneModule_ProvideProductFactory.create(builder.productOneModule, ProductOne_Factory.create());
+ this.packagerProvider = Packager_Factory.create(provideProductProvider);
+ }
+
+ @Override
+ public Packager packager() {
+ return packagerProvider.get();
+ }
+
+ public static final class Builder {
+ private ProductOneModule productOneModule;
+
+ private Builder() {
+ }
+
+ public PackagerOneComponent build() {
+ if (productOneModule == null) {
+ this.productOneModule = new ProductOneModule();
+ }
+ return new DaggerPackagerOneComponent(this);
+ }
+
+ public Builder productOneModule(ProductOneModule productOneModule) {
+ if (productOneModule == null) {
+ throw new NullPointerException("productOneModule");
+ }
+ this.productOneModule = productOneModule;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/DaggerPackagerTwoComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/DaggerPackagerTwoComponent.java
new file mode 100644
index 000000000..a691f2399
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/DaggerPackagerTwoComponent.java
@@ -0,0 +1,56 @@
+package test.builder.product;
+
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerPackagerTwoComponent implements PackagerTwoComponent {
+ private Provider<Product> provideProductProvider;
+ private Provider<Packager> packagerProvider;
+
+ private DaggerPackagerTwoComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static PackagerTwoComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.provideProductProvider = ProductTwoModule_ProvideProductFactory.create(builder.productTwoModule, ProductTwo_Factory.create());
+ this.packagerProvider = Packager_Factory.create(provideProductProvider);
+ }
+
+ @Override
+ public Packager packager() {
+ return packagerProvider.get();
+ }
+
+ public static final class Builder {
+ private ProductTwoModule productTwoModule;
+
+ private Builder() {
+ }
+
+ public PackagerTwoComponent build() {
+ if (productTwoModule == null) {
+ this.productTwoModule = new ProductTwoModule();
+ }
+ return new DaggerPackagerTwoComponent(this);
+ }
+
+ public Builder productTwoModule(ProductTwoModule productTwoModule) {
+ if (productTwoModule == null) {
+ throw new NullPointerException("productTwoModule");
+ }
+ this.productTwoModule = productTwoModule;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/Packager_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/Packager_Factory.java
new file mode 100644
index 000000000..8ce215437
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/Packager_Factory.java
@@ -0,0 +1,25 @@
+package test.builder.product;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class Packager_Factory implements Factory<Packager> {
+ private final Provider<Product> productProvider;
+
+ public Packager_Factory(Provider<Product> productProvider) {
+ assert productProvider != null;
+ this.productProvider = productProvider;
+ }
+
+ @Override
+ public Packager get() {
+ return new Packager(productProvider.get());
+ }
+
+ public static Factory<Packager> create(Provider<Product> productProvider) {
+ return new Packager_Factory(productProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductOneModule_ProvideProductFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductOneModule_ProvideProductFactory.java
new file mode 100644
index 000000000..99578a483
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductOneModule_ProvideProductFactory.java
@@ -0,0 +1,32 @@
+package test.builder.product;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ProductOneModule_ProvideProductFactory implements Factory<Product> {
+ private final ProductOneModule module;
+ private final Provider<ProductOne> productOneProvider;
+
+ public ProductOneModule_ProvideProductFactory(ProductOneModule module, Provider<ProductOne> productOneProvider) {
+ assert module != null;
+ this.module = module;
+ assert productOneProvider != null;
+ this.productOneProvider = productOneProvider;
+ }
+
+ @Override
+ public Product get() {
+ Product provided = module.provideProduct(productOneProvider.get());
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Product> create(ProductOneModule module, Provider<ProductOne> productOneProvider) {
+ return new ProductOneModule_ProvideProductFactory(module, productOneProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductOne_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductOne_Factory.java
new file mode 100644
index 000000000..a9d0a0524
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductOne_Factory.java
@@ -0,0 +1,19 @@
+package test.builder.product;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum ProductOne_Factory implements Factory<ProductOne> {
+INSTANCE;
+
+ @Override
+ public ProductOne get() {
+ return new ProductOne();
+ }
+
+ public static Factory<ProductOne> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductTwoModule_ProvideProductFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductTwoModule_ProvideProductFactory.java
new file mode 100644
index 000000000..131a6199d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductTwoModule_ProvideProductFactory.java
@@ -0,0 +1,32 @@
+package test.builder.product;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ProductTwoModule_ProvideProductFactory implements Factory<Product> {
+ private final ProductTwoModule module;
+ private final Provider<ProductTwo> productTwoProvider;
+
+ public ProductTwoModule_ProvideProductFactory(ProductTwoModule module, Provider<ProductTwo> productTwoProvider) {
+ assert module != null;
+ this.module = module;
+ assert productTwoProvider != null;
+ this.productTwoProvider = productTwoProvider;
+ }
+
+ @Override
+ public Product get() {
+ Product provided = module.provideProduct(productTwoProvider.get());
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Product> create(ProductTwoModule module, Provider<ProductTwo> productTwoProvider) {
+ return new ProductTwoModule_ProvideProductFactory(module, productTwoProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductTwo_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductTwo_Factory.java
new file mode 100644
index 000000000..dca46d756
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/ProductTwo_Factory.java
@@ -0,0 +1,19 @@
+package test.builder.product;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum ProductTwo_Factory implements Factory<ProductTwo> {
+INSTANCE;
+
+ @Override
+ public ProductTwo get() {
+ return new ProductTwo();
+ }
+
+ public static Factory<ProductTwo> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/RestClient_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/RestClient_Factory.java
new file mode 100644
index 000000000..6ce80ced5
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/product/RestClient_Factory.java
@@ -0,0 +1,20 @@
+package test.builder.product;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import test.builder.abstractinjectmethod.RestClient;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum RestClient_Factory implements Factory<RestClient> {
+INSTANCE;
+
+ @Override
+ public RestClient get() {
+ return new RestClient();
+ }
+
+ public static Factory<RestClient> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/subcomponent/DaggerRootComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/subcomponent/DaggerRootComponent.java
new file mode 100644
index 000000000..07e359302
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/subcomponent/DaggerRootComponent.java
@@ -0,0 +1,69 @@
+package test.builder.subcomponent;
+
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerRootComponent implements RootComponent {
+ private Provider<String> providesStringProvider;
+
+ private DaggerRootComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private void initialize(final Builder builder) {
+ this.providesStringProvider = ModuleWithParameter_ProvidesStringFactory.create(builder.moduleWithParameter);
+ }
+
+ @Override
+ public String string() {
+ return providesStringProvider.get();
+ }
+
+ @Override
+ public SubComponent newSubComponent() {
+ return new SubComponentImpl();
+ }
+
+ public static final class Builder {
+ private ModuleWithParameter moduleWithParameter;
+
+ private Builder() {
+ }
+
+ public RootComponent build() {
+ if (moduleWithParameter == null) {
+ throw new IllegalStateException("moduleWithParameter must be set");
+ }
+ return new DaggerRootComponent(this);
+ }
+
+ public Builder moduleWithParameter(ModuleWithParameter moduleWithParameter) {
+ if (moduleWithParameter == null) {
+ throw new NullPointerException("moduleWithParameter");
+ }
+ this.moduleWithParameter = moduleWithParameter;
+ return this;
+ }
+ }
+
+ private final class SubComponentImpl implements SubComponent {
+ private SubComponentImpl() {
+ initialize();
+ }
+
+ private void initialize() {
+ }
+
+ @Override
+ public String string() {
+ return DaggerRootComponent.this.providesStringProvider.get();
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/subcomponent/DaggerSubComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/subcomponent/DaggerSubComponent.java
new file mode 100644
index 000000000..86ae65f4c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/subcomponent/DaggerSubComponent.java
@@ -0,0 +1,50 @@
+package test.builder.subcomponent;
+
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerSubComponent implements SubComponent {
+ private Provider<String> providesStringProvider;
+
+ private DaggerSubComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private void initialize(final Builder builder) {
+ this.providesStringProvider = ModuleWithParameter_ProvidesStringFactory.create(builder.moduleWithParameter);
+ }
+
+ @Override
+ public String string() {
+ return providesStringProvider.get();
+ }
+
+ public static final class Builder {
+ private ModuleWithParameter moduleWithParameter;
+
+ private Builder() {
+ }
+
+ public SubComponent build() {
+ if (moduleWithParameter == null) {
+ throw new IllegalStateException("moduleWithParameter must be set");
+ }
+ return new DaggerSubComponent(this);
+ }
+
+ public Builder moduleWithParameter(ModuleWithParameter moduleWithParameter) {
+ if (moduleWithParameter == null) {
+ throw new NullPointerException("moduleWithParameter");
+ }
+ this.moduleWithParameter = moduleWithParameter;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/subcomponent/ModuleWithParameter_ProvidesStringFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/subcomponent/ModuleWithParameter_ProvidesStringFactory.java
new file mode 100644
index 000000000..df0f9b0b1
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/builder/subcomponent/ModuleWithParameter_ProvidesStringFactory.java
@@ -0,0 +1,28 @@
+package test.builder.subcomponent;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ModuleWithParameter_ProvidesStringFactory implements Factory<String> {
+ private final ModuleWithParameter module;
+
+ public ModuleWithParameter_ProvidesStringFactory(ModuleWithParameter module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.providesString();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(ModuleWithParameter module) {
+ return new ModuleWithParameter_ProvidesStringFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/DaggerMembersInjectComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/DaggerMembersInjectComponent.java
new file mode 100644
index 000000000..c566f6c63
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/DaggerMembersInjectComponent.java
@@ -0,0 +1,82 @@
+package test.membersinject;
+
+import dagger.MembersInjector;
+import dagger.internal.MembersInjectors;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerMembersInjectComponent implements MembersInjectComponent {
+ private Provider<String[]> provideStringArrayProvider;
+ private MembersInjector<MembersInjectGenericParent<String[]>> membersInjectGenericParentMembersInjector;
+ private MembersInjector<ChildOfStringArray> childOfStringArrayMembersInjector;
+ private Provider<MembersInjectGenericParent<String[]>[]> provideFooArrayOfStringArrayProvider;
+ private MembersInjector<MembersInjectGenericParent<MembersInjectGenericParent<String[]>[]>> membersInjectGenericParentMembersInjector1;
+ private MembersInjector<ChildOfArrayOfParentOfStringArray> childOfArrayOfParentOfStringArrayMembersInjector;
+ private Provider<int[]> provideIntArrayProvider;
+ private MembersInjector<MembersInjectGenericParent<int[]>> membersInjectGenericParentMembersInjector2;
+ private MembersInjector<ChildOfPrimitiveIntArray> childOfPrimitiveIntArrayMembersInjector;
+
+ private DaggerMembersInjectComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static MembersInjectComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.provideStringArrayProvider = MembersInjectModule_ProvideStringArrayFactory.create(builder.membersInjectModule);
+ this.membersInjectGenericParentMembersInjector = MembersInjectGenericParent_MembersInjector.create(provideStringArrayProvider);
+ this.childOfStringArrayMembersInjector = MembersInjectors.delegatingTo(membersInjectGenericParentMembersInjector);
+ this.provideFooArrayOfStringArrayProvider = MembersInjectModule_ProvideFooArrayOfStringArrayFactory.create(builder.membersInjectModule);
+ this.membersInjectGenericParentMembersInjector1 = MembersInjectGenericParent_MembersInjector.create(provideFooArrayOfStringArrayProvider);
+ this.childOfArrayOfParentOfStringArrayMembersInjector = MembersInjectors.delegatingTo(membersInjectGenericParentMembersInjector1);
+ this.provideIntArrayProvider = MembersInjectModule_ProvideIntArrayFactory.create(builder.membersInjectModule);
+ this.membersInjectGenericParentMembersInjector2 = MembersInjectGenericParent_MembersInjector.create(provideIntArrayProvider);
+ this.childOfPrimitiveIntArrayMembersInjector = MembersInjectors.delegatingTo(membersInjectGenericParentMembersInjector2);
+ }
+
+ @Override
+ public void inject(ChildOfStringArray subfoo) {
+ childOfStringArrayMembersInjector.injectMembers(subfoo);
+ }
+
+ @Override
+ public void inject(ChildOfArrayOfParentOfStringArray subfoo) {
+ childOfArrayOfParentOfStringArrayMembersInjector.injectMembers(subfoo);
+ }
+
+ @Override
+ public void inject(ChildOfPrimitiveIntArray subfoo) {
+ childOfPrimitiveIntArrayMembersInjector.injectMembers(subfoo);
+ }
+
+ public static final class Builder {
+ private MembersInjectModule membersInjectModule;
+
+ private Builder() {
+ }
+
+ public MembersInjectComponent build() {
+ if (membersInjectModule == null) {
+ this.membersInjectModule = new MembersInjectModule();
+ }
+ return new DaggerMembersInjectComponent(this);
+ }
+
+ public Builder membersInjectModule(MembersInjectModule membersInjectModule) {
+ if (membersInjectModule == null) {
+ throw new NullPointerException("membersInjectModule");
+ }
+ this.membersInjectModule = membersInjectModule;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectGenericParent_MembersInjector.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectGenericParent_MembersInjector.java
new file mode 100644
index 000000000..8b3624a33
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectGenericParent_MembersInjector.java
@@ -0,0 +1,28 @@
+package test.membersinject;
+
+import dagger.MembersInjector;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MembersInjectGenericParent_MembersInjector<T> implements MembersInjector<MembersInjectGenericParent<T>> {
+ private final Provider<T> tProvider;
+
+ public MembersInjectGenericParent_MembersInjector(Provider<T> tProvider) {
+ assert tProvider != null;
+ this.tProvider = tProvider;
+ }
+
+ @Override
+ public void injectMembers(MembersInjectGenericParent<T> instance) {
+ if (instance == null) {
+ throw new NullPointerException("Cannot inject members into a null reference");
+ }
+ instance.t = tProvider.get();
+ }
+
+ public static <T> MembersInjector<MembersInjectGenericParent<T>> create(Provider<T> tProvider) {
+ return new MembersInjectGenericParent_MembersInjector<T>(tProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectModule_ProvideFooArrayOfStringArrayFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectModule_ProvideFooArrayOfStringArrayFactory.java
new file mode 100644
index 000000000..59719859c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectModule_ProvideFooArrayOfStringArrayFactory.java
@@ -0,0 +1,28 @@
+package test.membersinject;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MembersInjectModule_ProvideFooArrayOfStringArrayFactory implements Factory<MembersInjectGenericParent<String[]>[]> {
+ private final MembersInjectModule module;
+
+ public MembersInjectModule_ProvideFooArrayOfStringArrayFactory(MembersInjectModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public MembersInjectGenericParent<String[]>[] get() {
+ MembersInjectGenericParent<String[]>[] provided = module.provideFooArrayOfStringArray();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<MembersInjectGenericParent<String[]>[]> create(MembersInjectModule module) {
+ return new MembersInjectModule_ProvideFooArrayOfStringArrayFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectModule_ProvideIntArrayFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectModule_ProvideIntArrayFactory.java
new file mode 100644
index 000000000..c5fef425b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectModule_ProvideIntArrayFactory.java
@@ -0,0 +1,28 @@
+package test.membersinject;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MembersInjectModule_ProvideIntArrayFactory implements Factory<int[]> {
+ private final MembersInjectModule module;
+
+ public MembersInjectModule_ProvideIntArrayFactory(MembersInjectModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public int[] get() {
+ int[] provided = module.provideIntArray();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<int[]> create(MembersInjectModule module) {
+ return new MembersInjectModule_ProvideIntArrayFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectModule_ProvideStringArrayFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectModule_ProvideStringArrayFactory.java
new file mode 100644
index 000000000..76b083da2
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/membersinject/MembersInjectModule_ProvideStringArrayFactory.java
@@ -0,0 +1,28 @@
+package test.membersinject;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MembersInjectModule_ProvideStringArrayFactory implements Factory<String[]> {
+ private final MembersInjectModule module;
+
+ public MembersInjectModule_ProvideStringArrayFactory(MembersInjectModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String[] get() {
+ String[] provided = module.provideStringArray();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String[]> create(MembersInjectModule module) {
+ return new MembersInjectModule_ProvideStringArrayFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/DaggerFooComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/DaggerFooComponent.java
new file mode 100644
index 000000000..e8a396f73
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/DaggerFooComponent.java
@@ -0,0 +1,130 @@
+package test.multipackage;
+
+import dagger.internal.SetFactory;
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.multipackage.a.AModule;
+import test.multipackage.a.AModule_ProvideStringFactory;
+import test.multipackage.b.BModule;
+import test.multipackage.b.BModule_ProvideStringFactory;
+import test.multipackage.c.CModule;
+import test.multipackage.c.CModule_ProvideStringFactory;
+import test.multipackage.d.DModule;
+import test.multipackage.d.DModule_ProvideStringFactory;
+import test.multipackage.foo.Foo;
+import test.multipackage.foo.Foo_Factory;
+import test.multipackage.grandsub.FooGrandchildComponent;
+import test.multipackage.sub.FooChildComponent;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerFooComponent implements FooComponent {
+ private Provider<Set<String>> setOfStringContribution1Provider;
+ private Provider<Set<String>> setOfStringProvider;
+
+ private DaggerFooComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static FooComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.setOfStringContribution1Provider = AModule_ProvideStringFactory.create(builder.aModule);
+ this.setOfStringProvider = SetFactory.create(setOfStringContribution1Provider);
+ }
+
+ @Override
+ public Set<String> setOfString() {
+ return setOfStringProvider.get();
+ }
+
+ @Override
+ public FooChildComponent fooChildComponent() {
+ return new FooChildComponentImpl();
+ }
+
+ public static final class Builder {
+ private AModule aModule;
+
+ private Builder() {
+ }
+
+ public FooComponent build() {
+ if (aModule == null) {
+ this.aModule = new AModule();
+ }
+ return new DaggerFooComponent(this);
+ }
+
+ public Builder aModule(AModule aModule) {
+ if (aModule == null) {
+ throw new NullPointerException("aModule");
+ }
+ this.aModule = aModule;
+ return this;
+ }
+ }
+
+ private final class FooChildComponentImpl implements FooChildComponent {
+ private final BModule bModule;
+ private final CModule cModule;
+ private Provider<Set<String>> setOfStringContribution2Provider;
+ private Provider<Set<String>> setOfStringContribution3Provider;
+ private Provider<Set<String>> setOfStringProvider;
+ private Provider<Foo<FooChildComponent>> fooProvider;
+
+ private FooChildComponentImpl() {
+ this.bModule = new BModule();
+ this.cModule = new CModule();
+ initialize();
+ }
+
+ private void initialize() {
+ this.setOfStringContribution2Provider = BModule_ProvideStringFactory.create(bModule);
+ this.setOfStringContribution3Provider = CModule_ProvideStringFactory.create(cModule);
+ this.setOfStringProvider = SetFactory.create(setOfStringContribution1Provider, setOfStringContribution2Provider, setOfStringContribution3Provider);
+ this.fooProvider = Foo_Factory.create(setOfStringProvider);
+ }
+
+ @Override
+ public Foo<FooChildComponent> foo() {
+ return fooProvider.get();
+ }
+
+ @Override
+ public FooGrandchildComponent fooGrandchildComponent() {
+ return new FooGrandchildComponentImpl();
+ }
+
+ private final class FooGrandchildComponentImpl implements FooGrandchildComponent {
+ private final DModule dModule;
+ private Provider<Set<String>> setOfStringContribution4Provider;
+ private Provider<Set<String>> setOfStringProvider;
+ private Provider<Foo<FooGrandchildComponent>> fooProvider;
+
+ private FooGrandchildComponentImpl() {
+ this.dModule = new DModule();
+ initialize();
+ }
+
+ private void initialize() {
+ this.setOfStringContribution4Provider = DModule_ProvideStringFactory.create(dModule);
+ this.setOfStringProvider = SetFactory.create(setOfStringContribution1Provider, setOfStringContribution2Provider, setOfStringContribution3Provider, setOfStringContribution4Provider);
+ this.fooProvider = Foo_Factory.create(setOfStringProvider);
+ }
+
+ @Override
+ public Foo<FooGrandchildComponent> foo() {
+ return fooProvider.get();
+ }
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/a/AModule_ProvideStringFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/a/AModule_ProvideStringFactory.java
new file mode 100644
index 000000000..eaa2ab79b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/a/AModule_ProvideStringFactory.java
@@ -0,0 +1,26 @@
+package test.multipackage.a;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class AModule_ProvideStringFactory implements Factory<Set<String>> {
+ private final AModule module;
+
+ public AModule_ProvideStringFactory(AModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Set<String> get() {
+ return Collections.<String>singleton(module.provideString());
+ }
+
+ public static Factory<Set<String>> create(AModule module) {
+ return new AModule_ProvideStringFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/b/BModule_ProvideStringFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/b/BModule_ProvideStringFactory.java
new file mode 100644
index 000000000..5a53cff51
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/b/BModule_ProvideStringFactory.java
@@ -0,0 +1,26 @@
+package test.multipackage.b;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class BModule_ProvideStringFactory implements Factory<Set<String>> {
+ private final BModule module;
+
+ public BModule_ProvideStringFactory(BModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Set<String> get() {
+ return Collections.<String>singleton(module.provideString());
+ }
+
+ public static Factory<Set<String>> create(BModule module) {
+ return new BModule_ProvideStringFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/c/CModule_ProvideStringFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/c/CModule_ProvideStringFactory.java
new file mode 100644
index 000000000..516deaaa6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/c/CModule_ProvideStringFactory.java
@@ -0,0 +1,26 @@
+package test.multipackage.c;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class CModule_ProvideStringFactory implements Factory<Set<String>> {
+ private final CModule module;
+
+ public CModule_ProvideStringFactory(CModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Set<String> get() {
+ return Collections.<String>singleton(module.provideString());
+ }
+
+ public static Factory<Set<String>> create(CModule module) {
+ return new CModule_ProvideStringFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/d/DModule_ProvideStringFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/d/DModule_ProvideStringFactory.java
new file mode 100644
index 000000000..b0abcd366
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/d/DModule_ProvideStringFactory.java
@@ -0,0 +1,26 @@
+package test.multipackage.d;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DModule_ProvideStringFactory implements Factory<Set<String>> {
+ private final DModule module;
+
+ public DModule_ProvideStringFactory(DModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Set<String> get() {
+ return Collections.<String>singleton(module.provideString());
+ }
+
+ public static Factory<Set<String>> create(DModule module) {
+ return new DModule_ProvideStringFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/foo/Foo_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/foo/Foo_Factory.java
new file mode 100644
index 000000000..2d4f3c201
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/multipackage/foo/Foo_Factory.java
@@ -0,0 +1,26 @@
+package test.multipackage.foo;
+
+import dagger.internal.Factory;
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class Foo_Factory<T> implements Factory<Foo<T>> {
+ private final Provider<Set<String>> stringsProvider;
+
+ public Foo_Factory(Provider<Set<String>> stringsProvider) {
+ assert stringsProvider != null;
+ this.stringsProvider = stringsProvider;
+ }
+
+ @Override
+ public Foo<T> get() {
+ return new Foo<T>(stringsProvider.get());
+ }
+
+ public static <T> Factory<Foo<T>> create(Provider<Set<String>> stringsProvider) {
+ return new Foo_Factory<T>(stringsProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/DaggerNullComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/DaggerNullComponent.java
new file mode 100644
index 000000000..e7c7d219a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/DaggerNullComponent.java
@@ -0,0 +1,81 @@
+package test.nullables;
+
+import dagger.MembersInjector;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerNullComponent implements NullComponent {
+ private Provider<String> provideNullableStringProvider;
+ private Provider<Number> provideNumberProvider;
+ private MembersInjector<NullFoo> nullFooMembersInjector;
+ private Provider<NullFoo> nullFooProvider;
+
+ private DaggerNullComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static NullComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.provideNullableStringProvider = NullModule_ProvideNullableStringFactory.create(builder.nullModule);
+ this.provideNumberProvider = NullModule_ProvideNumberFactory.create(builder.nullModule);
+ this.nullFooMembersInjector = NullFoo_MembersInjector.create(provideNullableStringProvider, provideNumberProvider);
+ this.nullFooProvider = NullFoo_Factory.create(nullFooMembersInjector, provideNullableStringProvider, provideNumberProvider);
+ }
+
+ @Override
+ public NullFoo nullFoo() {
+ return nullFooProvider.get();
+ }
+
+ @Override
+ public String string() {
+ return provideNullableStringProvider.get();
+ }
+
+ @Override
+ public Provider<String> stringProvider() {
+ return provideNullableStringProvider;
+ }
+
+ @Override
+ public Number number() {
+ return provideNumberProvider.get();
+ }
+
+ @Override
+ public Provider<Number> numberProvider() {
+ return provideNumberProvider;
+ }
+
+ public static final class Builder {
+ private NullModule nullModule;
+
+ private Builder() {
+ }
+
+ public NullComponent build() {
+ if (nullModule == null) {
+ this.nullModule = new NullModule();
+ }
+ return new DaggerNullComponent(this);
+ }
+
+ public Builder nullModule(NullModule nullModule) {
+ if (nullModule == null) {
+ throw new NullPointerException("nullModule");
+ }
+ this.nullModule = nullModule;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/DaggerNullComponentWithDependency.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/DaggerNullComponentWithDependency.java
new file mode 100644
index 000000000..8c44e045a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/DaggerNullComponentWithDependency.java
@@ -0,0 +1,82 @@
+package test.nullables;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerNullComponentWithDependency implements NullComponentWithDependency {
+ private Provider<String> stringProvider;
+ private Provider<Number> numberProvider;
+
+ private DaggerNullComponentWithDependency(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private void initialize(final Builder builder) {
+ this.stringProvider = new Factory<String>() {
+ private final NullComponent nullComponent = builder.nullComponent;
+ @Nullable @Override public String get() {
+ return nullComponent.string();
+ }
+ };
+ this.numberProvider = new Factory<Number>() {
+ private final NullComponent nullComponent = builder.nullComponent;
+ @Override public Number get() {
+ Number provided = nullComponent.number();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable component method");
+ }
+ return provided;
+ }
+ };
+ }
+
+ @Override
+ public String string() {
+ return stringProvider.get();
+ }
+
+ @Override
+ public Provider<String> stringProvider() {
+ return stringProvider;
+ }
+
+ @Override
+ public Number number() {
+ return numberProvider.get();
+ }
+
+ @Override
+ public Provider<Number> numberProvider() {
+ return numberProvider;
+ }
+
+ public static final class Builder {
+ private NullComponent nullComponent;
+
+ private Builder() {
+ }
+
+ public NullComponentWithDependency build() {
+ if (nullComponent == null) {
+ throw new IllegalStateException("nullComponent must be set");
+ }
+ return new DaggerNullComponentWithDependency(this);
+ }
+
+ public Builder nullComponent(NullComponent nullComponent) {
+ if (nullComponent == null) {
+ throw new NullPointerException("nullComponent");
+ }
+ this.nullComponent = nullComponent;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullFoo_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullFoo_Factory.java
new file mode 100644
index 000000000..3795e8776
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullFoo_Factory.java
@@ -0,0 +1,34 @@
+package test.nullables;
+
+import dagger.MembersInjector;
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class NullFoo_Factory implements Factory<NullFoo> {
+ private final MembersInjector<NullFoo> membersInjector;
+ private final Provider<String> stringProvider;
+ private final Provider<Number> numberProvider;
+
+ public NullFoo_Factory(MembersInjector<NullFoo> membersInjector, Provider<String> stringProvider, Provider<Number> numberProvider) {
+ assert membersInjector != null;
+ this.membersInjector = membersInjector;
+ assert stringProvider != null;
+ this.stringProvider = stringProvider;
+ assert numberProvider != null;
+ this.numberProvider = numberProvider;
+ }
+
+ @Override
+ public NullFoo get() {
+ NullFoo instance = new NullFoo(stringProvider.get(), stringProvider, numberProvider.get(), numberProvider);
+ membersInjector.injectMembers(instance);
+ return instance;
+ }
+
+ public static Factory<NullFoo> create(MembersInjector<NullFoo> membersInjector, Provider<String> stringProvider, Provider<Number> numberProvider) {
+ return new NullFoo_Factory(membersInjector, stringProvider, numberProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullFoo_MembersInjector.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullFoo_MembersInjector.java
new file mode 100644
index 000000000..d16b41c46
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullFoo_MembersInjector.java
@@ -0,0 +1,35 @@
+package test.nullables;
+
+import dagger.MembersInjector;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class NullFoo_MembersInjector implements MembersInjector<NullFoo> {
+ private final Provider<String> fieldInjectedStringAndStringProvider;
+ private final Provider<Number> fieldInjectedNumberAndNumberProvider;
+
+ public NullFoo_MembersInjector(Provider<String> fieldInjectedStringAndStringProvider, Provider<Number> fieldInjectedNumberAndNumberProvider) {
+ assert fieldInjectedStringAndStringProvider != null;
+ this.fieldInjectedStringAndStringProvider = fieldInjectedStringAndStringProvider;
+ assert fieldInjectedNumberAndNumberProvider != null;
+ this.fieldInjectedNumberAndNumberProvider = fieldInjectedNumberAndNumberProvider;
+ }
+
+ @Override
+ public void injectMembers(NullFoo instance) {
+ if (instance == null) {
+ throw new NullPointerException("Cannot inject members into a null reference");
+ }
+ instance.fieldInjectedString = fieldInjectedStringAndStringProvider.get();
+ instance.fieldInjectedStringProvider = fieldInjectedStringAndStringProvider;
+ instance.fieldInjectedNumber = fieldInjectedNumberAndNumberProvider.get();
+ instance.fieldInjectedNumberProvider = fieldInjectedNumberAndNumberProvider;
+ instance.inject(fieldInjectedStringAndStringProvider.get(), fieldInjectedStringAndStringProvider, fieldInjectedNumberAndNumberProvider.get(), fieldInjectedNumberAndNumberProvider);
+ }
+
+ public static MembersInjector<NullFoo> create(Provider<String> fieldInjectedStringAndStringProvider, Provider<Number> fieldInjectedNumberAndNumberProvider) {
+ return new NullFoo_MembersInjector(fieldInjectedStringAndStringProvider, fieldInjectedNumberAndNumberProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullModule_ProvideNullableStringFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullModule_ProvideNullableStringFactory.java
new file mode 100644
index 000000000..f853f1df2
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullModule_ProvideNullableStringFactory.java
@@ -0,0 +1,25 @@
+package test.nullables;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class NullModule_ProvideNullableStringFactory implements Factory<String> {
+ private final NullModule module;
+
+ public NullModule_ProvideNullableStringFactory(NullModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ @Nullable
+ public String get() {
+ return module.provideNullableString();
+ }
+
+ public static Factory<String> create(NullModule module) {
+ return new NullModule_ProvideNullableStringFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullModule_ProvideNumberFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullModule_ProvideNumberFactory.java
new file mode 100644
index 000000000..84e372788
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/nullables/NullModule_ProvideNumberFactory.java
@@ -0,0 +1,28 @@
+package test.nullables;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class NullModule_ProvideNumberFactory implements Factory<Number> {
+ private final NullModule module;
+
+ public NullModule_ProvideNumberFactory(NullModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Number get() {
+ Number provided = module.provideNumber();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Number> create(NullModule module) {
+ return new NullModule_ProvideNumberFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/AllStaticModule_ContibuteEmptyIntegerSetFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/AllStaticModule_ContibuteEmptyIntegerSetFactory.java
new file mode 100644
index 000000000..506fbe250
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/AllStaticModule_ContibuteEmptyIntegerSetFactory.java
@@ -0,0 +1,24 @@
+package test.staticprovides;
+
+import dagger.internal.Factory;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum AllStaticModule_ContibuteEmptyIntegerSetFactory implements Factory<Set<Integer>> {
+INSTANCE;
+
+ @Override
+ public Set<Integer> get() {
+ Set<Integer> provided = AllStaticModule.contibuteEmptyIntegerSet();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Set<Integer>> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/AllStaticModule_ContributeStringFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/AllStaticModule_ContributeStringFactory.java
new file mode 100644
index 000000000..9700ff3d5
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/AllStaticModule_ContributeStringFactory.java
@@ -0,0 +1,21 @@
+package test.staticprovides;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum AllStaticModule_ContributeStringFactory implements Factory<Set<String>> {
+INSTANCE;
+
+ @Override
+ public Set<String> get() {
+ return Collections.<String>singleton(AllStaticModule.contributeString());
+ }
+
+ public static Factory<Set<String>> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/DaggerStaticTestComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/DaggerStaticTestComponent.java
new file mode 100644
index 000000000..8df8c5c50
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/DaggerStaticTestComponent.java
@@ -0,0 +1,83 @@
+package test.staticprovides;
+
+import dagger.internal.SetFactory;
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerStaticTestComponent implements StaticTestComponent {
+ private Provider<Set<String>> setOfStringContribution1Provider;
+ private Provider<Set<String>> setOfStringContribution2Provider;
+ private Provider<Set<String>> setOfStringContribution3Provider;
+ private Provider<Set<String>> setOfStringProvider;
+ private Provider<Set<Integer>> setOfIntegerContribution1Provider;
+ private Provider<Set<Integer>> setOfIntegerProvider;
+
+ private DaggerStaticTestComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static StaticTestComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.setOfStringContribution1Provider = AllStaticModule_ContributeStringFactory.create();
+ this.setOfStringContribution2Provider = SomeStaticModule_ContributeStringFromAStaticMethodFactory.create();
+ this.setOfStringContribution3Provider = SomeStaticModule_ContributeStringFromAnInstanceMethodFactory.create(builder.someStaticModule);
+ this.setOfStringProvider = SetFactory.create(setOfStringContribution1Provider, setOfStringContribution2Provider, setOfStringContribution3Provider);
+ this.setOfIntegerContribution1Provider = AllStaticModule_ContibuteEmptyIntegerSetFactory.create();
+ this.setOfIntegerProvider = SetFactory.create(setOfIntegerContribution1Provider);
+ }
+
+ @Override
+ public Set<String> getMultiboundStrings() {
+ return setOfStringProvider.get();
+ }
+
+ @Override
+ public Set<Integer> getMultiboundIntegers() {
+ return setOfIntegerProvider.get();
+ }
+
+ public static final class Builder {
+ private AllStaticModule allStaticModule;
+ private SomeStaticModule someStaticModule;
+
+ private Builder() {
+ }
+
+ public StaticTestComponent build() {
+ if (allStaticModule == null) {
+ this.allStaticModule = new AllStaticModule();
+ }
+ if (someStaticModule == null) {
+ this.someStaticModule = new SomeStaticModule();
+ }
+ return new DaggerStaticTestComponent(this);
+ }
+
+ public Builder allStaticModule(AllStaticModule allStaticModule) {
+ if (allStaticModule == null) {
+ throw new NullPointerException("allStaticModule");
+ }
+ this.allStaticModule = allStaticModule;
+ return this;
+ }
+
+ public Builder someStaticModule(SomeStaticModule someStaticModule) {
+ if (someStaticModule == null) {
+ throw new NullPointerException("someStaticModule");
+ }
+ this.someStaticModule = someStaticModule;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/SomeStaticModule_ContributeStringFromAStaticMethodFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/SomeStaticModule_ContributeStringFromAStaticMethodFactory.java
new file mode 100644
index 000000000..e4177662d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/SomeStaticModule_ContributeStringFromAStaticMethodFactory.java
@@ -0,0 +1,21 @@
+package test.staticprovides;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum SomeStaticModule_ContributeStringFromAStaticMethodFactory implements Factory<Set<String>> {
+INSTANCE;
+
+ @Override
+ public Set<String> get() {
+ return Collections.<String>singleton(SomeStaticModule.contributeStringFromAStaticMethod());
+ }
+
+ public static Factory<Set<String>> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/SomeStaticModule_ContributeStringFromAnInstanceMethodFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/SomeStaticModule_ContributeStringFromAnInstanceMethodFactory.java
new file mode 100644
index 000000000..f96be5feb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/staticprovides/SomeStaticModule_ContributeStringFromAnInstanceMethodFactory.java
@@ -0,0 +1,26 @@
+package test.staticprovides;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class SomeStaticModule_ContributeStringFromAnInstanceMethodFactory implements Factory<Set<String>> {
+ private final SomeStaticModule module;
+
+ public SomeStaticModule_ContributeStringFromAnInstanceMethodFactory(SomeStaticModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Set<String> get() {
+ return Collections.<String>singleton(module.contributeStringFromAnInstanceMethod());
+ }
+
+ public static Factory<Set<String>> create(SomeStaticModule module) {
+ return new SomeStaticModule_ContributeStringFromAnInstanceMethodFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/ContributionsModule_ContributeAnIntFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/ContributionsModule_ContributeAnIntFactory.java
new file mode 100644
index 000000000..dddf66ec9
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/ContributionsModule_ContributeAnIntFactory.java
@@ -0,0 +1,30 @@
+package test.sub;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ContributionsModule_ContributeAnIntFactory implements Factory<Set<Integer>> {
+ private final ContributionsModule module;
+ private final Provider<Double> doubleDependencyProvider;
+
+ public ContributionsModule_ContributeAnIntFactory(ContributionsModule module, Provider<Double> doubleDependencyProvider) {
+ assert module != null;
+ this.module = module;
+ assert doubleDependencyProvider != null;
+ this.doubleDependencyProvider = doubleDependencyProvider;
+ }
+
+ @Override
+ public Set<Integer> get() {
+ return Collections.<Integer>singleton(module.contributeAnInt(doubleDependencyProvider.get()));
+ }
+
+ public static Factory<Set<Integer>> create(ContributionsModule module, Provider<Double> doubleDependencyProvider) {
+ return new ContributionsModule_ContributeAnIntFactory(module, doubleDependencyProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/ContributionsModule_ContributeAnotherIntFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/ContributionsModule_ContributeAnotherIntFactory.java
new file mode 100644
index 000000000..e36e78a01
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/ContributionsModule_ContributeAnotherIntFactory.java
@@ -0,0 +1,26 @@
+package test.sub;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ContributionsModule_ContributeAnotherIntFactory implements Factory<Set<Integer>> {
+ private final ContributionsModule module;
+
+ public ContributionsModule_ContributeAnotherIntFactory(ContributionsModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Set<Integer> get() {
+ return Collections.<Integer>singleton(module.contributeAnotherInt());
+ }
+
+ public static Factory<Set<Integer>> create(ContributionsModule module) {
+ return new ContributionsModule_ContributeAnotherIntFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/ContributionsModule_ContributeSomeIntsFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/ContributionsModule_ContributeSomeIntsFactory.java
new file mode 100644
index 000000000..68e42d694
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/ContributionsModule_ContributeSomeIntsFactory.java
@@ -0,0 +1,29 @@
+package test.sub;
+
+import dagger.internal.Factory;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ContributionsModule_ContributeSomeIntsFactory implements Factory<Set<Integer>> {
+ private final ContributionsModule module;
+
+ public ContributionsModule_ContributeSomeIntsFactory(ContributionsModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Set<Integer> get() {
+ Set<Integer> provided = module.contributeSomeInts();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Set<Integer>> create(ContributionsModule module) {
+ return new ContributionsModule_ContributeSomeIntsFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/DaggerGenericComponent_PackageProxy.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/DaggerGenericComponent_PackageProxy.java
new file mode 100644
index 000000000..24f34741e
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/DaggerGenericComponent_PackageProxy.java
@@ -0,0 +1,16 @@
+package test.sub;
+
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.Generic;
+import test.Generic2;
+import test.sub.PackagePrivateContainer.PublicEnclosed;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerGenericComponent_PackageProxy {
+ public Provider<Generic2<PackagePrivate>> generic2Provider;
+ public Provider<Generic2<PublicEnclosed>> generic2Provider1;
+ public Provider<Generic<PackagePrivate>> genericProvider;
+ public Provider<Generic<PublicEnclosed>> genericProvider1;
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/Exposed_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/Exposed_Factory.java
new file mode 100644
index 000000000..404872f0a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/Exposed_Factory.java
@@ -0,0 +1,36 @@
+package test.sub;
+
+import dagger.MembersInjector;
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.Generic;
+import test.sub.PackagePrivateContainer.PublicEnclosed;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class Exposed_Factory implements Factory<Exposed> {
+ private final MembersInjector<Exposed> membersInjector;
+ private final Provider<Generic<PackagePrivate>> gppProvider;
+ private final Provider<Generic<PublicEnclosed>> gppcProvider;
+
+ public Exposed_Factory(MembersInjector<Exposed> membersInjector, Provider<Generic<PackagePrivate>> gppProvider, Provider<Generic<PublicEnclosed>> gppcProvider) {
+ assert membersInjector != null;
+ this.membersInjector = membersInjector;
+ assert gppProvider != null;
+ this.gppProvider = gppProvider;
+ assert gppcProvider != null;
+ this.gppcProvider = gppcProvider;
+ }
+
+ @Override
+ public Exposed get() {
+ Exposed instance = new Exposed(gppProvider.get(), gppcProvider.get());
+ membersInjector.injectMembers(instance);
+ return instance;
+ }
+
+ public static Factory<Exposed> create(MembersInjector<Exposed> membersInjector, Provider<Generic<PackagePrivate>> gppProvider, Provider<Generic<PublicEnclosed>> gppcProvider) {
+ return new Exposed_Factory(membersInjector, gppProvider, gppcProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/Exposed_MembersInjector.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/Exposed_MembersInjector.java
new file mode 100644
index 000000000..2f94e5a62
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/Exposed_MembersInjector.java
@@ -0,0 +1,34 @@
+package test.sub;
+
+import dagger.MembersInjector;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.Generic2;
+import test.sub.PackagePrivateContainer.PublicEnclosed;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class Exposed_MembersInjector implements MembersInjector<Exposed> {
+ private final Provider<Generic2<PackagePrivate>> gpp2Provider;
+ private final Provider<Generic2<PublicEnclosed>> gppc2Provider;
+
+ public Exposed_MembersInjector(Provider<Generic2<PackagePrivate>> gpp2Provider, Provider<Generic2<PublicEnclosed>> gppc2Provider) {
+ assert gpp2Provider != null;
+ this.gpp2Provider = gpp2Provider;
+ assert gppc2Provider != null;
+ this.gppc2Provider = gppc2Provider;
+ }
+
+ @Override
+ public void injectMembers(Exposed instance) {
+ if (instance == null) {
+ throw new NullPointerException("Cannot inject members into a null reference");
+ }
+ instance.gpp2 = gpp2Provider.get();
+ instance.gppc2 = gppc2Provider.get();
+ }
+
+ public static MembersInjector<Exposed> create(Provider<Generic2<PackagePrivate>> gpp2Provider, Provider<Generic2<PublicEnclosed>> gppc2Provider) {
+ return new Exposed_MembersInjector(gpp2Provider, gppc2Provider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/OtherThing_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/OtherThing_Factory.java
new file mode 100644
index 000000000..8d844fb07
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/OtherThing_Factory.java
@@ -0,0 +1,25 @@
+package test.sub;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class OtherThing_Factory implements Factory<OtherThing> {
+ private final Provider<Integer> iProvider;
+
+ public OtherThing_Factory(Provider<Integer> iProvider) {
+ assert iProvider != null;
+ this.iProvider = iProvider;
+ }
+
+ @Override
+ public OtherThing get() {
+ return new OtherThing(iProvider.get());
+ }
+
+ public static Factory<OtherThing> create(Provider<Integer> iProvider) {
+ return new OtherThing_Factory(iProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PackagePrivateContainer$PublicEnclosed_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PackagePrivateContainer$PublicEnclosed_Factory.java
new file mode 100644
index 000000000..44f943e4c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PackagePrivateContainer$PublicEnclosed_Factory.java
@@ -0,0 +1,20 @@
+package test.sub;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import test.sub.PackagePrivateContainer.PublicEnclosed;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PackagePrivateContainer$PublicEnclosed_Factory implements Factory<PublicEnclosed> {
+INSTANCE;
+
+ @Override
+ public PublicEnclosed get() {
+ return new PublicEnclosed();
+ }
+
+ public static Factory<PublicEnclosed> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PackagePrivate_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PackagePrivate_Factory.java
new file mode 100644
index 000000000..165f4f33a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PackagePrivate_Factory.java
@@ -0,0 +1,19 @@
+package test.sub;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum PackagePrivate_Factory implements Factory<PackagePrivate> {
+INSTANCE;
+
+ @Override
+ public PackagePrivate get() {
+ return new PackagePrivate();
+ }
+
+ public static Factory<PackagePrivate> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PublicSubclass2_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PublicSubclass2_Factory.java
new file mode 100644
index 000000000..0c863c6d9
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PublicSubclass2_Factory.java
@@ -0,0 +1,32 @@
+package test.sub;
+
+import dagger.MembersInjector;
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.sub.PackagePrivateContainer.PublicEnclosed;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class PublicSubclass2_Factory implements Factory<PublicSubclass2> {
+ private final MembersInjector<PublicSubclass2> membersInjector;
+ private final Provider<PublicEnclosed> ppProvider;
+
+ public PublicSubclass2_Factory(MembersInjector<PublicSubclass2> membersInjector, Provider<PublicEnclosed> ppProvider) {
+ assert membersInjector != null;
+ this.membersInjector = membersInjector;
+ assert ppProvider != null;
+ this.ppProvider = ppProvider;
+ }
+
+ @Override
+ public PublicSubclass2 get() {
+ PublicSubclass2 instance = new PublicSubclass2(ppProvider.get());
+ membersInjector.injectMembers(instance);
+ return instance;
+ }
+
+ public static Factory<PublicSubclass2> create(MembersInjector<PublicSubclass2> membersInjector, Provider<PublicEnclosed> ppProvider) {
+ return new PublicSubclass2_Factory(membersInjector, ppProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PublicSubclass_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PublicSubclass_Factory.java
new file mode 100644
index 000000000..1f2f5406f
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/sub/PublicSubclass_Factory.java
@@ -0,0 +1,31 @@
+package test.sub;
+
+import dagger.MembersInjector;
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class PublicSubclass_Factory implements Factory<PublicSubclass> {
+ private final MembersInjector<PublicSubclass> membersInjector;
+ private final Provider<PackagePrivate> ppProvider;
+
+ public PublicSubclass_Factory(MembersInjector<PublicSubclass> membersInjector, Provider<PackagePrivate> ppProvider) {
+ assert membersInjector != null;
+ this.membersInjector = membersInjector;
+ assert ppProvider != null;
+ this.ppProvider = ppProvider;
+ }
+
+ @Override
+ public PublicSubclass get() {
+ PublicSubclass instance = new PublicSubclass(ppProvider.get());
+ membersInjector.injectMembers(instance);
+ return instance;
+ }
+
+ public static Factory<PublicSubclass> create(MembersInjector<PublicSubclass> membersInjector, Provider<PackagePrivate> ppProvider) {
+ return new PublicSubclass_Factory(membersInjector, ppProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ChildModuleWithState_ProvideIntFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ChildModuleWithState_ProvideIntFactory.java
new file mode 100644
index 000000000..150bdc090
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ChildModuleWithState_ProvideIntFactory.java
@@ -0,0 +1,28 @@
+package test.subcomponent;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ChildModuleWithState_ProvideIntFactory implements Factory<Integer> {
+ private final ChildModuleWithState module;
+
+ public ChildModuleWithState_ProvideIntFactory(ChildModuleWithState module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Integer get() {
+ Integer provided = module.provideInt();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Integer> create(ChildModuleWithState module) {
+ return new ChildModuleWithState_ProvideIntFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ChildModule_ProvideUnscopedObjectFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ChildModule_ProvideUnscopedObjectFactory.java
new file mode 100644
index 000000000..67456801a
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ChildModule_ProvideUnscopedObjectFactory.java
@@ -0,0 +1,26 @@
+package test.subcomponent;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ChildModule_ProvideUnscopedObjectFactory implements Factory<Set<Object>> {
+ private final ChildModule module;
+
+ public ChildModule_ProvideUnscopedObjectFactory(ChildModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Set<Object> get() {
+ return Collections.<Object>singleton(module.provideUnscopedObject());
+ }
+
+ public static Factory<Set<Object>> create(ChildModule module) {
+ return new ChildModule_ProvideUnscopedObjectFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/DaggerParentComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/DaggerParentComponent.java
new file mode 100644
index 000000000..7169bbf43
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/DaggerParentComponent.java
@@ -0,0 +1,274 @@
+package test.subcomponent;
+
+import dagger.internal.ScopedProvider;
+import dagger.internal.SetFactory;
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerParentComponent implements ParentComponent {
+ private Provider<SingletonType> singletonTypeProvider;
+ private Provider<UnscopedType> unscopedTypeProvider;
+ private Provider<Set<Object>> setOfObjectContribution1Provider;
+ private Provider<Set<Object>> setOfObjectContribution2Provider;
+ private Provider<Set<Object>> setOfObjectProvider;
+ private Provider<UnscopedType> provideUnscopedTypeBoundAsSingletonProvider;
+
+ private DaggerParentComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static ParentComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.singletonTypeProvider = ScopedProvider.create(SingletonType_Factory.create());
+ this.unscopedTypeProvider = UnscopedType_Factory.create(singletonTypeProvider);
+ this.setOfObjectContribution1Provider = ParentModule_ProvideUnscopedObjectFactory.create(builder.parentModule);
+ this.setOfObjectContribution2Provider = ScopedProvider.create(ParentModule_ProvideSingletonObjectFactory.create(builder.parentModule));
+ this.setOfObjectProvider = SetFactory.create(setOfObjectContribution1Provider, setOfObjectContribution2Provider);
+ this.provideUnscopedTypeBoundAsSingletonProvider = ScopedProvider.create(ParentModule_ProvideUnscopedTypeBoundAsSingletonFactory.create(builder.parentModule, unscopedTypeProvider));
+ }
+
+ @Override
+ public Provider<UnscopedType> getUnscopedTypeProvider() {
+ return unscopedTypeProvider;
+ }
+
+ @Override
+ public Set<Object> objectSet() {
+ return setOfObjectProvider.get();
+ }
+
+ @Override
+ public ChildComponent newChildComponent() {
+ return new ChildComponentImpl();
+ }
+
+ @Override
+ public ChildAbstractClassComponent newChildAbstractClassComponent() {
+ return new ChildAbstractClassComponentImpl();
+ }
+
+ @Override
+ public ChildComponentRequiringModules newChildComponentRequiringModules(ChildModuleWithParameters cmwp, ChildModuleWithState childModuleWithState) {
+ return new ChildComponentRequiringModulesImpl(cmwp, childModuleWithState);
+ }
+
+ public static final class Builder {
+ private ParentModule parentModule;
+
+ private Builder() {
+ }
+
+ public ParentComponent build() {
+ if (parentModule == null) {
+ this.parentModule = new ParentModule();
+ }
+ return new DaggerParentComponent(this);
+ }
+
+ public Builder parentModule(ParentModule parentModule) {
+ if (parentModule == null) {
+ throw new NullPointerException("parentModule");
+ }
+ this.parentModule = parentModule;
+ return this;
+ }
+ }
+
+ private final class ChildComponentImpl implements ChildComponent {
+ private final ChildModule childModule;
+ private Provider<RequiresSingletons> requiresSingletonsProvider;
+ private Provider<Set<Object>> setOfObjectContribution3Provider;
+ private Provider<Set<Object>> setOfObjectProvider;
+
+ private ChildComponentImpl() {
+ this.childModule = new ChildModule();
+ initialize();
+ }
+
+ private void initialize() {
+ this.requiresSingletonsProvider = RequiresSingletons_Factory.create(DaggerParentComponent.this.singletonTypeProvider, DaggerParentComponent.this.provideUnscopedTypeBoundAsSingletonProvider);
+ this.setOfObjectContribution3Provider = ChildModule_ProvideUnscopedObjectFactory.create(childModule);
+ this.setOfObjectProvider = SetFactory.create(setOfObjectContribution1Provider, setOfObjectContribution2Provider, setOfObjectContribution3Provider);
+ }
+
+ @Override
+ public Provider<UnscopedType> getUnscopedTypeProvider() {
+ return DaggerParentComponent.this.unscopedTypeProvider;
+ }
+
+ @Override
+ public RequiresSingletons requiresSingleton() {
+ return requiresSingletonsProvider.get();
+ }
+
+ @Override
+ public Set<Object> objectSet() {
+ return setOfObjectProvider.get();
+ }
+
+ @Override
+ public GrandchildComponent newGrandchildComponent() {
+ return new GrandchildComponentImpl();
+ }
+
+ private final class GrandchildComponentImpl implements GrandchildComponent {
+ private final GrandchildModule grandchildModule;
+ private Provider<Set<Object>> setOfObjectContribution4Provider;
+ private Provider<Set<Object>> setOfObjectProvider;
+ private Provider<AnInterface> provideAnInterfaceProvider;
+ private Provider<NeedsAnInterface> provideNeedsAnInterfaceProvider;
+
+ private GrandchildComponentImpl() {
+ this.grandchildModule = new GrandchildModule();
+ initialize();
+ }
+
+ private void initialize() {
+ this.setOfObjectContribution4Provider = GrandchildModule_ProvideUnscopedObjectFactory.create(grandchildModule);
+ this.setOfObjectProvider = SetFactory.create(setOfObjectContribution1Provider, setOfObjectContribution2Provider, setOfObjectContribution3Provider, setOfObjectContribution4Provider);
+ this.provideAnInterfaceProvider = GrandchildModule_ProvideAnInterfaceFactory.create(grandchildModule, ImplementsAnInterface_Factory.create());
+ this.provideNeedsAnInterfaceProvider = GrandchildModule_ProvideNeedsAnInterfaceFactory.create(grandchildModule, provideAnInterfaceProvider);
+ }
+
+ @Override
+ public Provider<UnscopedType> getUnscopedTypeProvider() {
+ return DaggerParentComponent.this.unscopedTypeProvider;
+ }
+
+ @Override
+ public RequiresSingletons requiresSingleton() {
+ return ChildComponentImpl.this.requiresSingletonsProvider.get();
+ }
+
+ @Override
+ public Set<Object> objectSet() {
+ return setOfObjectProvider.get();
+ }
+
+ @Override
+ public NeedsAnInterface needsAnInterface() {
+ return provideNeedsAnInterfaceProvider.get();
+ }
+ }
+ }
+
+ private final class ChildAbstractClassComponentImpl extends ChildAbstractClassComponent {
+ private final ChildModule childModule;
+ private Provider<RequiresSingletons> requiresSingletonsProvider;
+ private Provider<Set<Object>> setOfObjectContribution3Provider;
+ private Provider<Set<Object>> setOfObjectProvider;
+
+ private ChildAbstractClassComponentImpl() {
+ this.childModule = new ChildModule();
+ initialize();
+ }
+
+ private void initialize() {
+ this.requiresSingletonsProvider = RequiresSingletons_Factory.create(DaggerParentComponent.this.singletonTypeProvider, DaggerParentComponent.this.provideUnscopedTypeBoundAsSingletonProvider);
+ this.setOfObjectContribution3Provider = ChildModule_ProvideUnscopedObjectFactory.create(childModule);
+ this.setOfObjectProvider = SetFactory.create(setOfObjectContribution1Provider, setOfObjectContribution2Provider, setOfObjectContribution3Provider);
+ }
+
+ @Override
+ public Provider<UnscopedType> getUnscopedTypeProvider() {
+ return DaggerParentComponent.this.unscopedTypeProvider;
+ }
+
+ @Override
+ public RequiresSingletons requiresSingleton() {
+ return requiresSingletonsProvider.get();
+ }
+
+ @Override
+ public Set<Object> objectSet() {
+ return setOfObjectProvider.get();
+ }
+
+ @Override
+ public GrandchildComponent newGrandchildComponent() {
+ return new GrandchildComponentImpl();
+ }
+
+ private final class GrandchildComponentImpl implements GrandchildComponent {
+ private final GrandchildModule grandchildModule;
+ private Provider<Set<Object>> setOfObjectContribution4Provider;
+ private Provider<Set<Object>> setOfObjectProvider;
+ private Provider<AnInterface> provideAnInterfaceProvider;
+ private Provider<NeedsAnInterface> provideNeedsAnInterfaceProvider;
+
+ private GrandchildComponentImpl() {
+ this.grandchildModule = new GrandchildModule();
+ initialize();
+ }
+
+ private void initialize() {
+ this.setOfObjectContribution4Provider = GrandchildModule_ProvideUnscopedObjectFactory.create(grandchildModule);
+ this.setOfObjectProvider = SetFactory.create(setOfObjectContribution1Provider, setOfObjectContribution2Provider, setOfObjectContribution3Provider, setOfObjectContribution4Provider);
+ this.provideAnInterfaceProvider = GrandchildModule_ProvideAnInterfaceFactory.create(grandchildModule, ImplementsAnInterface_Factory.create());
+ this.provideNeedsAnInterfaceProvider = GrandchildModule_ProvideNeedsAnInterfaceFactory.create(grandchildModule, provideAnInterfaceProvider);
+ }
+
+ @Override
+ public Provider<UnscopedType> getUnscopedTypeProvider() {
+ return DaggerParentComponent.this.unscopedTypeProvider;
+ }
+
+ @Override
+ public RequiresSingletons requiresSingleton() {
+ return ChildAbstractClassComponentImpl.this.requiresSingletonsProvider.get();
+ }
+
+ @Override
+ public Set<Object> objectSet() {
+ return setOfObjectProvider.get();
+ }
+
+ @Override
+ public NeedsAnInterface needsAnInterface() {
+ return provideNeedsAnInterfaceProvider.get();
+ }
+ }
+ }
+
+ private final class ChildComponentRequiringModulesImpl implements ChildComponentRequiringModules {
+ private final ChildModuleWithParameters childModuleWithParameters;
+ private final ChildModuleWithState childModuleWithState;
+ private final ChildModule childModule;
+ private Provider<Integer> provideIntProvider;
+ private Provider<Set<Object>> setOfObjectProvider;
+
+ private ChildComponentRequiringModulesImpl(ChildModuleWithParameters childModuleWithParameters, ChildModuleWithState childModuleWithState) {
+ if (childModuleWithParameters == null) {
+ throw new NullPointerException();
+ }
+ this.childModuleWithParameters = childModuleWithParameters;
+ if (childModuleWithState == null) {
+ throw new NullPointerException();
+ }
+ this.childModuleWithState = childModuleWithState;
+ this.childModule = new ChildModule();
+ initialize();
+ }
+
+ private void initialize() {
+ this.provideIntProvider = ChildModuleWithState_ProvideIntFactory.create(childModuleWithState);
+ this.setOfObjectProvider = SetFactory.create(setOfObjectContribution1Provider, setOfObjectContribution2Provider);
+ }
+
+ @Override
+ public int getInt() {
+ return provideIntProvider.get();
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/DaggerParentOfGenericComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/DaggerParentOfGenericComponent.java
new file mode 100644
index 000000000..bb1e240b8
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/DaggerParentOfGenericComponent.java
@@ -0,0 +1,155 @@
+package test.subcomponent;
+
+import dagger.internal.ScopedProvider;
+import dagger.internal.SetFactory;
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerParentOfGenericComponent implements ParentOfGenericComponent {
+ private Provider<SingletonType> singletonTypeProvider;
+ private Provider<UnscopedType> unscopedTypeProvider;
+ private Provider<Set<Object>> setOfObjectContribution1Provider;
+ private Provider<Set<Object>> setOfObjectContribution2Provider;
+ private Provider<Set<Object>> setOfObjectProvider;
+ private Provider<UnscopedType> provideUnscopedTypeBoundAsSingletonProvider;
+
+ private DaggerParentOfGenericComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static ParentOfGenericComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.singletonTypeProvider = ScopedProvider.create(SingletonType_Factory.create());
+ this.unscopedTypeProvider = UnscopedType_Factory.create(singletonTypeProvider);
+ this.setOfObjectContribution1Provider = ParentModule_ProvideUnscopedObjectFactory.create(builder.parentModule);
+ this.setOfObjectContribution2Provider = ScopedProvider.create(ParentModule_ProvideSingletonObjectFactory.create(builder.parentModule));
+ this.setOfObjectProvider = SetFactory.create(setOfObjectContribution1Provider, setOfObjectContribution2Provider);
+ this.provideUnscopedTypeBoundAsSingletonProvider = ScopedProvider.create(ParentModule_ProvideUnscopedTypeBoundAsSingletonFactory.create(builder.parentModule, unscopedTypeProvider));
+ }
+
+ @Override
+ public Provider<UnscopedType> getUnscopedTypeProvider() {
+ return unscopedTypeProvider;
+ }
+
+ @Override
+ public Set<Object> objectSet() {
+ return setOfObjectProvider.get();
+ }
+
+ @Override
+ public ChildComponent subcomponent() {
+ return new ChildComponentImpl();
+ }
+
+ public static final class Builder {
+ private ParentModule parentModule;
+
+ private Builder() {
+ }
+
+ public ParentOfGenericComponent build() {
+ if (parentModule == null) {
+ this.parentModule = new ParentModule();
+ }
+ return new DaggerParentOfGenericComponent(this);
+ }
+
+ public Builder parentModule(ParentModule parentModule) {
+ if (parentModule == null) {
+ throw new NullPointerException("parentModule");
+ }
+ this.parentModule = parentModule;
+ return this;
+ }
+ }
+
+ private final class ChildComponentImpl implements ChildComponent {
+ private final ChildModule childModule;
+ private Provider<RequiresSingletons> requiresSingletonsProvider;
+ private Provider<Set<Object>> setOfObjectContribution3Provider;
+ private Provider<Set<Object>> setOfObjectProvider;
+
+ private ChildComponentImpl() {
+ this.childModule = new ChildModule();
+ initialize();
+ }
+
+ private void initialize() {
+ this.requiresSingletonsProvider = RequiresSingletons_Factory.create(DaggerParentOfGenericComponent.this.singletonTypeProvider, DaggerParentOfGenericComponent.this.provideUnscopedTypeBoundAsSingletonProvider);
+ this.setOfObjectContribution3Provider = ChildModule_ProvideUnscopedObjectFactory.create(childModule);
+ this.setOfObjectProvider = SetFactory.create(setOfObjectContribution1Provider, setOfObjectContribution2Provider, setOfObjectContribution3Provider);
+ }
+
+ @Override
+ public Provider<UnscopedType> getUnscopedTypeProvider() {
+ return DaggerParentOfGenericComponent.this.unscopedTypeProvider;
+ }
+
+ @Override
+ public RequiresSingletons requiresSingleton() {
+ return requiresSingletonsProvider.get();
+ }
+
+ @Override
+ public Set<Object> objectSet() {
+ return setOfObjectProvider.get();
+ }
+
+ @Override
+ public GrandchildComponent newGrandchildComponent() {
+ return new GrandchildComponentImpl();
+ }
+
+ private final class GrandchildComponentImpl implements GrandchildComponent {
+ private final GrandchildModule grandchildModule;
+ private Provider<Set<Object>> setOfObjectContribution4Provider;
+ private Provider<Set<Object>> setOfObjectProvider;
+ private Provider<AnInterface> provideAnInterfaceProvider;
+ private Provider<NeedsAnInterface> provideNeedsAnInterfaceProvider;
+
+ private GrandchildComponentImpl() {
+ this.grandchildModule = new GrandchildModule();
+ initialize();
+ }
+
+ private void initialize() {
+ this.setOfObjectContribution4Provider = GrandchildModule_ProvideUnscopedObjectFactory.create(grandchildModule);
+ this.setOfObjectProvider = SetFactory.create(setOfObjectContribution1Provider, setOfObjectContribution2Provider, setOfObjectContribution3Provider, setOfObjectContribution4Provider);
+ this.provideAnInterfaceProvider = GrandchildModule_ProvideAnInterfaceFactory.create(grandchildModule, ImplementsAnInterface_Factory.create());
+ this.provideNeedsAnInterfaceProvider = GrandchildModule_ProvideNeedsAnInterfaceFactory.create(grandchildModule, provideAnInterfaceProvider);
+ }
+
+ @Override
+ public Provider<UnscopedType> getUnscopedTypeProvider() {
+ return DaggerParentOfGenericComponent.this.unscopedTypeProvider;
+ }
+
+ @Override
+ public RequiresSingletons requiresSingleton() {
+ return ChildComponentImpl.this.requiresSingletonsProvider.get();
+ }
+
+ @Override
+ public Set<Object> objectSet() {
+ return setOfObjectProvider.get();
+ }
+
+ @Override
+ public NeedsAnInterface needsAnInterface() {
+ return provideNeedsAnInterfaceProvider.get();
+ }
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/GrandchildModule_ProvideAnInterfaceFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/GrandchildModule_ProvideAnInterfaceFactory.java
new file mode 100644
index 000000000..f2bdbe7e3
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/GrandchildModule_ProvideAnInterfaceFactory.java
@@ -0,0 +1,32 @@
+package test.subcomponent;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class GrandchildModule_ProvideAnInterfaceFactory implements Factory<AnInterface> {
+ private final GrandchildModule module;
+ private final Provider<ImplementsAnInterface> implementsAnInterfaceProvider;
+
+ public GrandchildModule_ProvideAnInterfaceFactory(GrandchildModule module, Provider<ImplementsAnInterface> implementsAnInterfaceProvider) {
+ assert module != null;
+ this.module = module;
+ assert implementsAnInterfaceProvider != null;
+ this.implementsAnInterfaceProvider = implementsAnInterfaceProvider;
+ }
+
+ @Override
+ public AnInterface get() {
+ AnInterface provided = module.provideAnInterface(implementsAnInterfaceProvider.get());
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<AnInterface> create(GrandchildModule module, Provider<ImplementsAnInterface> implementsAnInterfaceProvider) {
+ return new GrandchildModule_ProvideAnInterfaceFactory(module, implementsAnInterfaceProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/GrandchildModule_ProvideNeedsAnInterfaceFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/GrandchildModule_ProvideNeedsAnInterfaceFactory.java
new file mode 100644
index 000000000..25801e090
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/GrandchildModule_ProvideNeedsAnInterfaceFactory.java
@@ -0,0 +1,32 @@
+package test.subcomponent;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class GrandchildModule_ProvideNeedsAnInterfaceFactory implements Factory<NeedsAnInterface> {
+ private final GrandchildModule module;
+ private final Provider<AnInterface> anInterfaceProvider;
+
+ public GrandchildModule_ProvideNeedsAnInterfaceFactory(GrandchildModule module, Provider<AnInterface> anInterfaceProvider) {
+ assert module != null;
+ this.module = module;
+ assert anInterfaceProvider != null;
+ this.anInterfaceProvider = anInterfaceProvider;
+ }
+
+ @Override
+ public NeedsAnInterface get() {
+ NeedsAnInterface provided = module.provideNeedsAnInterface(anInterfaceProvider.get());
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<NeedsAnInterface> create(GrandchildModule module, Provider<AnInterface> anInterfaceProvider) {
+ return new GrandchildModule_ProvideNeedsAnInterfaceFactory(module, anInterfaceProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/GrandchildModule_ProvideUnscopedObjectFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/GrandchildModule_ProvideUnscopedObjectFactory.java
new file mode 100644
index 000000000..677282ff6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/GrandchildModule_ProvideUnscopedObjectFactory.java
@@ -0,0 +1,26 @@
+package test.subcomponent;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class GrandchildModule_ProvideUnscopedObjectFactory implements Factory<Set<Object>> {
+ private final GrandchildModule module;
+
+ public GrandchildModule_ProvideUnscopedObjectFactory(GrandchildModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Set<Object> get() {
+ return Collections.<Object>singleton(module.provideUnscopedObject());
+ }
+
+ public static Factory<Set<Object>> create(GrandchildModule module) {
+ return new GrandchildModule_ProvideUnscopedObjectFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ImplementsAnInterface_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ImplementsAnInterface_Factory.java
new file mode 100644
index 000000000..592b8a78d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ImplementsAnInterface_Factory.java
@@ -0,0 +1,19 @@
+package test.subcomponent;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum ImplementsAnInterface_Factory implements Factory<ImplementsAnInterface> {
+INSTANCE;
+
+ @Override
+ public ImplementsAnInterface get() {
+ return new ImplementsAnInterface();
+ }
+
+ public static Factory<ImplementsAnInterface> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ParentModule_ProvideSingletonObjectFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ParentModule_ProvideSingletonObjectFactory.java
new file mode 100644
index 000000000..e59a84002
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ParentModule_ProvideSingletonObjectFactory.java
@@ -0,0 +1,26 @@
+package test.subcomponent;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ParentModule_ProvideSingletonObjectFactory implements Factory<Set<Object>> {
+ private final ParentModule module;
+
+ public ParentModule_ProvideSingletonObjectFactory(ParentModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Set<Object> get() {
+ return Collections.<Object>singleton(module.provideSingletonObject());
+ }
+
+ public static Factory<Set<Object>> create(ParentModule module) {
+ return new ParentModule_ProvideSingletonObjectFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ParentModule_ProvideUnscopedObjectFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ParentModule_ProvideUnscopedObjectFactory.java
new file mode 100644
index 000000000..854a59a4d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ParentModule_ProvideUnscopedObjectFactory.java
@@ -0,0 +1,26 @@
+package test.subcomponent;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ParentModule_ProvideUnscopedObjectFactory implements Factory<Set<Object>> {
+ private final ParentModule module;
+
+ public ParentModule_ProvideUnscopedObjectFactory(ParentModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Set<Object> get() {
+ return Collections.<Object>singleton(module.provideUnscopedObject());
+ }
+
+ public static Factory<Set<Object>> create(ParentModule module) {
+ return new ParentModule_ProvideUnscopedObjectFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ParentModule_ProvideUnscopedTypeBoundAsSingletonFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ParentModule_ProvideUnscopedTypeBoundAsSingletonFactory.java
new file mode 100644
index 000000000..fbe6e4fa9
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/ParentModule_ProvideUnscopedTypeBoundAsSingletonFactory.java
@@ -0,0 +1,32 @@
+package test.subcomponent;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ParentModule_ProvideUnscopedTypeBoundAsSingletonFactory implements Factory<UnscopedType> {
+ private final ParentModule module;
+ private final Provider<UnscopedType> unscopedTypeProvider;
+
+ public ParentModule_ProvideUnscopedTypeBoundAsSingletonFactory(ParentModule module, Provider<UnscopedType> unscopedTypeProvider) {
+ assert module != null;
+ this.module = module;
+ assert unscopedTypeProvider != null;
+ this.unscopedTypeProvider = unscopedTypeProvider;
+ }
+
+ @Override
+ public UnscopedType get() {
+ UnscopedType provided = module.provideUnscopedTypeBoundAsSingleton(unscopedTypeProvider.get());
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<UnscopedType> create(ParentModule module, Provider<UnscopedType> unscopedTypeProvider) {
+ return new ParentModule_ProvideUnscopedTypeBoundAsSingletonFactory(module, unscopedTypeProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/RequiresSingletons_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/RequiresSingletons_Factory.java
new file mode 100644
index 000000000..fbe397c6c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/RequiresSingletons_Factory.java
@@ -0,0 +1,28 @@
+package test.subcomponent;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class RequiresSingletons_Factory implements Factory<RequiresSingletons> {
+ private final Provider<SingletonType> singletonTypeProvider;
+ private final Provider<UnscopedType> unscopedTypeBoundAsSingletonProvider;
+
+ public RequiresSingletons_Factory(Provider<SingletonType> singletonTypeProvider, Provider<UnscopedType> unscopedTypeBoundAsSingletonProvider) {
+ assert singletonTypeProvider != null;
+ this.singletonTypeProvider = singletonTypeProvider;
+ assert unscopedTypeBoundAsSingletonProvider != null;
+ this.unscopedTypeBoundAsSingletonProvider = unscopedTypeBoundAsSingletonProvider;
+ }
+
+ @Override
+ public RequiresSingletons get() {
+ return new RequiresSingletons(singletonTypeProvider.get(), unscopedTypeBoundAsSingletonProvider.get());
+ }
+
+ public static Factory<RequiresSingletons> create(Provider<SingletonType> singletonTypeProvider, Provider<UnscopedType> unscopedTypeBoundAsSingletonProvider) {
+ return new RequiresSingletons_Factory(singletonTypeProvider, unscopedTypeBoundAsSingletonProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/SingletonType_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/SingletonType_Factory.java
new file mode 100644
index 000000000..1159e38cf
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/SingletonType_Factory.java
@@ -0,0 +1,19 @@
+package test.subcomponent;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum SingletonType_Factory implements Factory<SingletonType> {
+INSTANCE;
+
+ @Override
+ public SingletonType get() {
+ return new SingletonType();
+ }
+
+ public static Factory<SingletonType> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/UnscopedType_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/UnscopedType_Factory.java
new file mode 100644
index 000000000..9b2a57582
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/UnscopedType_Factory.java
@@ -0,0 +1,25 @@
+package test.subcomponent;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class UnscopedType_Factory implements Factory<UnscopedType> {
+ private final Provider<SingletonType> singletonTypeProvider;
+
+ public UnscopedType_Factory(Provider<SingletonType> singletonTypeProvider) {
+ assert singletonTypeProvider != null;
+ this.singletonTypeProvider = singletonTypeProvider;
+ }
+
+ @Override
+ public UnscopedType get() {
+ return new UnscopedType(singletonTypeProvider.get());
+ }
+
+ public static Factory<UnscopedType> create(Provider<SingletonType> singletonTypeProvider) {
+ return new UnscopedType_Factory(singletonTypeProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/DaggerParentComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/DaggerParentComponent.java
new file mode 100644
index 000000000..1360a9b9c
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/DaggerParentComponent.java
@@ -0,0 +1,91 @@
+package test.subcomponent.hiding;
+
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.subcomponent.hiding.a.CommonModuleName;
+import test.subcomponent.hiding.a.CommonModuleName_ProvideStringFactory;
+import test.subcomponent.hiding.a.CommonName;
+import test.subcomponent.hiding.a.CommonName_Factory;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerParentComponent implements ParentComponent {
+ private Provider<String> provideStringProvider;
+ private Provider<CommonName> commonNameProvider;
+
+ private DaggerParentComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static ParentComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.provideStringProvider = CommonModuleName_ProvideStringFactory.create(builder.commonModuleName);
+ this.commonNameProvider = CommonName_Factory.create(provideStringProvider);
+ }
+
+ @Override
+ public CommonName aCommonName() {
+ return commonNameProvider.get();
+ }
+
+ @Override
+ public ChildComponent newChildComponent() {
+ return new ChildComponentImpl();
+ }
+
+ public static final class Builder {
+ private CommonModuleName commonModuleName;
+
+ private Builder() {
+ }
+
+ public ParentComponent build() {
+ if (commonModuleName == null) {
+ this.commonModuleName = new CommonModuleName();
+ }
+ return new DaggerParentComponent(this);
+ }
+
+ public Builder commonModuleName(CommonModuleName commonModuleName) {
+ if (commonModuleName == null) {
+ throw new NullPointerException("commonModuleName");
+ }
+ this.commonModuleName = commonModuleName;
+ return this;
+ }
+ }
+
+ private final class ChildComponentImpl implements ChildComponent {
+ private final test.subcomponent.hiding.b.CommonModuleName commonModuleName;
+ private Provider<Integer> provideStringProvider;
+ private Provider<test.subcomponent.hiding.b.CommonName> commonNameProvider;
+
+ private ChildComponentImpl() {
+ this.commonModuleName = new test.subcomponent.hiding.b.CommonModuleName();
+ initialize();
+ }
+
+ private void initialize() {
+ this.provideStringProvider = test.subcomponent.hiding.b.CommonModuleName_ProvideStringFactory.create(commonModuleName);
+ this.commonNameProvider = test.subcomponent.hiding.b.CommonName_Factory.create(provideStringProvider);
+ }
+
+ @Override
+ public CommonName aCommonName() {
+ return DaggerParentComponent.this.commonNameProvider.get();
+ }
+
+ @Override
+ public test.subcomponent.hiding.b.CommonName bCommonName() {
+ return commonNameProvider.get();
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/a/CommonModuleName_ProvideStringFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/a/CommonModuleName_ProvideStringFactory.java
new file mode 100644
index 000000000..c782d1ec6
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/a/CommonModuleName_ProvideStringFactory.java
@@ -0,0 +1,28 @@
+package test.subcomponent.hiding.a;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class CommonModuleName_ProvideStringFactory implements Factory<String> {
+ private final CommonModuleName module;
+
+ public CommonModuleName_ProvideStringFactory(CommonModuleName module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.provideString();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(CommonModuleName module) {
+ return new CommonModuleName_ProvideStringFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/a/CommonName_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/a/CommonName_Factory.java
new file mode 100644
index 000000000..ffe03c9eb
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/a/CommonName_Factory.java
@@ -0,0 +1,25 @@
+package test.subcomponent.hiding.a;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class CommonName_Factory implements Factory<CommonName> {
+ private final Provider<String> sProvider;
+
+ public CommonName_Factory(Provider<String> sProvider) {
+ assert sProvider != null;
+ this.sProvider = sProvider;
+ }
+
+ @Override
+ public CommonName get() {
+ return new CommonName(sProvider.get());
+ }
+
+ public static Factory<CommonName> create(Provider<String> sProvider) {
+ return new CommonName_Factory(sProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/b/CommonModuleName_ProvideStringFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/b/CommonModuleName_ProvideStringFactory.java
new file mode 100644
index 000000000..9eb4d10c0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/b/CommonModuleName_ProvideStringFactory.java
@@ -0,0 +1,28 @@
+package test.subcomponent.hiding.b;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class CommonModuleName_ProvideStringFactory implements Factory<Integer> {
+ private final CommonModuleName module;
+
+ public CommonModuleName_ProvideStringFactory(CommonModuleName module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Integer get() {
+ Integer provided = module.provideString();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<Integer> create(CommonModuleName module) {
+ return new CommonModuleName_ProvideStringFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/b/CommonName_Factory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/b/CommonName_Factory.java
new file mode 100644
index 000000000..e05b6f4d9
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/hiding/b/CommonName_Factory.java
@@ -0,0 +1,25 @@
+package test.subcomponent.hiding.b;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class CommonName_Factory implements Factory<CommonName> {
+ private final Provider<Integer> iProvider;
+
+ public CommonName_Factory(Provider<Integer> iProvider) {
+ assert iProvider != null;
+ this.iProvider = iProvider;
+ }
+
+ @Override
+ public CommonName get() {
+ return new CommonName(iProvider.get());
+ }
+
+ public static Factory<CommonName> create(Provider<Integer> iProvider) {
+ return new CommonName_Factory(iProvider);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/DaggerParentComponent.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/DaggerParentComponent.java
new file mode 100644
index 000000000..9b46e3011
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/DaggerParentComponent.java
@@ -0,0 +1,102 @@
+package test.subcomponent.repeat;
+
+import dagger.internal.SetFactory;
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import test.subcomponent.repeat.ParentComponent;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerParentComponent implements ParentComponent {
+ private Provider<String> provideStringProvider;
+ private Provider<Set<String>> setOfStringContribution1Provider;
+ private Provider<Set<String>> setOfStringProvider;
+ private Provider<OnlyUsedInParent> provideOnlyUsedInParentProvider;
+
+ private DaggerParentComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static ParentComponent.Builder builder() {
+ return new Builder();
+ }
+
+ public static ParentComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.provideStringProvider = RepeatedModule_ProvideStringFactory.create(builder.repeatedModule);
+ this.setOfStringContribution1Provider = RepeatedModule_ContributeStringFactory.create(builder.repeatedModule);
+ this.setOfStringProvider = SetFactory.create(setOfStringContribution1Provider);
+ this.provideOnlyUsedInParentProvider = RepeatedModule_ProvideOnlyUsedInParentFactory.create(builder.repeatedModule);
+ }
+
+ @Override
+ public String getString() {
+ return provideStringProvider.get();
+ }
+
+ @Override
+ public Set<String> getMultiboundStrings() {
+ return setOfStringProvider.get();
+ }
+
+ @Override
+ public OnlyUsedInParent getOnlyUsedInParent() {
+ return provideOnlyUsedInParentProvider.get();
+ }
+
+ @Override
+ public ChildComponent newChildComponent() {
+ return new ChildComponentImpl();
+ }
+
+ private static final class Builder implements ParentComponent.Builder {
+ private RepeatedModule repeatedModule;
+
+
+ @Override
+ public ParentComponent build() {
+ if (repeatedModule == null) {
+ this.repeatedModule = new RepeatedModule();
+ }
+ return new DaggerParentComponent(this);
+ }
+ }
+
+ private final class ChildComponentImpl implements ChildComponent {
+ private final RepeatedModule repeatedModule;
+ private Provider<Set<String>> setOfStringContribution1Provider;
+ private Provider<Set<String>> setOfStringProvider;
+ private Provider<OnlyUsedInChild> provideOnlyUsedInChildProvider;
+
+ private ChildComponentImpl() {
+ this.repeatedModule = new RepeatedModule();
+ initialize();
+ }
+
+ private void initialize() {
+ this.setOfStringContribution1Provider = RepeatedModule_ContributeStringFactory.create(repeatedModule);
+ this.setOfStringProvider = SetFactory.create(setOfStringContribution1Provider);
+ this.provideOnlyUsedInChildProvider = RepeatedModule_ProvideOnlyUsedInChildFactory.create(repeatedModule);
+ }
+
+ @Override
+ public String getString() {
+ return DaggerParentComponent.this.provideStringProvider.get();
+ }
+
+ @Override
+ public Set<String> getMultiboundStrings() {
+ return setOfStringProvider.get();
+ }
+
+ @Override
+ public OnlyUsedInChild getOnlyUsedInChild() {
+ return provideOnlyUsedInChildProvider.get();
+ }
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ContributeStringFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ContributeStringFactory.java
new file mode 100644
index 000000000..63bebf89b
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ContributeStringFactory.java
@@ -0,0 +1,26 @@
+package test.subcomponent.repeat;
+
+import dagger.internal.Factory;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class RepeatedModule_ContributeStringFactory implements Factory<Set<String>> {
+ private final RepeatedModule module;
+
+ public RepeatedModule_ContributeStringFactory(RepeatedModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public Set<String> get() {
+ return Collections.<String>singleton(module.contributeString());
+ }
+
+ public static Factory<Set<String>> create(RepeatedModule module) {
+ return new RepeatedModule_ContributeStringFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInChildFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInChildFactory.java
new file mode 100644
index 000000000..4ac085de0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInChildFactory.java
@@ -0,0 +1,28 @@
+package test.subcomponent.repeat;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class RepeatedModule_ProvideOnlyUsedInChildFactory implements Factory<OnlyUsedInChild> {
+ private final RepeatedModule module;
+
+ public RepeatedModule_ProvideOnlyUsedInChildFactory(RepeatedModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public OnlyUsedInChild get() {
+ OnlyUsedInChild provided = module.provideOnlyUsedInChild();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<OnlyUsedInChild> create(RepeatedModule module) {
+ return new RepeatedModule_ProvideOnlyUsedInChildFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInParentFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInParentFactory.java
new file mode 100644
index 000000000..e3fd0ff64
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ProvideOnlyUsedInParentFactory.java
@@ -0,0 +1,28 @@
+package test.subcomponent.repeat;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class RepeatedModule_ProvideOnlyUsedInParentFactory implements Factory<OnlyUsedInParent> {
+ private final RepeatedModule module;
+
+ public RepeatedModule_ProvideOnlyUsedInParentFactory(RepeatedModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public OnlyUsedInParent get() {
+ OnlyUsedInParent provided = module.provideOnlyUsedInParent();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<OnlyUsedInParent> create(RepeatedModule module) {
+ return new RepeatedModule_ProvideOnlyUsedInParentFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ProvideStringFactory.java b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ProvideStringFactory.java
new file mode 100644
index 000000000..4ebb69168
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-sources/annotations/test/subcomponent/repeat/RepeatedModule_ProvideStringFactory.java
@@ -0,0 +1,28 @@
+package test.subcomponent.repeat;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class RepeatedModule_ProvideStringFactory implements Factory<String> {
+ private final RepeatedModule module;
+
+ public RepeatedModule_ProvideStringFactory(RepeatedModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.provideString();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(RepeatedModule module) {
+ return new RepeatedModule_ProvideStringFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/functional-tests/target/generated-test-sources/test-annotations/test/AutoAnnotation_MultibindingTest_nestedWrappedKey.java b/compiler/src/it/functional-tests/target/generated-test-sources/test-annotations/test/AutoAnnotation_MultibindingTest_nestedWrappedKey.java
new file mode 100644
index 000000000..f2877eac7
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-test-sources/test-annotations/test/AutoAnnotation_MultibindingTest_nestedWrappedKey.java
@@ -0,0 +1,55 @@
+
+package test;
+
+import javax.annotation.Generated;
+
+@Generated("com.google.auto.value.processor.AutoAnnotationProcessor")
+final class AutoAnnotation_MultibindingTest_nestedWrappedKey implements TestStringKey.NestedWrappedKey {
+
+ private final Class<?> value;
+
+ AutoAnnotation_MultibindingTest_nestedWrappedKey(
+ Class<?> value) {
+ if (value == null) {
+ throw new NullPointerException("Null value");
+ }
+ this.value = value;
+ }
+
+ @Override
+ public Class<? extends TestStringKey.NestedWrappedKey> annotationType() {
+ return TestStringKey.NestedWrappedKey.class;
+ }
+
+ @Override
+ public Class<?> value() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("@test.TestStringKey.NestedWrappedKey(");
+ sb.append(value);
+ return sb.append(')').toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof TestStringKey.NestedWrappedKey) {
+ TestStringKey.NestedWrappedKey that = (TestStringKey.NestedWrappedKey) o;
+ return (value.equals(that.value()));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return
+ ((127 * 111972721) ^ (value.hashCode()));
+ // 111972721 is "value".hashCode()
+ }
+
+}
diff --git a/compiler/src/it/functional-tests/target/generated-test-sources/test-annotations/test/AutoAnnotation_MultibindingTest_testStringKey.java b/compiler/src/it/functional-tests/target/generated-test-sources/test-annotations/test/AutoAnnotation_MultibindingTest_testStringKey.java
new file mode 100644
index 000000000..37a81ddbd
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-test-sources/test-annotations/test/AutoAnnotation_MultibindingTest_testStringKey.java
@@ -0,0 +1,90 @@
+
+package test;
+
+import javax.annotation.Generated;
+
+@Generated("com.google.auto.value.processor.AutoAnnotationProcessor")
+final class AutoAnnotation_MultibindingTest_testStringKey implements TestStringKey {
+
+ private final String value;
+
+ AutoAnnotation_MultibindingTest_testStringKey(
+ String value) {
+ if (value == null) {
+ throw new NullPointerException("Null value");
+ }
+ this.value = value;
+ }
+
+ @Override
+ public Class<? extends TestStringKey> annotationType() {
+ return TestStringKey.class;
+ }
+
+ @Override
+ public String value() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("@test.TestStringKey(");
+ appendQuoted(sb, value);
+ return sb.append(')').toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof TestStringKey) {
+ TestStringKey that = (TestStringKey) o;
+ return (value.equals(that.value()));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return
+ ((127 * 111972721) ^ (value.hashCode()));
+ // 111972721 is "value".hashCode()
+ }
+
+ private static void appendQuoted(StringBuilder sb, String s) {
+ sb.append('"');
+ for (int i = 0; i < s.length(); i++) {
+ appendEscaped(sb, s.charAt(i));
+ }
+ sb.append('"');
+ }
+
+ private static void appendEscaped(StringBuilder sb, char c) {
+ switch (c) {
+ case '\\':
+ case '"':
+ case '\'':
+ sb.append('\\').append(c);
+ break;
+ case '\n':
+ sb.append("\\n");
+ break;
+ case '\r':
+ sb.append("\\r");
+ break;
+ case '\t':
+ sb.append("\\t");
+ break;
+ default:
+ if (c < 0x20) {
+ sb.append(String.format("\\%03o", (int) c));
+ } else if (c < 0x7f || Character.isLetter(c)) {
+ sb.append(c);
+ } else {
+ sb.append(String.format("\\u%04x", (int) c));
+ }
+ break;
+ }
+ }
+}
diff --git a/compiler/src/it/functional-tests/target/generated-test-sources/test-annotations/test/AutoAnnotation_MultibindingTest_testWrappedAnnotationKey.java b/compiler/src/it/functional-tests/target/generated-test-sources/test-annotations/test/AutoAnnotation_MultibindingTest_testWrappedAnnotationKey.java
new file mode 100644
index 000000000..d3e798d5d
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/generated-test-sources/test-annotations/test/AutoAnnotation_MultibindingTest_testWrappedAnnotationKey.java
@@ -0,0 +1,120 @@
+
+package test;
+
+import java.util.Arrays;
+import javax.annotation.Generated;
+
+@Generated("com.google.auto.value.processor.AutoAnnotationProcessor")
+final class AutoAnnotation_MultibindingTest_testWrappedAnnotationKey implements TestWrappedAnnotationKey {
+
+ private final TestStringKey value;
+
+ private final int[] integers;
+
+ private final TestClassKey[] annotations;
+
+ private final Class<? extends Number>[] classes;
+
+ AutoAnnotation_MultibindingTest_testWrappedAnnotationKey(
+ TestStringKey value,
+ int[] integers,
+ TestClassKey[] annotations,
+ Class<? extends Number>[] classes) {
+ if (value == null) {
+ throw new NullPointerException("Null value");
+ }
+ this.value = value;
+ if (integers == null) {
+ throw new NullPointerException("Null integers");
+ }
+ this.integers = integers.clone();
+ if (annotations == null) {
+ throw new NullPointerException("Null annotations");
+ }
+ this.annotations = annotations.clone();
+ if (classes == null) {
+ throw new NullPointerException("Null classes");
+ }
+ this.classes = classes.clone();
+ }
+
+ @Override
+ public Class<? extends TestWrappedAnnotationKey> annotationType() {
+ return TestWrappedAnnotationKey.class;
+ }
+
+ @Override
+ public TestStringKey value() {
+ return value;
+ }
+
+ @Override
+ public int[] integers() {
+ return integers.clone();
+ }
+
+ @Override
+ public TestClassKey[] annotations() {
+ return annotations.clone();
+ }
+
+ @Override
+ public Class<? extends Number>[] classes() {
+ return classes.clone();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("@test.TestWrappedAnnotationKey(");
+ sb.append("value=");
+ sb.append(value);
+ sb.append(", ");
+ sb.append("integers=");
+ sb.append(Arrays.toString(integers));
+ sb.append(", ");
+ sb.append("annotations=");
+ sb.append(Arrays.toString(annotations));
+ sb.append(", ");
+ sb.append("classes=");
+ sb.append(Arrays.toString(classes));
+ return sb.append(')').toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof TestWrappedAnnotationKey) {
+ TestWrappedAnnotationKey that = (TestWrappedAnnotationKey) o;
+ return (value.equals(that.value()))
+ && (Arrays.equals(integers,
+ (that instanceof AutoAnnotation_MultibindingTest_testWrappedAnnotationKey)
+ ? ((AutoAnnotation_MultibindingTest_testWrappedAnnotationKey) that).integers
+ : that.integers()))
+ && (Arrays.equals(annotations,
+ (that instanceof AutoAnnotation_MultibindingTest_testWrappedAnnotationKey)
+ ? ((AutoAnnotation_MultibindingTest_testWrappedAnnotationKey) that).annotations
+ : that.annotations()))
+ && (Arrays.equals(classes,
+ (that instanceof AutoAnnotation_MultibindingTest_testWrappedAnnotationKey)
+ ? ((AutoAnnotation_MultibindingTest_testWrappedAnnotationKey) that).classes
+ : that.classes()));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return
+ ((127 * 111972721) ^ (value.hashCode())) +
+ ((127 * 570074869) ^ (Arrays.hashCode(integers))) +
+ ((127 * -961709276) ^ (Arrays.hashCode(annotations))) +
+ ((127 * 853620774) ^ (Arrays.hashCode(classes)));
+ // 111972721 is "value".hashCode()
+ // 570074869 is "integers".hashCode()
+ // -961709276 is "annotations".hashCode()
+ // 853620774 is "classes".hashCode()
+ }
+
+}
diff --git a/compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest$1$1.class b/compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest$1$1.class
new file mode 100644
index 000000000..a558550c0
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest$1$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest$1$2.class b/compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest$1$2.class
new file mode 100644
index 000000000..899679986
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest$1$2.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest$1.class b/compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest$1.class
new file mode 100644
index 000000000..f6abfe204
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest$1.class
Binary files differ
diff --git a/compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest.class b/compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest.class
new file mode 100644
index 000000000..956726c91
--- /dev/null
+++ b/compiler/src/it/functional-tests/target/test-classes/test/nullables/NullabilityTest.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/pom.xml b/compiler/src/it/producers-functional-tests/pom.xml
new file mode 100644
index 000000000..bc1c3c7b5
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/pom.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2014 Google, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-parent</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+ <groupId>dagger.tests</groupId>
+ <artifactId>producers-functional-tests</artifactId>
+ <name>Producers Functional Tests</name>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-producers</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-compiler</artifactId>
+ <version>${project.version}</version>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ <configuration>
+ <source>1.7</source>
+ <target>1.7</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <failsOnError>false</failsOnError>
+ <consoleOutput>true</consoleOutput>
+ <configLocation>../../../../checkstyle.xml</configLocation>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>compile</phase>
+ <goals>
+ <goal>checkstyle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/test/DependedComponent.java b/compiler/src/it/producers-functional-tests/src/main/java/test/DependedComponent.java
new file mode 100644
index 000000000..fa392dd8e
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/test/DependedComponent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.Component;
+
+@Component(modules = DependedModule.class)
+interface DependedComponent {
+ String getGreeting();
+}
+
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/test/DependedModule.java b/compiler/src/it/producers-functional-tests/src/main/java/test/DependedModule.java
new file mode 100644
index 000000000..604107025
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/test/DependedModule.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+final class DependedModule {
+ @Provides
+ String provideGreeting() {
+ return "Hello world!";
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/test/DependedProducerModule.java b/compiler/src/it/producers-functional-tests/src/main/java/test/DependedProducerModule.java
new file mode 100644
index 000000000..ad0c792a9
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/test/DependedProducerModule.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import com.google.common.base.Ascii;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+
+import java.util.List;
+
+@ProducerModule
+final class DependedProducerModule {
+
+ @Produces
+ int produceNumberOfGreetings() {
+ return 2;
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/test/DependedProductionComponent.java b/compiler/src/it/producers-functional-tests/src/main/java/test/DependedProductionComponent.java
new file mode 100644
index 000000000..57f175812
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/test/DependedProductionComponent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProductionComponent;
+
+@ProductionComponent(modules = DependedProducerModule.class)
+interface DependedProductionComponent {
+ ListenableFuture<Integer> numGreetings();
+}
+
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/test/DependentComponent.java b/compiler/src/it/producers-functional-tests/src/main/java/test/DependentComponent.java
new file mode 100644
index 000000000..4b14f99b5
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/test/DependentComponent.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProductionComponent;
+
+import java.util.List;
+
+@ProductionComponent(
+ modules = DependentProducerModule.class,
+ dependencies = {DependedComponent.class, DependedProductionComponent.class})
+interface DependentComponent {
+ ListenableFuture<List<String>> greetings();
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/test/DependentProducerModule.java b/compiler/src/it/producers-functional-tests/src/main/java/test/DependentProducerModule.java
new file mode 100644
index 000000000..234c088d3
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/test/DependentProducerModule.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import com.google.common.base.Ascii;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+
+import java.util.List;
+
+@ProducerModule
+final class DependentProducerModule {
+ @Produces
+ ListenableFuture<List<String>> greetings(Integer numGreetings, String greeting) {
+ List<String> greetings = ImmutableList.of(
+ String.valueOf(numGreetings), greeting, Ascii.toUpperCase(greeting));
+ return Futures.immediateFuture(greetings);
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/test/MultibindingComponent.java b/compiler/src/it/producers-functional-tests/src/main/java/test/MultibindingComponent.java
new file mode 100644
index 000000000..561ad4a89
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/test/MultibindingComponent.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProductionComponent;
+import java.util.Set;
+
+@ProductionComponent(modules = MultibindingProducerModule.class)
+interface MultibindingComponent {
+ ListenableFuture<Set<String>> strs();
+ ListenableFuture<Integer> strCount();
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/test/MultibindingProducerModule.java b/compiler/src/it/producers-functional-tests/src/main/java/test/MultibindingProducerModule.java
new file mode 100644
index 000000000..4651afcc6
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/test/MultibindingProducerModule.java
@@ -0,0 +1,49 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.util.Set;
+
+import static dagger.producers.Produces.Type.SET;
+import static dagger.producers.Produces.Type.SET_VALUES;
+
+@ProducerModule
+final class MultibindingProducerModule {
+ @Produces(type = SET) ListenableFuture<String> futureStr() {
+ return Futures.immediateFuture("foo");
+ }
+
+ @Produces(type = SET) String str() {
+ return "bar";
+ }
+
+ @Produces(type = SET_VALUES) ListenableFuture<Set<String>> futureStrs() {
+ return Futures.<Set<String>>immediateFuture(ImmutableSet.of("foo1", "foo2"));
+ }
+
+ @Produces(type = SET_VALUES) Set<String> strs() {
+ return ImmutableSet.of("bar1", "bar2");
+ }
+
+ @Produces int strCount(Set<String> strs) {
+ return strs.size();
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/test/Request.java b/compiler/src/it/producers-functional-tests/src/main/java/test/Request.java
new file mode 100644
index 000000000..039d0fe55
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/test/Request.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import javax.inject.Inject;
+
+final class Request {
+ private final String name;
+
+ @Inject
+ Request() {
+ this.name = "Request";
+ }
+
+ String name() {
+ return this.name;
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/test/Response.java b/compiler/src/it/producers-functional-tests/src/main/java/test/Response.java
new file mode 100644
index 000000000..7a46e5b0e
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/test/Response.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+final class Response {
+ private final String data;
+
+ Response(String data) {
+ this.data = data;
+ }
+
+ String data() {
+ return this.data;
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/test/ResponseModule.java b/compiler/src/it/producers-functional-tests/src/main/java/test/ResponseModule.java
new file mode 100644
index 000000000..4a83c6c83
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/test/ResponseModule.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+final class ResponseModule {
+ @Provides
+ static int requestNumber() {
+ return 5;
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/test/ResponseProducerModule.java b/compiler/src/it/producers-functional-tests/src/main/java/test/ResponseProducerModule.java
new file mode 100644
index 000000000..f3ad22939
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/test/ResponseProducerModule.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+
+@ProducerModule(includes = ResponseModule.class)
+final class ResponseProducerModule {
+ @Produces
+ static ListenableFuture<String> greeting() {
+ return Futures.immediateFuture("Hello");
+ }
+
+ @Produces
+ static Response response(String greeting, Request request, int requestNumber) {
+ return new Response(String.format("%s, %s #%d!", greeting, request.name(), requestNumber));
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/test/SimpleComponent.java b/compiler/src/it/producers-functional-tests/src/main/java/test/SimpleComponent.java
new file mode 100644
index 000000000..583cd50f0
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/test/SimpleComponent.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProductionComponent;
+
+@ProductionComponent(modules = ResponseProducerModule.class)
+interface SimpleComponent {
+ ListenableFuture<Response> response();
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/test/SimpleProducerModule.java b/compiler/src/it/producers-functional-tests/src/main/java/test/SimpleProducerModule.java
new file mode 100644
index 000000000..98f3cfb56
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/test/SimpleProducerModule.java
@@ -0,0 +1,219 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.io.IOException;
+import java.util.Set;
+import javax.inject.Provider;
+import javax.inject.Qualifier;
+
+import static dagger.producers.Produces.Type.SET;
+import static dagger.producers.Produces.Type.SET_VALUES;
+
+/**
+ * A module that contains various signatures of produces methods. This is not used in any
+ * components.
+ */
+@ProducerModule
+final class SimpleProducerModule {
+ @Qualifier @interface Qual {
+ int value();
+ }
+
+ // Unique bindings.
+
+ @Produces
+ @Qual(-2)
+ static ListenableFuture<String> throwingProducer() {
+ throw new RuntimeException("monkey");
+ }
+
+ @Produces
+ @Qual(-1)
+ static ListenableFuture<String> settableFutureStr(SettableFuture<String> future) {
+ return future;
+ }
+
+ @Produces
+ @Qual(0)
+ static String str() {
+ return "str";
+ }
+
+ @Produces
+ @Qual(1)
+ static ListenableFuture<String> futureStr() {
+ return Futures.immediateFuture("future str");
+ }
+
+ @Produces
+ @Qual(2)
+ static String strWithArg(int i) {
+ return "str with arg";
+ }
+
+ @Produces
+ @Qual(3)
+ static ListenableFuture<String> futureStrWithArg(int i) {
+ return Futures.immediateFuture("future str with arg");
+ }
+
+ @Produces
+ @Qual(4)
+ static String strThrowingException() throws IOException {
+ return "str throwing exception";
+ }
+
+ @Produces
+ @Qual(5)
+ static ListenableFuture<String> futureStrThrowingException() throws IOException {
+ return Futures.immediateFuture("future str throwing exception");
+ }
+
+ @Produces
+ @Qual(6)
+ static String strWithArgThrowingException(int i) throws IOException {
+ return "str with arg throwing exception";
+ }
+
+ @Produces
+ @Qual(7)
+ static ListenableFuture<String> futureStrWithArgThrowingException(int i) throws IOException {
+ return Futures.immediateFuture("future str with arg throwing exception");
+ }
+
+ @Produces
+ @Qual(8)
+ static String strWithArgs(int i, Produced<Double> b, Producer<Object> c, Provider<Boolean> d) {
+ return "str with args";
+ }
+
+ @Produces
+ @Qual(9)
+ static String strWithArgsThrowingException(
+ int i, Produced<Double> b, Producer<Object> c, Provider<Boolean> d) throws IOException {
+ return "str with args throwing exception";
+ }
+
+ @Produces
+ @Qual(10)
+ static ListenableFuture<String> futureStrWithArgs(
+ int i, Produced<Double> b, Producer<Object> c, Provider<Boolean> d) {
+ return Futures.immediateFuture("future str with args");
+ }
+
+ @Produces
+ @Qual(11)
+ static ListenableFuture<String> futureStrWithArgsThrowingException(
+ int i, Produced<Double> b, Producer<Object> c, Provider<Boolean> d) throws IOException {
+ return Futures.immediateFuture("str with args throwing exception");
+ }
+
+ // Set bindings.
+
+ @Produces(type = SET)
+ static String setOfStrElement() {
+ return "set of str element";
+ }
+
+ @Produces(type = SET)
+ static String setOfStrElementThrowingException() throws IOException {
+ return "set of str element throwing exception";
+ }
+
+ @Produces(type = SET)
+ static ListenableFuture<String> setOfStrFutureElement() {
+ return Futures.immediateFuture("set of str element");
+ }
+
+ @Produces(type = SET)
+ static ListenableFuture<String> setOfStrFutureElementThrowingException() throws IOException {
+ return Futures.immediateFuture("set of str element throwing exception");
+ }
+
+ @Produces(type = SET)
+ static String setOfStrElementWithArg(int i) {
+ return "set of str element with arg";
+ }
+
+ @Produces(type = SET)
+ static String setOfStrElementWithArgThrowingException(int i) throws IOException {
+ return "set of str element with arg throwing exception";
+ }
+
+ @Produces(type = SET)
+ static ListenableFuture<String> setOfStrFutureElementWithArg(int i) {
+ return Futures.immediateFuture("set of str element with arg");
+ }
+
+ @Produces(type = SET)
+ static ListenableFuture<String> setOfStrFutureElementWithArgThrowingException(int i)
+ throws IOException {
+ return Futures.immediateFuture("set of str element with arg throwing exception");
+ }
+
+ @Produces(type = SET_VALUES)
+ static Set<String> setOfStrValues() {
+ return ImmutableSet.of("set of str 1", "set of str 2");
+ }
+
+ @Produces(type = SET_VALUES)
+ static Set<String> setOfStrValuesThrowingException() throws IOException {
+ return ImmutableSet.of("set of str 1", "set of str 2 throwing exception");
+ }
+
+ @Produces(type = SET_VALUES)
+ static ListenableFuture<Set<String>> setOfStrFutureValues() {
+ return Futures.<Set<String>>immediateFuture(ImmutableSet.of("set of str 1", "set of str 2"));
+ }
+
+ @Produces(type = SET_VALUES)
+ static ListenableFuture<Set<String>> setOfStrFutureValuesThrowingException() throws IOException {
+ return Futures.<Set<String>>immediateFuture(
+ ImmutableSet.of("set of str 1", "set of str 2 throwing exception"));
+ }
+
+ @Produces(type = SET_VALUES)
+ static Set<String> setOfStrValuesWithArg(int i) {
+ return ImmutableSet.of("set of str with arg 1", "set of str with arg 2");
+ }
+
+ @Produces(type = SET_VALUES)
+ static Set<String> setOfStrValuesWithArgThrowingException(int i) throws IOException {
+ return ImmutableSet.of("set of str with arg 1", "set of str with arg 2 throwing exception");
+ }
+
+ @Produces(type = SET_VALUES)
+ static ListenableFuture<Set<String>> setOfStrFutureValuesWithArg(int i) {
+ return Futures.<Set<String>>immediateFuture(
+ ImmutableSet.of("set of str with arg 1", "set of str with arg 2"));
+ }
+
+ @Produces(type = SET_VALUES)
+ static ListenableFuture<Set<String>> setOfStrFutureValuesWithArgThrowingException(int i)
+ throws IOException {
+ return Futures.<Set<String>>immediateFuture(
+ ImmutableSet.of("set of str with arg 1", "set of str with arg 2 throwing exception"));
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/test/java/test/DependentTest.java b/compiler/src/it/producers-functional-tests/src/test/java/test/DependentTest.java
new file mode 100644
index 000000000..15aa48165
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/test/java/test/DependentTest.java
@@ -0,0 +1,74 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class DependentTest {
+ @Test public void dependentComponent() throws Exception {
+ DependentComponent dependentComponent = DaggerDependentComponent
+ .builder()
+ .dependedProductionComponent(DaggerDependedProductionComponent.builder()
+ .executor(MoreExecutors.directExecutor())
+ .build())
+ .dependedComponent(DaggerDependedComponent.create())
+ .executor(MoreExecutors.directExecutor())
+ .build();
+ assertThat(dependentComponent).isNotNull();
+ assertThat(dependentComponent.greetings().get()).containsExactly(
+ "2", "Hello world!", "HELLO WORLD!");
+ }
+
+ @Test public void reuseBuilderWithDependentComponent() throws Exception {
+ DaggerDependentComponent.Builder dependentComponentBuilder = DaggerDependentComponent
+ .builder()
+ .executor(MoreExecutors.directExecutor());
+
+ DependentComponent componentUsingComponents = dependentComponentBuilder
+ .dependedProductionComponent(DaggerDependedProductionComponent.builder()
+ .executor(MoreExecutors.directExecutor())
+ .build())
+ .dependedComponent(DaggerDependedComponent.create())
+ .build();
+
+ DependentComponent componentUsingJavaImpls = dependentComponentBuilder
+ .dependedProductionComponent(new DependedProductionComponent() {
+ @Override public ListenableFuture<Integer> numGreetings() {
+ return Futures.immediateFuture(3);
+ }
+ })
+ .dependedComponent(new DependedComponent() {
+ @Override public String getGreeting() {
+ return "Goodbye world!";
+ }
+ })
+ .build();
+
+ assertThat(componentUsingJavaImpls.greetings().get()).containsExactly(
+ "3", "Goodbye world!", "GOODBYE WORLD!");
+ assertThat(componentUsingComponents.greetings().get()).containsExactly(
+ "2", "Hello world!", "HELLO WORLD!");
+
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/test/java/test/MultibindingTest.java b/compiler/src/it/producers-functional-tests/src/test/java/test/MultibindingTest.java
new file mode 100644
index 000000000..20c86dc52
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/test/java/test/MultibindingTest.java
@@ -0,0 +1,35 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import com.google.common.util.concurrent.MoreExecutors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class MultibindingTest {
+ @Test public void multibinding() throws Exception {
+ MultibindingComponent multibindingComponent = DaggerMultibindingComponent.builder()
+ .executor(MoreExecutors.directExecutor())
+ .build();
+ assertThat(multibindingComponent.strs().get())
+ .containsExactly("foo", "foo1", "foo2", "bar", "bar1", "bar2");
+ assertThat(multibindingComponent.strCount().get()).isEqualTo(6);
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/test/java/test/ProducerFactoryTest.java b/compiler/src/it/producers-functional-tests/src/test/java/test/ProducerFactoryTest.java
new file mode 100644
index 000000000..4c347318a
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/test/java/test/ProducerFactoryTest.java
@@ -0,0 +1,195 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.SettableFuture;
+
+import dagger.producers.Producer;
+import dagger.producers.monitoring.ProducerMonitor;
+import dagger.producers.monitoring.ProducerToken;
+import dagger.producers.monitoring.ProductionComponentMonitor;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.ExecutionException;
+
+@RunWith(JUnit4.class)
+public class ProducerFactoryTest {
+ @Mock private ProductionComponentMonitor componentMonitor;
+ @Mock private ProducerMonitor monitor;
+
+ @Before
+ public void setUpMocks() {
+ MockitoAnnotations.initMocks(this);
+ when(componentMonitor.producerMonitorFor(any(ProducerToken.class))).thenReturn(monitor);
+ }
+
+ @Test
+ public void noArgMethod() throws Exception {
+ ProducerToken token = ProducerToken.create(SimpleProducerModule_StrFactory.class);
+ Producer<String> producer =
+ new SimpleProducerModule_StrFactory(
+ componentMonitor, MoreExecutors.directExecutor());
+ assertThat(producer.get().get()).isEqualTo("str");
+ InOrder order = inOrder(componentMonitor, monitor);
+ order.verify(componentMonitor).producerMonitorFor(token);
+ order.verify(monitor).methodStarting();
+ order.verify(monitor).methodFinished();
+ order.verify(monitor).succeeded("str");
+ order.verifyNoMoreInteractions();
+ }
+
+ @Test public void singleArgMethod() throws Exception {
+ SettableFuture<Integer> intFuture = SettableFuture.create();
+ Producer<Integer> intProducer = producerOfFuture(intFuture);
+ Producer<String> producer =
+ new SimpleProducerModule_StrWithArgFactory(
+ componentMonitor, MoreExecutors.directExecutor(), intProducer);
+ assertThat(producer.get().isDone()).isFalse();
+ intFuture.set(42);
+ assertThat(producer.get().get()).isEqualTo("str with arg");
+ }
+
+ @Test
+ public void successMonitor() throws Exception {
+ ProducerToken token = ProducerToken.create(SimpleProducerModule_SettableFutureStrFactory.class);
+
+ SettableFuture<String> strFuture = SettableFuture.create();
+ SettableFuture<SettableFuture<String>> strFutureFuture = SettableFuture.create();
+ Producer<SettableFuture<String>> strFutureProducer = producerOfFuture(strFutureFuture);
+ Producer<String> producer =
+ new SimpleProducerModule_SettableFutureStrFactory(
+ componentMonitor, MoreExecutors.directExecutor(), strFutureProducer);
+ assertThat(producer.get().isDone()).isFalse();
+
+ InOrder order = inOrder(componentMonitor, monitor);
+ order.verify(componentMonitor).producerMonitorFor(token);
+
+ strFutureFuture.set(strFuture);
+ order.verify(monitor).methodStarting();
+ order.verify(monitor).methodFinished();
+ assertThat(producer.get().isDone()).isFalse();
+
+ strFuture.set("monkey");
+ assertThat(producer.get().get()).isEqualTo("monkey");
+ order.verify(monitor).succeeded("monkey");
+
+ order.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void failureMonitor() throws Exception {
+ ProducerToken token = ProducerToken.create(SimpleProducerModule_SettableFutureStrFactory.class);
+
+ SettableFuture<String> strFuture = SettableFuture.create();
+ SettableFuture<SettableFuture<String>> strFutureFuture = SettableFuture.create();
+ Producer<SettableFuture<String>> strFutureProducer = producerOfFuture(strFutureFuture);
+ Producer<String> producer =
+ new SimpleProducerModule_SettableFutureStrFactory(
+ componentMonitor, MoreExecutors.directExecutor(), strFutureProducer);
+ assertThat(producer.get().isDone()).isFalse();
+
+ InOrder order = inOrder(componentMonitor, monitor);
+ order.verify(componentMonitor).producerMonitorFor(token);
+
+ strFutureFuture.set(strFuture);
+ order.verify(monitor).methodStarting();
+ order.verify(monitor).methodFinished();
+ assertThat(producer.get().isDone()).isFalse();
+
+ Throwable t = new RuntimeException("monkey");
+ strFuture.setException(t);
+ try {
+ producer.get().get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).isSameAs(t);
+ order.verify(monitor).failed(t);
+ }
+
+ order.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void failureMonitorDueToThrowingProducer() throws Exception {
+ ProducerToken token = ProducerToken.create(SimpleProducerModule_ThrowingProducerFactory.class);
+
+ Producer<String> producer =
+ new SimpleProducerModule_ThrowingProducerFactory(
+ componentMonitor, MoreExecutors.directExecutor());
+ assertThat(producer.get().isDone()).isTrue();
+
+ InOrder order = inOrder(componentMonitor, monitor);
+ order.verify(componentMonitor).producerMonitorFor(token);
+
+ order.verify(monitor).methodStarting();
+ order.verify(monitor).methodFinished();
+
+ try {
+ producer.get().get();
+ fail();
+ } catch (ExecutionException e) {
+ order.verify(monitor).failed(e.getCause());
+ }
+
+ order.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void nullComponentMonitor() throws Exception {
+ Producer<String> producer =
+ new SimpleProducerModule_StrFactory(null, MoreExecutors.directExecutor());
+ assertThat(producer.get().get()).isEqualTo("str");
+ verifyZeroInteractions(componentMonitor, monitor);
+ }
+
+ @Test
+ public void nullMonitor() throws Exception {
+ when(componentMonitor.producerMonitorFor(any(ProducerToken.class))).thenReturn(null);
+
+ ProducerToken token = ProducerToken.create(SimpleProducerModule_StrFactory.class);
+ Producer<String> producer =
+ new SimpleProducerModule_StrFactory(
+ componentMonitor, MoreExecutors.directExecutor());
+ assertThat(producer.get().get()).isEqualTo("str");
+ verify(componentMonitor).producerMonitorFor(token);
+ verifyZeroInteractions(monitor);
+ }
+
+ private static <T> Producer<T> producerOfFuture(final ListenableFuture<T> future) {
+ return new Producer<T>() {
+ @Override public ListenableFuture<T> get() {
+ return future;
+ }
+ };
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/test/java/test/SimpleTest.java b/compiler/src/it/producers-functional-tests/src/test/java/test/SimpleTest.java
new file mode 100644
index 000000000..e6e73961c
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/test/java/test/SimpleTest.java
@@ -0,0 +1,35 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 test;
+
+import com.google.common.util.concurrent.MoreExecutors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class SimpleTest {
+ @Test public void testSimpleComponent() throws Exception {
+ SimpleComponent simpleComponent = DaggerSimpleComponent
+ .builder()
+ .executor(MoreExecutors.directExecutor())
+ .build();
+ assertThat(simpleComponent).isNotNull();
+ assertThat(simpleComponent.response().get().data()).isEqualTo("Hello, Request #5!");
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedComponent$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedComponent$1.class
new file mode 100644
index 000000000..a91fe82ec
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedComponent$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedComponent$Builder.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedComponent$Builder.class
new file mode 100644
index 000000000..eb9ca5814
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedComponent.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedComponent.class
new file mode 100644
index 000000000..1f7742d1d
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedComponent.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedProductionComponent$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedProductionComponent$1.class
new file mode 100644
index 000000000..410d94316
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedProductionComponent$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedProductionComponent$Builder.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedProductionComponent$Builder.class
new file mode 100644
index 000000000..2513bc09b
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedProductionComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedProductionComponent.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedProductionComponent.class
new file mode 100644
index 000000000..acf8d8abf
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependedProductionComponent.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent$1.class
new file mode 100644
index 000000000..63265be68
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent$2.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent$2.class
new file mode 100644
index 000000000..6ed580933
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent$2.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent$Builder.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent$Builder.class
new file mode 100644
index 000000000..e86528462
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent.class
new file mode 100644
index 000000000..a02fb5594
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerDependentComponent.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerMultibindingComponent$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerMultibindingComponent$1.class
new file mode 100644
index 000000000..ebdc3abfa
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerMultibindingComponent$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerMultibindingComponent$Builder.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerMultibindingComponent$Builder.class
new file mode 100644
index 000000000..0d7425a91
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerMultibindingComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerMultibindingComponent.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerMultibindingComponent.class
new file mode 100644
index 000000000..cbb2e35e0
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerMultibindingComponent.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerSimpleComponent$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerSimpleComponent$1.class
new file mode 100644
index 000000000..e55138d76
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerSimpleComponent$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerSimpleComponent$Builder.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerSimpleComponent$Builder.class
new file mode 100644
index 000000000..56538412e
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerSimpleComponent$Builder.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DaggerSimpleComponent.class b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerSimpleComponent.class
new file mode 100644
index 000000000..8f486a6ed
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DaggerSimpleComponent.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DependedComponent.class b/compiler/src/it/producers-functional-tests/target/classes/test/DependedComponent.class
new file mode 100644
index 000000000..6b785c0ff
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DependedComponent.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DependedModule.class b/compiler/src/it/producers-functional-tests/target/classes/test/DependedModule.class
new file mode 100644
index 000000000..6c67e1d7d
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DependedModule.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DependedModule_ProvideGreetingFactory.class b/compiler/src/it/producers-functional-tests/target/classes/test/DependedModule_ProvideGreetingFactory.class
new file mode 100644
index 000000000..d9a8fc543
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DependedModule_ProvideGreetingFactory.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DependedProducerModule.class b/compiler/src/it/producers-functional-tests/target/classes/test/DependedProducerModule.class
new file mode 100644
index 000000000..589230974
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DependedProducerModule.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DependedProducerModule_ProduceNumberOfGreetingsFactory$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/DependedProducerModule_ProduceNumberOfGreetingsFactory$1.class
new file mode 100644
index 000000000..f1b7f66ba
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DependedProducerModule_ProduceNumberOfGreetingsFactory$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DependedProducerModule_ProduceNumberOfGreetingsFactory.class b/compiler/src/it/producers-functional-tests/target/classes/test/DependedProducerModule_ProduceNumberOfGreetingsFactory.class
new file mode 100644
index 000000000..0d6a5b29b
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DependedProducerModule_ProduceNumberOfGreetingsFactory.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DependedProductionComponent.class b/compiler/src/it/producers-functional-tests/target/classes/test/DependedProductionComponent.class
new file mode 100644
index 000000000..8235aae01
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DependedProductionComponent.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DependentComponent.class b/compiler/src/it/producers-functional-tests/target/classes/test/DependentComponent.class
new file mode 100644
index 000000000..a343eb341
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DependentComponent.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DependentProducerModule.class b/compiler/src/it/producers-functional-tests/target/classes/test/DependentProducerModule.class
new file mode 100644
index 000000000..88aa71235
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DependentProducerModule.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DependentProducerModule_GreetingsFactory$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/DependentProducerModule_GreetingsFactory$1.class
new file mode 100644
index 000000000..daa203c65
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DependentProducerModule_GreetingsFactory$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/DependentProducerModule_GreetingsFactory.class b/compiler/src/it/producers-functional-tests/target/classes/test/DependentProducerModule_GreetingsFactory.class
new file mode 100644
index 000000000..81062ffc6
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/DependentProducerModule_GreetingsFactory.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingComponent.class b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingComponent.class
new file mode 100644
index 000000000..029eb4f29
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingComponent.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule.class b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule.class
new file mode 100644
index 000000000..969082eb1
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrFactory$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrFactory$1.class
new file mode 100644
index 000000000..76795987d
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrFactory$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrFactory.class b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrFactory.class
new file mode 100644
index 000000000..9d7d69f78
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrFactory.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrsFactory$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrsFactory$1.class
new file mode 100644
index 000000000..b39e8a870
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrsFactory$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrsFactory.class b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrsFactory.class
new file mode 100644
index 000000000..d55182cd7
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_FutureStrsFactory.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrCountFactory$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrCountFactory$1.class
new file mode 100644
index 000000000..82877e51c
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrCountFactory$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrCountFactory.class b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrCountFactory.class
new file mode 100644
index 000000000..1d8769756
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrCountFactory.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrFactory$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrFactory$1.class
new file mode 100644
index 000000000..ac9e2935e
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrFactory$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrFactory.class b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrFactory.class
new file mode 100644
index 000000000..d1ff35e3d
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrFactory.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrsFactory$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrsFactory$1.class
new file mode 100644
index 000000000..a68db6060
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrsFactory$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrsFactory.class b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrsFactory.class
new file mode 100644
index 000000000..47c2f6320
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/MultibindingProducerModule_StrsFactory.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/Request.class b/compiler/src/it/producers-functional-tests/target/classes/test/Request.class
new file mode 100644
index 000000000..ff235acfd
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/Request.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/Request_Factory.class b/compiler/src/it/producers-functional-tests/target/classes/test/Request_Factory.class
new file mode 100644
index 000000000..cca4b9bd2
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/Request_Factory.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/Response.class b/compiler/src/it/producers-functional-tests/target/classes/test/Response.class
new file mode 100644
index 000000000..230c7e232
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/Response.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule.class b/compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule.class
new file mode 100644
index 000000000..72bf75b4c
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_GreetingFactory$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_GreetingFactory$1.class
new file mode 100644
index 000000000..9ced7811b
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_GreetingFactory$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_GreetingFactory.class b/compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_GreetingFactory.class
new file mode 100644
index 000000000..958e2953c
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_GreetingFactory.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_ResponseFactory$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_ResponseFactory$1.class
new file mode 100644
index 000000000..18d2dd382
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_ResponseFactory$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_ResponseFactory.class b/compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_ResponseFactory.class
new file mode 100644
index 000000000..495d4a790
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/ResponseProducerModule_ResponseFactory.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/SimpleComponent.class b/compiler/src/it/producers-functional-tests/target/classes/test/SimpleComponent.class
new file mode 100644
index 000000000..0bb28fee5
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/SimpleComponent.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule.class b/compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule.class
new file mode 100644
index 000000000..37cb83eb2
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_LenFactory$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_LenFactory$1.class
new file mode 100644
index 000000000..fe2162c7c
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_LenFactory$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_LenFactory.class b/compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_LenFactory.class
new file mode 100644
index 000000000..225191592
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_LenFactory.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_StrFactory$1.class b/compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_StrFactory$1.class
new file mode 100644
index 000000000..77dc845fa
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_StrFactory$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_StrFactory.class b/compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_StrFactory.class
new file mode 100644
index 000000000..dfd5c8154
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/classes/test/SimpleProducerModule_StrFactory.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerDependedComponent.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerDependedComponent.java
new file mode 100644
index 000000000..7bafd2699
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerDependedComponent.java
@@ -0,0 +1,54 @@
+package test;
+
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerDependedComponent implements DependedComponent {
+ private Provider<String> provideGreetingProvider;
+
+ private DaggerDependedComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static DependedComponent create() {
+ return builder().build();
+ }
+
+ private void initialize(final Builder builder) {
+ this.provideGreetingProvider = DependedModule_ProvideGreetingFactory.create(builder.dependedModule);
+ }
+
+ @Override
+ public String getGreeting() {
+ return provideGreetingProvider.get();
+ }
+
+ public static final class Builder {
+ private DependedModule dependedModule;
+
+ private Builder() {
+ }
+
+ public DependedComponent build() {
+ if (dependedModule == null) {
+ this.dependedModule = new DependedModule();
+ }
+ return new DaggerDependedComponent(this);
+ }
+
+ public Builder dependedModule(DependedModule dependedModule) {
+ if (dependedModule == null) {
+ throw new NullPointerException("dependedModule");
+ }
+ this.dependedModule = dependedModule;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerDependedProductionComponent.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerDependedProductionComponent.java
new file mode 100644
index 000000000..ca5d48b8e
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerDependedProductionComponent.java
@@ -0,0 +1,64 @@
+package test;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Producer;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerDependedProductionComponent implements DependedProductionComponent {
+ private Producer<Integer> produceNumberOfGreetingsProducer;
+
+ private DaggerDependedProductionComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private void initialize(final Builder builder) {
+ this.produceNumberOfGreetingsProducer = new DependedProducerModule_ProduceNumberOfGreetingsFactory(builder.dependedProducerModule, builder.executor);
+ }
+
+ @Override
+ public ListenableFuture<Integer> numGreetings() {
+ return produceNumberOfGreetingsProducer.get();
+ }
+
+ public static final class Builder {
+ private DependedProducerModule dependedProducerModule;
+ private Executor executor;
+
+ private Builder() {
+ }
+
+ public DependedProductionComponent build() {
+ if (dependedProducerModule == null) {
+ this.dependedProducerModule = new DependedProducerModule();
+ }
+ if (executor == null) {
+ throw new IllegalStateException("executor must be set");
+ }
+ return new DaggerDependedProductionComponent(this);
+ }
+
+ public Builder dependedProducerModule(DependedProducerModule dependedProducerModule) {
+ if (dependedProducerModule == null) {
+ throw new NullPointerException("dependedProducerModule");
+ }
+ this.dependedProducerModule = dependedProducerModule;
+ return this;
+ }
+
+ public Builder executor(Executor executor) {
+ if (executor == null) {
+ throw new NullPointerException("executor");
+ }
+ this.executor = executor;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerDependentComponent.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerDependentComponent.java
new file mode 100644
index 000000000..22f46a0bf
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerDependentComponent.java
@@ -0,0 +1,110 @@
+package test;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.internal.Factory;
+import dagger.producers.Producer;
+import dagger.producers.internal.Producers;
+import java.util.List;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerDependentComponent implements DependentComponent {
+ private Producer<Integer> numGreetingsProducer;
+ private Provider<String> getGreetingProvider;
+ private Producer<List<String>> greetingsProducer;
+
+ private DaggerDependentComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private void initialize(final Builder builder) {
+ this.numGreetingsProducer = new Producer<Integer>() {
+ private final DependedProductionComponent dependedProductionComponent = builder.dependedProductionComponent;
+ @Override public ListenableFuture<Integer> get() {
+ return dependedProductionComponent.numGreetings();
+ }
+ };
+ this.getGreetingProvider = new Factory<String>() {
+ private final DependedComponent dependedComponent = builder.dependedComponent;
+ @Override public String get() {
+ String provided = dependedComponent.getGreeting();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable component method");
+ }
+ return provided;
+ }
+ };
+ this.greetingsProducer = new DependentProducerModule_GreetingsFactory(builder.dependentProducerModule, builder.executor, numGreetingsProducer, Producers.producerFromProvider(getGreetingProvider));
+ }
+
+ @Override
+ public ListenableFuture<List<String>> greetings() {
+ return greetingsProducer.get();
+ }
+
+ public static final class Builder {
+ private DependentProducerModule dependentProducerModule;
+ private DependedComponent dependedComponent;
+ private DependedProductionComponent dependedProductionComponent;
+ private Executor executor;
+
+ private Builder() {
+ }
+
+ public DependentComponent build() {
+ if (dependentProducerModule == null) {
+ this.dependentProducerModule = new DependentProducerModule();
+ }
+ if (dependedComponent == null) {
+ throw new IllegalStateException("dependedComponent must be set");
+ }
+ if (dependedProductionComponent == null) {
+ throw new IllegalStateException("dependedProductionComponent must be set");
+ }
+ if (executor == null) {
+ throw new IllegalStateException("executor must be set");
+ }
+ return new DaggerDependentComponent(this);
+ }
+
+ public Builder dependentProducerModule(DependentProducerModule dependentProducerModule) {
+ if (dependentProducerModule == null) {
+ throw new NullPointerException("dependentProducerModule");
+ }
+ this.dependentProducerModule = dependentProducerModule;
+ return this;
+ }
+
+ public Builder dependedComponent(DependedComponent dependedComponent) {
+ if (dependedComponent == null) {
+ throw new NullPointerException("dependedComponent");
+ }
+ this.dependedComponent = dependedComponent;
+ return this;
+ }
+
+ public Builder dependedProductionComponent(DependedProductionComponent dependedProductionComponent) {
+ if (dependedProductionComponent == null) {
+ throw new NullPointerException("dependedProductionComponent");
+ }
+ this.dependedProductionComponent = dependedProductionComponent;
+ return this;
+ }
+
+ public Builder executor(Executor executor) {
+ if (executor == null) {
+ throw new NullPointerException("executor");
+ }
+ this.executor = executor;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerMultibindingComponent.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerMultibindingComponent.java
new file mode 100644
index 000000000..fe03735e2
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerMultibindingComponent.java
@@ -0,0 +1,81 @@
+package test;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Producer;
+import dagger.producers.internal.SetProducer;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerMultibindingComponent implements MultibindingComponent {
+ private Producer<Set<String>> setOfStringContribution1Producer;
+ private Producer<Set<String>> setOfStringContribution2Producer;
+ private Producer<Set<String>> setOfStringContribution3Producer;
+ private Producer<Set<String>> setOfStringContribution4Producer;
+ private Producer<Set<String>> setOfStringProducer;
+ private Producer<Integer> strCountProducer;
+
+ private DaggerMultibindingComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private void initialize(final Builder builder) {
+ this.setOfStringContribution1Producer = new MultibindingProducerModule_FutureStrFactory(builder.multibindingProducerModule, builder.executor);
+ this.setOfStringContribution2Producer = new MultibindingProducerModule_StrFactory(builder.multibindingProducerModule, builder.executor);
+ this.setOfStringContribution3Producer = new MultibindingProducerModule_FutureStrsFactory(builder.multibindingProducerModule, builder.executor);
+ this.setOfStringContribution4Producer = new MultibindingProducerModule_StrsFactory(builder.multibindingProducerModule, builder.executor);
+ this.setOfStringProducer = SetProducer.create(setOfStringContribution1Producer, setOfStringContribution2Producer, setOfStringContribution3Producer, setOfStringContribution4Producer);
+ this.strCountProducer = new MultibindingProducerModule_StrCountFactory(builder.multibindingProducerModule, builder.executor, setOfStringProducer);
+ }
+
+ @Override
+ public ListenableFuture<Set<String>> strs() {
+ return setOfStringProducer.get();
+ }
+
+ @Override
+ public ListenableFuture<Integer> strCount() {
+ return strCountProducer.get();
+ }
+
+ public static final class Builder {
+ private MultibindingProducerModule multibindingProducerModule;
+ private Executor executor;
+
+ private Builder() {
+ }
+
+ public MultibindingComponent build() {
+ if (multibindingProducerModule == null) {
+ this.multibindingProducerModule = new MultibindingProducerModule();
+ }
+ if (executor == null) {
+ throw new IllegalStateException("executor must be set");
+ }
+ return new DaggerMultibindingComponent(this);
+ }
+
+ public Builder multibindingProducerModule(MultibindingProducerModule multibindingProducerModule) {
+ if (multibindingProducerModule == null) {
+ throw new NullPointerException("multibindingProducerModule");
+ }
+ this.multibindingProducerModule = multibindingProducerModule;
+ return this;
+ }
+
+ public Builder executor(Executor executor) {
+ if (executor == null) {
+ throw new NullPointerException("executor");
+ }
+ this.executor = executor;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerSimpleComponent.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerSimpleComponent.java
new file mode 100644
index 000000000..1a5f86f65
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DaggerSimpleComponent.java
@@ -0,0 +1,67 @@
+package test;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Producer;
+import dagger.producers.internal.Producers;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DaggerSimpleComponent implements SimpleComponent {
+ private Producer<String> greetingProducer;
+ private Producer<Response> responseProducer;
+
+ private DaggerSimpleComponent(Builder builder) {
+ assert builder != null;
+ initialize(builder);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private void initialize(final Builder builder) {
+ this.greetingProducer = new ResponseProducerModule_GreetingFactory(builder.responseProducerModule, builder.executor);
+ this.responseProducer = new ResponseProducerModule_ResponseFactory(builder.responseProducerModule, builder.executor, greetingProducer, Producers.producerFromProvider(Request_Factory.create()));
+ }
+
+ @Override
+ public ListenableFuture<Response> response() {
+ return responseProducer.get();
+ }
+
+ public static final class Builder {
+ private ResponseProducerModule responseProducerModule;
+ private Executor executor;
+
+ private Builder() {
+ }
+
+ public SimpleComponent build() {
+ if (responseProducerModule == null) {
+ this.responseProducerModule = new ResponseProducerModule();
+ }
+ if (executor == null) {
+ throw new IllegalStateException("executor must be set");
+ }
+ return new DaggerSimpleComponent(this);
+ }
+
+ public Builder responseProducerModule(ResponseProducerModule responseProducerModule) {
+ if (responseProducerModule == null) {
+ throw new NullPointerException("responseProducerModule");
+ }
+ this.responseProducerModule = responseProducerModule;
+ return this;
+ }
+
+ public Builder executor(Executor executor) {
+ if (executor == null) {
+ throw new NullPointerException("executor");
+ }
+ this.executor = executor;
+ return this;
+ }
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DependedModule_ProvideGreetingFactory.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DependedModule_ProvideGreetingFactory.java
new file mode 100644
index 000000000..ef14f86af
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DependedModule_ProvideGreetingFactory.java
@@ -0,0 +1,28 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DependedModule_ProvideGreetingFactory implements Factory<String> {
+ private final DependedModule module;
+
+ public DependedModule_ProvideGreetingFactory(DependedModule module) {
+ assert module != null;
+ this.module = module;
+ }
+
+ @Override
+ public String get() {
+ String provided = module.provideGreeting();
+ if (provided == null) {
+ throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
+ }
+ return provided;
+ }
+
+ public static Factory<String> create(DependedModule module) {
+ return new DependedModule_ProvideGreetingFactory(module);
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DependedProducerModule_ProduceNumberOfGreetingsFactory.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DependedProducerModule_ProduceNumberOfGreetingsFactory.java
new file mode 100644
index 000000000..4bee1017b
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DependedProducerModule_ProduceNumberOfGreetingsFactory.java
@@ -0,0 +1,32 @@
+package test;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.internal.AbstractProducer;
+import dagger.producers.internal.Producers;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DependedProducerModule_ProduceNumberOfGreetingsFactory extends AbstractProducer<Integer> {
+ private final DependedProducerModule module;
+ private final Executor executor;
+
+ public DependedProducerModule_ProduceNumberOfGreetingsFactory(DependedProducerModule module, Executor executor) {
+ assert module != null;
+ this.module = module;
+ assert executor != null;
+ this.executor = executor;
+ }
+
+ @Override
+ protected ListenableFuture<Integer> compute() {
+ ListenableFuture<Integer> future = Producers.submitToExecutor(new Callable<Integer>() {
+ @Override public Integer call() {
+ return module.produceNumberOfGreetings();
+ }
+ }, executor);
+ return future;
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DependentProducerModule_GreetingsFactory.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DependentProducerModule_GreetingsFactory.java
new file mode 100644
index 000000000..ba4887249
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/DependentProducerModule_GreetingsFactory.java
@@ -0,0 +1,42 @@
+package test;
+
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Producer;
+import dagger.producers.internal.AbstractProducer;
+import java.util.List;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class DependentProducerModule_GreetingsFactory extends AbstractProducer<List<String>> {
+ private final DependentProducerModule module;
+ private final Executor executor;
+ private final Producer<Integer> numGreetingsProducer;
+ private final Producer<String> greetingProducer;
+
+ public DependentProducerModule_GreetingsFactory(DependentProducerModule module, Executor executor, Producer<Integer> numGreetingsProducer, Producer<String> greetingProducer) {
+ assert module != null;
+ this.module = module;
+ assert executor != null;
+ this.executor = executor;
+ assert numGreetingsProducer != null;
+ this.numGreetingsProducer = numGreetingsProducer;
+ assert greetingProducer != null;
+ this.greetingProducer = greetingProducer;
+ }
+
+ @Override
+ protected ListenableFuture<List<String>> compute() {
+ ListenableFuture<Integer> numGreetingsProducerFuture = numGreetingsProducer.get();
+ ListenableFuture<String> greetingProducerFuture = greetingProducer.get();
+ return Futures.transform(Futures.<Object>allAsList(numGreetingsProducerFuture,greetingProducerFuture), new AsyncFunction<List<Object>, List<String>>() {
+ @SuppressWarnings("unchecked") // safe by specification
+ @Override public ListenableFuture<List<String>> apply(List<Object> args) {
+ return module.greetings((Integer) args.get(0), (String) args.get(1));
+ }
+ }, executor);
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_FutureStrFactory.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_FutureStrFactory.java
new file mode 100644
index 000000000..1f8e47fc6
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_FutureStrFactory.java
@@ -0,0 +1,34 @@
+package test;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.internal.AbstractProducer;
+import dagger.producers.internal.Producers;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingProducerModule_FutureStrFactory extends AbstractProducer<Set<String>> {
+ private final MultibindingProducerModule module;
+ private final Executor executor;
+
+ public MultibindingProducerModule_FutureStrFactory(MultibindingProducerModule module, Executor executor) {
+ assert module != null;
+ this.module = module;
+ assert executor != null;
+ this.executor = executor;
+ }
+
+ @Override
+ protected ListenableFuture<Set<String>> compute() {
+ ListenableFuture<ListenableFuture<Set<String>>> future = Producers.submitToExecutor(new Callable<ListenableFuture<Set<String>>>() {
+ @Override public ListenableFuture<Set<String>> call() {
+ return Producers.createFutureSingletonSet(module.futureStr());
+ }
+ }, executor);
+ return Futures.dereference(future);
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_FutureStrsFactory.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_FutureStrsFactory.java
new file mode 100644
index 000000000..8838ea5a4
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_FutureStrsFactory.java
@@ -0,0 +1,34 @@
+package test;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.internal.AbstractProducer;
+import dagger.producers.internal.Producers;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingProducerModule_FutureStrsFactory extends AbstractProducer<Set<String>> {
+ private final MultibindingProducerModule module;
+ private final Executor executor;
+
+ public MultibindingProducerModule_FutureStrsFactory(MultibindingProducerModule module, Executor executor) {
+ assert module != null;
+ this.module = module;
+ assert executor != null;
+ this.executor = executor;
+ }
+
+ @Override
+ protected ListenableFuture<Set<String>> compute() {
+ ListenableFuture<ListenableFuture<Set<String>>> future = Producers.submitToExecutor(new Callable<ListenableFuture<Set<String>>>() {
+ @Override public ListenableFuture<Set<String>> call() {
+ return module.futureStrs();
+ }
+ }, executor);
+ return Futures.dereference(future);
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_StrCountFactory.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_StrCountFactory.java
new file mode 100644
index 000000000..1da88f986
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_StrCountFactory.java
@@ -0,0 +1,37 @@
+package test;
+
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Producer;
+import dagger.producers.internal.AbstractProducer;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingProducerModule_StrCountFactory extends AbstractProducer<Integer> {
+ private final MultibindingProducerModule module;
+ private final Executor executor;
+ private final Producer<Set<String>> strsProducer;
+
+ public MultibindingProducerModule_StrCountFactory(MultibindingProducerModule module, Executor executor, Producer<Set<String>> strsProducer) {
+ assert module != null;
+ this.module = module;
+ assert executor != null;
+ this.executor = executor;
+ assert strsProducer != null;
+ this.strsProducer = strsProducer;
+ }
+
+ @Override
+ protected ListenableFuture<Integer> compute() {
+ ListenableFuture<Set<String>> strsProducerFuture = strsProducer.get();
+ return Futures.transform(strsProducerFuture, new AsyncFunction<Set<String>, Integer>() {
+ @Override public ListenableFuture<Integer> apply(Set<String> strs) {
+ return Futures.immediateFuture(module.strCount(strs));
+ }
+ }, executor);
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_StrFactory.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_StrFactory.java
new file mode 100644
index 000000000..e514ff9b5
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_StrFactory.java
@@ -0,0 +1,34 @@
+package test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.internal.AbstractProducer;
+import dagger.producers.internal.Producers;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingProducerModule_StrFactory extends AbstractProducer<Set<String>> {
+ private final MultibindingProducerModule module;
+ private final Executor executor;
+
+ public MultibindingProducerModule_StrFactory(MultibindingProducerModule module, Executor executor) {
+ assert module != null;
+ this.module = module;
+ assert executor != null;
+ this.executor = executor;
+ }
+
+ @Override
+ protected ListenableFuture<Set<String>> compute() {
+ ListenableFuture<Set<String>> future = Producers.submitToExecutor(new Callable<Set<String>>() {
+ @Override public Set<String> call() {
+ return ImmutableSet.of(module.str());
+ }
+ }, executor);
+ return future;
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_StrsFactory.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_StrsFactory.java
new file mode 100644
index 000000000..3bc2c1d83
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/MultibindingProducerModule_StrsFactory.java
@@ -0,0 +1,33 @@
+package test;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.internal.AbstractProducer;
+import dagger.producers.internal.Producers;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class MultibindingProducerModule_StrsFactory extends AbstractProducer<Set<String>> {
+ private final MultibindingProducerModule module;
+ private final Executor executor;
+
+ public MultibindingProducerModule_StrsFactory(MultibindingProducerModule module, Executor executor) {
+ assert module != null;
+ this.module = module;
+ assert executor != null;
+ this.executor = executor;
+ }
+
+ @Override
+ protected ListenableFuture<Set<String>> compute() {
+ ListenableFuture<Set<String>> future = Producers.submitToExecutor(new Callable<Set<String>>() {
+ @Override public Set<String> call() {
+ return module.strs();
+ }
+ }, executor);
+ return future;
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/Request_Factory.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/Request_Factory.java
new file mode 100644
index 000000000..5a5b3c24e
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/Request_Factory.java
@@ -0,0 +1,19 @@
+package test;
+
+import dagger.internal.Factory;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public enum Request_Factory implements Factory<Request> {
+INSTANCE;
+
+ @Override
+ public Request get() {
+ return new Request();
+ }
+
+ public static Factory<Request> create() {
+ return INSTANCE;
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/ResponseProducerModule_GreetingFactory.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/ResponseProducerModule_GreetingFactory.java
new file mode 100644
index 000000000..8e0d8bd78
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/ResponseProducerModule_GreetingFactory.java
@@ -0,0 +1,33 @@
+package test;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.internal.AbstractProducer;
+import dagger.producers.internal.Producers;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ResponseProducerModule_GreetingFactory extends AbstractProducer<String> {
+ private final ResponseProducerModule module;
+ private final Executor executor;
+
+ public ResponseProducerModule_GreetingFactory(ResponseProducerModule module, Executor executor) {
+ assert module != null;
+ this.module = module;
+ assert executor != null;
+ this.executor = executor;
+ }
+
+ @Override
+ protected ListenableFuture<String> compute() {
+ ListenableFuture<ListenableFuture<String>> future = Producers.submitToExecutor(new Callable<ListenableFuture<String>>() {
+ @Override public ListenableFuture<String> call() {
+ return module.greeting();
+ }
+ }, executor);
+ return Futures.dereference(future);
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/ResponseProducerModule_ResponseFactory.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/ResponseProducerModule_ResponseFactory.java
new file mode 100644
index 000000000..2d65f3890
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/ResponseProducerModule_ResponseFactory.java
@@ -0,0 +1,42 @@
+package test;
+
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Producer;
+import dagger.producers.internal.AbstractProducer;
+import java.util.List;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class ResponseProducerModule_ResponseFactory extends AbstractProducer<Response> {
+ private final ResponseProducerModule module;
+ private final Executor executor;
+ private final Producer<String> greetingProducer;
+ private final Producer<Request> requestProducer;
+
+ public ResponseProducerModule_ResponseFactory(ResponseProducerModule module, Executor executor, Producer<String> greetingProducer, Producer<Request> requestProducer) {
+ assert module != null;
+ this.module = module;
+ assert executor != null;
+ this.executor = executor;
+ assert greetingProducer != null;
+ this.greetingProducer = greetingProducer;
+ assert requestProducer != null;
+ this.requestProducer = requestProducer;
+ }
+
+ @Override
+ protected ListenableFuture<Response> compute() {
+ ListenableFuture<String> greetingProducerFuture = greetingProducer.get();
+ ListenableFuture<Request> requestProducerFuture = requestProducer.get();
+ return Futures.transform(Futures.<Object>allAsList(greetingProducerFuture,requestProducerFuture), new AsyncFunction<List<Object>, Response>() {
+ @SuppressWarnings("unchecked") // safe by specification
+ @Override public ListenableFuture<Response> apply(List<Object> args) {
+ return Futures.immediateFuture(module.response((String) args.get(0), (Request) args.get(1)));
+ }
+ }, executor);
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/SimpleProducerModule_LenFactory.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/SimpleProducerModule_LenFactory.java
new file mode 100644
index 000000000..0d26ff842
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/SimpleProducerModule_LenFactory.java
@@ -0,0 +1,36 @@
+package test;
+
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Producer;
+import dagger.producers.internal.AbstractProducer;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class SimpleProducerModule_LenFactory extends AbstractProducer<Integer> {
+ private final SimpleProducerModule module;
+ private final Executor executor;
+ private final Producer<String> strProducer;
+
+ public SimpleProducerModule_LenFactory(SimpleProducerModule module, Executor executor, Producer<String> strProducer) {
+ assert module != null;
+ this.module = module;
+ assert executor != null;
+ this.executor = executor;
+ assert strProducer != null;
+ this.strProducer = strProducer;
+ }
+
+ @Override
+ protected ListenableFuture<Integer> compute() {
+ ListenableFuture<String> strProducerFuture = strProducer.get();
+ return Futures.transform(strProducerFuture, new AsyncFunction<String, Integer>() {
+ @Override public ListenableFuture<Integer> apply(String str) {
+ return Futures.immediateFuture(module.len(str));
+ }
+ }, executor);
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/SimpleProducerModule_StrFactory.java b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/SimpleProducerModule_StrFactory.java
new file mode 100644
index 000000000..d38e99c3f
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/generated-sources/annotations/test/SimpleProducerModule_StrFactory.java
@@ -0,0 +1,33 @@
+package test;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.internal.AbstractProducer;
+import dagger.producers.internal.Producers;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+
+@Generated("dagger.internal.codegen.ComponentProcessor")
+public final class SimpleProducerModule_StrFactory extends AbstractProducer<String> {
+ private final SimpleProducerModule module;
+ private final Executor executor;
+
+ public SimpleProducerModule_StrFactory(SimpleProducerModule module, Executor executor) {
+ assert module != null;
+ this.module = module;
+ assert executor != null;
+ this.executor = executor;
+ }
+
+ @Override
+ protected ListenableFuture<String> compute() {
+ ListenableFuture<ListenableFuture<String>> future = Producers.submitToExecutor(new Callable<ListenableFuture<String>>() {
+ @Override public ListenableFuture<String> call() {
+ return module.str();
+ }
+ }, executor);
+ return Futures.dereference(future);
+ }
+}
+
diff --git a/compiler/src/it/producers-functional-tests/target/test-classes/test/DependentTest$1.class b/compiler/src/it/producers-functional-tests/target/test-classes/test/DependentTest$1.class
new file mode 100644
index 000000000..ff19f2a48
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/test-classes/test/DependentTest$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/test-classes/test/DependentTest$2.class b/compiler/src/it/producers-functional-tests/target/test-classes/test/DependentTest$2.class
new file mode 100644
index 000000000..f3a1d6008
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/test-classes/test/DependentTest$2.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/test-classes/test/DependentTest.class b/compiler/src/it/producers-functional-tests/target/test-classes/test/DependentTest.class
new file mode 100644
index 000000000..c7c6daa67
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/test-classes/test/DependentTest.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/test-classes/test/MultibindingTest.class b/compiler/src/it/producers-functional-tests/target/test-classes/test/MultibindingTest.class
new file mode 100644
index 000000000..cbf125c2d
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/test-classes/test/MultibindingTest.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/test-classes/test/ProducerFactoryTest$1.class b/compiler/src/it/producers-functional-tests/target/test-classes/test/ProducerFactoryTest$1.class
new file mode 100644
index 000000000..7daeead5d
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/test-classes/test/ProducerFactoryTest$1.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/test-classes/test/ProducerFactoryTest.class b/compiler/src/it/producers-functional-tests/target/test-classes/test/ProducerFactoryTest.class
new file mode 100644
index 000000000..96ee02f11
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/test-classes/test/ProducerFactoryTest.class
Binary files differ
diff --git a/compiler/src/it/producers-functional-tests/target/test-classes/test/SimpleTest.class b/compiler/src/it/producers-functional-tests/target/test-classes/test/SimpleTest.class
new file mode 100644
index 000000000..d00fb7c0d
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/target/test-classes/test/SimpleTest.class
Binary files differ
diff --git a/compiler/src/main/java/dagger/internal/codegen/AbstractComponentProcessingStep.java b/compiler/src/main/java/dagger/internal/codegen/AbstractComponentProcessingStep.java
new file mode 100644
index 000000000..578fb5ffa
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/AbstractComponentProcessingStep.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.BasicAnnotationProcessor.ProcessingStep;
+import com.google.auto.common.MoreElements;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+import java.lang.annotation.Annotation;
+import javax.annotation.processing.Messager;
+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}.
+ */
+abstract class AbstractComponentProcessingStep implements ProcessingStep {
+
+ private final Class<? extends Annotation> componentAnnotation;
+ private final Messager messager;
+ private final ComponentHierarchyValidator componentHierarchyValidator;
+ private final BindingGraphValidator bindingGraphValidator;
+ private final ComponentDescriptor.Factory componentDescriptorFactory;
+ private final BindingGraph.Factory bindingGraphFactory;
+ private final ComponentGenerator componentGenerator;
+
+ AbstractComponentProcessingStep(
+ Class<? extends Annotation> componentAnnotation,
+ Messager messager,
+ ComponentHierarchyValidator componentHierarchyValidator,
+ BindingGraphValidator bindingGraphValidator,
+ ComponentDescriptor.Factory componentDescriptorFactory,
+ BindingGraph.Factory bindingGraphFactory,
+ ComponentGenerator componentGenerator) {
+ this.componentAnnotation = componentAnnotation;
+ this.messager = messager;
+ this.componentHierarchyValidator = componentHierarchyValidator;
+ this.bindingGraphValidator = bindingGraphValidator;
+ this.componentDescriptorFactory = componentDescriptorFactory;
+ this.bindingGraphFactory = bindingGraphFactory;
+ this.componentGenerator = componentGenerator;
+ }
+
+ @Override
+ public final ImmutableSet<Element> process(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ ImmutableSet.Builder<Element> rejectedElements = ImmutableSet.builder();
+ ComponentElementValidator componentElementValidator =
+ componentElementValidator(elementsByAnnotation);
+ for (Element element : elementsByAnnotation.get(componentAnnotation)) {
+ TypeElement componentTypeElement = MoreElements.asType(element);
+ try {
+ if (componentElementValidator.validateComponent(componentTypeElement, messager)) {
+ ComponentDescriptor componentDescriptor =
+ componentDescriptorFactory.forComponent(componentTypeElement);
+ ValidationReport<TypeElement> hierarchyReport =
+ componentHierarchyValidator.validate(componentDescriptor);
+ hierarchyReport.printMessagesTo(messager);
+ if (hierarchyReport.isClean()) {
+ BindingGraph bindingGraph = bindingGraphFactory.create(componentDescriptor);
+ ValidationReport<TypeElement> graphReport =
+ bindingGraphValidator.validate(bindingGraph);
+ graphReport.printMessagesTo(messager);
+ if (graphReport.isClean()) {
+ generateComponent(bindingGraph);
+ }
+ }
+ }
+ } catch (TypeNotPresentException e) {
+ rejectedElements.add(componentTypeElement);
+ }
+ }
+ return rejectedElements.build();
+ }
+
+ private void generateComponent(BindingGraph bindingGraph) {
+ try {
+ componentGenerator.generate(bindingGraph);
+ } catch (SourceFileGenerationException e) {
+ e.printMessageTo(messager);
+ }
+ }
+
+ /**
+ * Returns an object that can validate a type element annotated with the component type.
+ */
+ protected abstract ComponentElementValidator componentElementValidator(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation);
+
+ /**
+ * Validates a component type element.
+ */
+ protected static abstract class ComponentElementValidator {
+ /**
+ * Validates a component type element. Prints any messages about the element to
+ * {@code messager}.
+ *
+ * @throws TypeNotPresentException if any type required to validate the component cannot be
+ * found
+ */
+ abstract boolean validateComponent(TypeElement componentTypeElement, Messager messager);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/AbstractComponentWriter.java b/compiler/src/main/java/dagger/internal/codegen/AbstractComponentWriter.java
new file mode 100644
index 000000000..e0425c925
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/AbstractComponentWriter.java
@@ -0,0 +1,1150 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+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.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.MembersInjector;
+import dagger.internal.DelegateFactory;
+import dagger.internal.Factory;
+import dagger.internal.InstanceFactory;
+import dagger.internal.MapFactory;
+import dagger.internal.MapProviderFactory;
+import dagger.internal.MembersInjectors;
+import dagger.internal.ScopedProvider;
+import dagger.internal.SetFactory;
+import dagger.internal.codegen.ComponentDescriptor.BuilderSpec;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.ComponentGenerator.MemberSelect;
+import dagger.internal.codegen.ComponentGenerator.ProxyClassAndField;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ClassWriter;
+import dagger.internal.codegen.writer.ConstructorWriter;
+import dagger.internal.codegen.writer.FieldWriter;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.MethodWriter;
+import dagger.internal.codegen.writer.ParameterizedTypeName;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.StringLiteral;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import dagger.internal.codegen.writer.TypeWriter;
+import dagger.internal.codegen.writer.VoidName;
+import dagger.producers.Producer;
+import dagger.producers.internal.Producers;
+import dagger.producers.internal.SetProducer;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+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.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+import javax.tools.Diagnostic.Kind;
+
+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.Preconditions.checkState;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.DELEGATED;
+import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.INITIALIZED;
+import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.UNINITIALIZED;
+import static dagger.internal.codegen.Binding.bindingPackageFor;
+import static dagger.internal.codegen.ComponentGenerator.MemberSelect.staticMethodInvocationWithCast;
+import static dagger.internal.codegen.ComponentGenerator.MemberSelect.staticSelect;
+import static dagger.internal.codegen.ErrorMessages.CANNOT_RETURN_NULL_FROM_NON_NULLABLE_COMPONENT_METHOD;
+import static dagger.internal.codegen.MapKeys.getMapKeySnippet;
+import static dagger.internal.codegen.MembersInjectionBinding.Strategy.NO_OP;
+import static dagger.internal.codegen.ProvisionBinding.FactoryCreationStrategy.ENUM_INSTANCE;
+import static dagger.internal.codegen.ProvisionBinding.Kind.PROVISION;
+import static dagger.internal.codegen.SourceFiles.factoryNameForProductionBinding;
+import static dagger.internal.codegen.SourceFiles.factoryNameForProvisionBinding;
+import static dagger.internal.codegen.SourceFiles.frameworkTypeUsageStatement;
+import static dagger.internal.codegen.SourceFiles.indexDependenciesByUnresolvedKey;
+import static dagger.internal.codegen.SourceFiles.membersInjectorNameForType;
+import static dagger.internal.codegen.Util.componentCanMakeNewInstances;
+import static dagger.internal.codegen.Util.getKeyTypeOfMap;
+import static dagger.internal.codegen.Util.getProvidedValueTypeOfMap;
+import static dagger.internal.codegen.Util.isMapWithNonProvidedValues;
+import static dagger.internal.codegen.writer.Snippet.memberSelectSnippet;
+import static dagger.internal.codegen.writer.Snippet.nullCheck;
+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 static javax.lang.model.type.TypeKind.DECLARED;
+import static javax.lang.model.type.TypeKind.VOID;
+
+/**
+ * Creates the implementation class for a component or subcomponent.
+ */
+abstract class AbstractComponentWriter {
+ // TODO(dpb): Make all these fields private after refactoring is complete.
+ protected final Elements elements;
+ protected final Types types;
+ protected final Key.Factory keyFactory;
+ protected final Kind nullableValidationType;
+ protected final Set<JavaWriter> javaWriters = new LinkedHashSet<>();
+ protected final ClassName name;
+ protected final BindingGraph graph;
+ private final Map<String, ProxyClassAndField> packageProxies = new HashMap<>();
+ private final Map<BindingKey, InitializationState> initializationStates = new HashMap<>();
+ protected ClassWriter componentWriter;
+ private ImmutableMap<BindingKey, MemberSelect> memberSelectSnippets;
+ private ImmutableMap<ContributionBinding, MemberSelect> multibindingContributionSnippets;
+ private ImmutableSet<BindingKey> enumBindingKeys;
+ protected ConstructorWriter constructorWriter;
+ protected Optional<ClassName> builderName = Optional.absent();
+
+ /**
+ * For each component requirement, the builder field. This map is empty for subcomponents that do
+ * not use a builder.
+ */
+ private ImmutableMap<TypeElement, FieldWriter> builderFields = ImmutableMap.of();
+
+ /**
+ * For each component requirement, the snippet for the component field that holds it.
+ *
+ * <p>Fields are written for all requirements for subcomponents that do not use a builder, and for
+ * any requirement that is reused from a subcomponent of this component.
+ */
+ protected final Map<TypeElement, MemberSelect> componentContributionFields = Maps.newHashMap();
+
+ AbstractComponentWriter(
+ Types types,
+ Elements elements,
+ Key.Factory keyFactory,
+ Diagnostic.Kind nullableValidationType,
+ ClassName name,
+ BindingGraph graph) {
+ this.types = types;
+ this.elements = elements;
+ this.keyFactory = keyFactory;
+ this.nullableValidationType = nullableValidationType;
+ this.name = name;
+ this.graph = graph;
+ }
+
+ protected final TypeElement componentDefinitionType() {
+ return graph.componentDescriptor().componentDefinitionType();
+ }
+
+ protected final ClassName componentDefinitionTypeName() {
+ return ClassName.fromTypeElement(componentDefinitionType());
+ }
+
+ /**
+ * Returns an expression snippet that evaluates to an instance of the contribution, looking for
+ * either a builder field or a component field.
+ */
+ private Snippet getComponentContributionSnippet(TypeElement contributionType) {
+ if (builderFields.containsKey(contributionType)) {
+ return Snippet.format("builder.%s", builderFields.get(contributionType).name());
+ } else {
+ Optional<Snippet> snippet = getOrCreateComponentContributionFieldSnippet(contributionType);
+ checkState(snippet.isPresent(), "no builder or component field for %s", contributionType);
+ return snippet.get();
+ }
+ }
+
+ /**
+ * Returns a snippet for a component contribution field. Adds a field the first time one is
+ * requested for a contribution type if this component's builder has a field for it.
+ */
+ protected Optional<Snippet> getOrCreateComponentContributionFieldSnippet(
+ TypeElement contributionType) {
+ MemberSelect fieldSelect = componentContributionFields.get(contributionType);
+ if (fieldSelect == null) {
+ if (!builderFields.containsKey(contributionType)) {
+ return Optional.absent();
+ }
+ FieldWriter componentField =
+ componentWriter.addField(contributionType, simpleVariableName(contributionType));
+ componentField.addModifiers(PRIVATE, FINAL);
+ constructorWriter
+ .body()
+ .addSnippet(
+ "this.%s = builder.%s;",
+ componentField.name(),
+ builderFields.get(contributionType).name());
+ fieldSelect = MemberSelect.instanceSelect(name, Snippet.format("%s", componentField.name()));
+ componentContributionFields.put(contributionType, fieldSelect);
+ }
+ return Optional.of(fieldSelect.getSnippetFor(name));
+ }
+
+ private Snippet getMemberSelectSnippet(BindingKey key) {
+ return getMemberSelect(key).getSnippetFor(name);
+ }
+
+ protected MemberSelect getMemberSelect(BindingKey key) {
+ return memberSelectSnippets.get(key);
+ }
+
+ protected Optional<MemberSelect> getMultibindingContributionSnippet(ContributionBinding binding) {
+ return Optional.fromNullable(multibindingContributionSnippets.get(binding));
+ }
+
+ /**
+ * Returns the initialization state of the factory field for a binding key in this component.
+ */
+ protected InitializationState getInitializationState(BindingKey bindingKey) {
+ return initializationStates.containsKey(bindingKey)
+ ? initializationStates.get(bindingKey)
+ : UNINITIALIZED;
+ }
+
+ private void setInitializationState(BindingKey bindingKey, InitializationState state) {
+ initializationStates.put(bindingKey, state);
+ }
+
+ ImmutableSet<JavaWriter> write() {
+ if (javaWriters.isEmpty()) {
+ writeComponent();
+ }
+ return ImmutableSet.copyOf(javaWriters);
+ }
+
+ private void writeComponent() {
+ componentWriter = createComponentClass();
+ addConstructor();
+ addBuilder();
+ addFactoryMethods();
+ addFields();
+ initializeFrameworkTypes();
+ implementInterfaceMethods();
+ addSubcomponents();
+ }
+
+ /**
+ * Creates the component implementation class.
+ */
+ protected abstract ClassWriter createComponentClass();
+
+ private void addConstructor() {
+ constructorWriter = componentWriter.addConstructor();
+ constructorWriter.addModifiers(PRIVATE);
+ }
+
+ /**
+ * Adds a builder type.
+ */
+ protected void addBuilder() {
+ ClassWriter builderWriter = createBuilder();
+ builderWriter.addModifiers(FINAL);
+ builderWriter.addConstructor().addModifiers(PRIVATE);
+ builderName = Optional.of(builderWriter.name());
+
+ Optional<BuilderSpec> builderSpec = graph.componentDescriptor().builderSpec();
+ if (builderSpec.isPresent()) {
+ builderWriter.addModifiers(PRIVATE);
+ builderWriter.setSupertype(builderSpec.get().builderDefinitionType());
+ } else {
+ builderWriter.addModifiers(PUBLIC);
+ }
+
+ builderFields = addBuilderFields(builderWriter);
+ addBuildMethod(builderWriter, builderSpec);
+ addBuilderMethods(builderWriter, builderSpec);
+
+ constructorWriter.addParameter(builderWriter, "builder");
+ constructorWriter.body().addSnippet("assert builder != null;");
+ }
+
+ /**
+ * Adds fields for each of the {@linkplain BindingGraph#componentRequirements component
+ * requirements}. Regardless of builder spec, there is always one field per requirement.
+ */
+ private ImmutableMap<TypeElement, FieldWriter> addBuilderFields(ClassWriter builderWriter) {
+ ImmutableMap.Builder<TypeElement, FieldWriter> builderFieldsBuilder = ImmutableMap.builder();
+ for (TypeElement contributionElement : graph.componentRequirements()) {
+ String contributionName = simpleVariableName(contributionElement);
+ FieldWriter builderField = builderWriter.addField(contributionElement, contributionName);
+ builderField.addModifiers(PRIVATE);
+ builderFieldsBuilder.put(contributionElement, builderField);
+ }
+ return builderFieldsBuilder.build();
+ }
+
+ /** Adds the build method to the builder. */
+ private void addBuildMethod(ClassWriter builderWriter, Optional<BuilderSpec> builderSpec) {
+ MethodWriter buildMethod;
+ if (builderSpec.isPresent()) {
+ ExecutableElement specBuildMethod = builderSpec.get().buildMethod();
+ // Note: we don't use the specBuildMethod.getReturnType() as the return type
+ // because it might be a type variable. We make use of covariant returns to allow
+ // us to return the component type, which will always be valid.
+ buildMethod =
+ builderWriter.addMethod(
+ componentDefinitionTypeName(), specBuildMethod.getSimpleName().toString());
+ buildMethod.annotate(Override.class);
+ } else {
+ buildMethod = builderWriter.addMethod(componentDefinitionTypeName(), "build");
+ }
+ buildMethod.addModifiers(PUBLIC);
+
+ for (Map.Entry<TypeElement, FieldWriter> builderFieldEntry : builderFields.entrySet()) {
+ FieldWriter builderField = builderFieldEntry.getValue();
+ if (componentCanMakeNewInstances(builderFieldEntry.getKey())) {
+ buildMethod.body()
+ .addSnippet("if (%1$s == null) { this.%1$s = new %2$s(); }",
+ builderField.name(),
+ builderField.type());
+ } else {
+ buildMethod.body()
+ .addSnippet(
+ "if (%s == null) { throw new %s(%s.class.getCanonicalName() + \" must be set\"); }",
+ builderField.name(),
+ ClassName.fromClass(IllegalStateException.class),
+ builderField.type());
+ }
+ }
+
+ buildMethod.body().addSnippet("return new %s(this);", name);
+ }
+
+ /**
+ * Adds the methods that set each of parameters on the builder. If the {@link BuilderSpec} is
+ * present, it will tailor the methods to match the spec.
+ */
+ private void addBuilderMethods(
+ ClassWriter builderWriter,
+ Optional<BuilderSpec> builderSpec) {
+ if (builderSpec.isPresent()) {
+ for (Map.Entry<TypeElement, ExecutableElement> builderMethodEntry :
+ builderSpec.get().methodMap().entrySet()) {
+ TypeElement builderMethodType = builderMethodEntry.getKey();
+ ExecutableElement specMethod = builderMethodEntry.getValue();
+ MethodWriter builderMethod = addBuilderMethodFromSpec(builderWriter, specMethod);
+ String parameterName =
+ Iterables.getOnlyElement(specMethod.getParameters()).getSimpleName().toString();
+ builderMethod.addParameter(builderMethodType, parameterName);
+ builderMethod.body().addSnippet(nullCheck(parameterName));
+ if (graph.componentRequirements().contains(builderMethodType)) {
+ // required type
+ builderMethod.body().addSnippet("this.%s = %s;",
+ builderFields.get(builderMethodType).name(),
+ parameterName);
+ addBuilderMethodReturnStatementForSpec(specMethod, builderMethod);
+ } else if (graph.ownedModuleTypes().contains(builderMethodType)) {
+ // owned, but not required
+ builderMethod.body()
+ .addSnippet("// This module is declared, but not used in the component. "
+ + "This method is a no-op");
+ addBuilderMethodReturnStatementForSpec(specMethod, builderMethod);
+ } else {
+ // neither owned nor required, so it must be an inherited module
+ builderMethod
+ .body()
+ .addSnippet(
+ "throw new %s(%s.format(%s, %s.class.getCanonicalName()));",
+ ClassName.fromClass(UnsupportedOperationException.class),
+ ClassName.fromClass(String.class),
+ StringLiteral.forValue(
+ "%s cannot be set because it is inherited from the enclosing component"),
+ ClassName.fromTypeElement(builderMethodType));
+ }
+ }
+ } else {
+ for (TypeElement componentRequirement : graph.availableDependencies()) {
+ String componentRequirementName = simpleVariableName(componentRequirement);
+ MethodWriter builderMethod = builderWriter.addMethod(
+ builderWriter.name(),
+ componentRequirementName);
+ builderMethod.addModifiers(PUBLIC);
+ builderMethod.addParameter(componentRequirement, componentRequirementName);
+ builderMethod.body().addSnippet(nullCheck(componentRequirementName));
+ if (graph.componentRequirements().contains(componentRequirement)) {
+ builderMethod.body()
+ .addSnippet("this.%s = %s;",
+ builderFields.get(componentRequirement).name(),
+ componentRequirementName);
+ } else {
+ builderMethod.annotate(Deprecated.class);
+ }
+ builderMethod.body().addSnippet("return this;");
+ }
+ }
+ }
+
+ private void addBuilderMethodReturnStatementForSpec(
+ ExecutableElement specMethod, MethodWriter builderMethod) {
+ if (!specMethod.getReturnType().getKind().equals(VOID)) {
+ builderMethod.body().addSnippet("return this;");
+ }
+ }
+
+ private MethodWriter addBuilderMethodFromSpec(
+ ClassWriter builderWriter, ExecutableElement method) {
+ String methodName = method.getSimpleName().toString();
+ TypeMirror returnType = method.getReturnType();
+ // If the return type is void, we add a method with the void return type.
+ // Otherwise we use the builderWriter and take advantage of covariant returns
+ // (so that we don't have to worry about setter methods that return type variables).
+ MethodWriter builderMethod =
+ returnType.getKind().equals(TypeKind.VOID)
+ ? builderWriter.addMethod(returnType, methodName)
+ : builderWriter.addMethod(builderWriter, methodName);
+ builderMethod.annotate(Override.class);
+ builderMethod.addModifiers(Sets.difference(method.getModifiers(), ImmutableSet.of(ABSTRACT)));
+ return builderMethod;
+ }
+
+ /**
+ * Creates the builder class.
+ */
+ protected abstract ClassWriter createBuilder();
+
+ /**
+ * Adds component factory methods.
+ */
+ protected abstract void addFactoryMethods();
+
+ private void addFields() {
+ Map<BindingKey, MemberSelect> memberSelectSnippetsBuilder = Maps.newHashMap();
+ Map<ContributionBinding, MemberSelect> multibindingContributionSnippetsBuilder =
+ Maps.newHashMap();
+ ImmutableSet.Builder<BindingKey> enumBindingKeysBuilder = ImmutableSet.builder();
+
+ for (ResolvedBindings resolvedBindings : graph.resolvedBindings().values()) {
+ addField(
+ memberSelectSnippetsBuilder,
+ multibindingContributionSnippetsBuilder,
+ enumBindingKeysBuilder,
+ resolvedBindings);
+ }
+
+ memberSelectSnippets = ImmutableMap.copyOf(memberSelectSnippetsBuilder);
+ multibindingContributionSnippets = ImmutableMap.copyOf(multibindingContributionSnippetsBuilder);
+ enumBindingKeys = enumBindingKeysBuilder.build();
+ }
+
+ private void addField(
+ Map<BindingKey, MemberSelect> memberSelectSnippetsBuilder,
+ Map<ContributionBinding, MemberSelect> multibindingContributionSnippetsBuilder,
+ ImmutableSet.Builder<BindingKey> enumBindingKeysBuilder,
+ ResolvedBindings resolvedBindings) {
+ BindingKey bindingKey = resolvedBindings.bindingKey();
+
+ // No field needed for unique contributions inherited from the parent.
+ if (resolvedBindings.isUniqueContribution() && resolvedBindings.ownedBindings().isEmpty()) {
+ return;
+ }
+
+ // No field needed for bindings with no dependencies or state.
+ Optional<MemberSelect> staticMemberSelect = staticMemberSelect(resolvedBindings);
+ if (staticMemberSelect.isPresent()) {
+ // TODO(gak): refactor to use enumBindingKeys throughout the generator
+ enumBindingKeysBuilder.add(bindingKey);
+ memberSelectSnippetsBuilder.put(bindingKey, staticMemberSelect.get());
+ return;
+ }
+
+ String bindingPackage = bindingPackageFor(resolvedBindings.bindings()).or(name.packageName());
+
+ final Optional<String> proxySelector;
+ final TypeWriter classWithFields;
+ final Set<Modifier> fieldModifiers;
+
+ if (bindingPackage.equals(name.packageName())) {
+ // no proxy
+ proxySelector = Optional.absent();
+ // component gets the fields
+ classWithFields = componentWriter;
+ // private fields
+ fieldModifiers = EnumSet.of(PRIVATE);
+ } else {
+ // get or create the proxy
+ ProxyClassAndField proxyClassAndField = packageProxies.get(bindingPackage);
+ if (proxyClassAndField == null) {
+ JavaWriter proxyJavaWriter = JavaWriter.inPackage(bindingPackage);
+ javaWriters.add(proxyJavaWriter);
+ ClassWriter proxyWriter = proxyJavaWriter.addClass(name.simpleName() + "_PackageProxy");
+ proxyWriter.annotate(Generated.class).setValue(ComponentProcessor.class.getCanonicalName());
+ proxyWriter.addModifiers(PUBLIC, FINAL);
+ // create the field for the proxy in the component
+ FieldWriter proxyFieldWriter =
+ componentWriter.addField(
+ proxyWriter.name(), bindingPackage.replace('.', '_') + "_Proxy");
+ proxyFieldWriter.addModifiers(PRIVATE, FINAL);
+ proxyFieldWriter.setInitializer("new %s()", proxyWriter.name());
+ proxyClassAndField = ProxyClassAndField.create(proxyWriter, proxyFieldWriter);
+ packageProxies.put(bindingPackage, proxyClassAndField);
+ }
+ // add the field for the member select
+ proxySelector = Optional.of(proxyClassAndField.proxyFieldWriter().name());
+ // proxy gets the fields
+ classWithFields = proxyClassAndField.proxyWriter();
+ // public fields in the proxy
+ fieldModifiers = EnumSet.of(PUBLIC);
+ }
+
+ if (bindingKey.kind().equals(BindingKey.Kind.CONTRIBUTION)) {
+ ImmutableSet<? extends ContributionBinding> contributionBindings =
+ resolvedBindings.contributionBindings();
+ if (ContributionBinding.bindingTypeFor(contributionBindings).isMultibinding()) {
+ // note that here we rely on the order of the resolved bindings being from parent to child
+ // otherwise, the numbering wouldn't work
+ int contributionNumber = 0;
+ for (ContributionBinding contributionBinding : contributionBindings) {
+ if (!contributionBinding.isSyntheticBinding()) {
+ contributionNumber++;
+ if (resolvedBindings.ownedBindings().contains(contributionBinding)) {
+ FrameworkField contributionBindingField =
+ FrameworkField.createForSyntheticContributionBinding(
+ bindingKey, contributionNumber, contributionBinding);
+ FieldWriter contributionField =
+ classWithFields.addField(
+ contributionBindingField.frameworkType(), contributionBindingField.name());
+ contributionField.addModifiers(fieldModifiers);
+
+ ImmutableList<String> contributionSelectTokens =
+ new ImmutableList.Builder<String>()
+ .addAll(proxySelector.asSet())
+ .add(contributionField.name())
+ .build();
+ multibindingContributionSnippetsBuilder.put(
+ contributionBinding,
+ MemberSelect.instanceSelect(name, memberSelectSnippet(contributionSelectTokens)));
+ }
+ }
+ }
+ }
+ }
+
+ FrameworkField bindingField = FrameworkField.createForResolvedBindings(resolvedBindings);
+ FieldWriter frameworkField =
+ classWithFields.addField(bindingField.frameworkType(), bindingField.name());
+ frameworkField.addModifiers(fieldModifiers);
+
+ ImmutableList<String> memberSelectTokens =
+ new ImmutableList.Builder<String>()
+ .addAll(proxySelector.asSet())
+ .add(frameworkField.name())
+ .build();
+ memberSelectSnippetsBuilder.put(
+ bindingKey,
+ MemberSelect.instanceSelect(name, Snippet.memberSelectSnippet(memberSelectTokens)));
+ }
+
+ /**
+ * If {@code resolvedBindings} is an unscoped provision binding with no factory arguments or a
+ * no-op members injection binding, then we do't need a field to hold its factory. In that case,
+ * this method returns the static member select snippet that returns the factory or no-op members
+ * injector.
+ */
+ private Optional<MemberSelect> staticMemberSelect(ResolvedBindings resolvedBindings) {
+ if (resolvedBindings.bindings().size() != 1) {
+ return Optional.absent();
+ }
+ switch (resolvedBindings.bindingKey().kind()) {
+ case CONTRIBUTION:
+ ContributionBinding contributionBinding =
+ getOnlyElement(resolvedBindings.contributionBindings());
+ if (contributionBinding.bindingType().isMultibinding()
+ || !(contributionBinding instanceof ProvisionBinding)) {
+ return Optional.absent();
+ }
+ ProvisionBinding provisionBinding = (ProvisionBinding) contributionBinding;
+ if (provisionBinding.factoryCreationStrategy().equals(ENUM_INSTANCE)
+ && !provisionBinding.scope().isPresent()) {
+ return Optional.of(
+ staticSelect(
+ factoryNameForProvisionBinding(provisionBinding), Snippet.format("create()")));
+ }
+ break;
+
+ case MEMBERS_INJECTION:
+ if (getOnlyElement(resolvedBindings.membersInjectionBindings())
+ .injectionStrategy()
+ .equals(NO_OP)) {
+ return Optional.of(
+ staticMethodInvocationWithCast(
+ ClassName.fromClass(MembersInjectors.class),
+ Snippet.format("noOp()"),
+ ClassName.fromClass(MembersInjector.class)));
+ }
+ break;
+
+ default:
+ throw new AssertionError();
+ }
+ return Optional.absent();
+ }
+
+ private void implementInterfaceMethods() {
+ Set<MethodSignature> interfaceMethods = Sets.newHashSet();
+ for (ComponentMethodDescriptor componentMethod :
+ graph.componentDescriptor().componentMethods()) {
+ if (componentMethod.dependencyRequest().isPresent()) {
+ DependencyRequest interfaceRequest = componentMethod.dependencyRequest().get();
+ ExecutableElement requestElement =
+ MoreElements.asExecutable(interfaceRequest.requestElement());
+ ExecutableType requestType = MoreTypes.asExecutable(types.asMemberOf(
+ MoreTypes.asDeclared(componentDefinitionType().asType()), requestElement));
+ MethodSignature signature = MethodSignature.fromExecutableType(
+ requestElement.getSimpleName().toString(), requestType);
+ if (!interfaceMethods.contains(signature)) {
+ interfaceMethods.add(signature);
+ MethodWriter interfaceMethod =
+ requestType.getReturnType().getKind().equals(VOID)
+ ? componentWriter.addMethod(
+ VoidName.VOID, requestElement.getSimpleName().toString())
+ : componentWriter.addMethod(
+ requestType.getReturnType(), requestElement.getSimpleName().toString());
+ interfaceMethod.annotate(Override.class);
+ interfaceMethod.addModifiers(PUBLIC);
+ BindingKey bindingKey = interfaceRequest.bindingKey();
+ switch (interfaceRequest.kind()) {
+ case MEMBERS_INJECTOR:
+ Snippet membersInjectorSelect = getMemberSelectSnippet(bindingKey);
+ List<? extends VariableElement> parameters = requestElement.getParameters();
+ if (parameters.isEmpty()) {
+ // we're returning the framework type
+ interfaceMethod.body().addSnippet("return %s;", membersInjectorSelect);
+ } else {
+ VariableElement parameter = Iterables.getOnlyElement(parameters);
+ Name parameterName = parameter.getSimpleName();
+ interfaceMethod.addParameter(
+ TypeNames.forTypeMirror(
+ Iterables.getOnlyElement(requestType.getParameterTypes())),
+ parameterName.toString());
+ interfaceMethod
+ .body()
+ .addSnippet(
+ "%s.injectMembers(%s);",
+ // In this case we know we won't need the cast because we're never going to
+ // pass the reference to anything.
+ membersInjectorSelect,
+ parameterName);
+ if (!requestType.getReturnType().getKind().equals(VOID)) {
+ interfaceMethod.body().addSnippet("return %s;", parameterName);
+ }
+ }
+ break;
+ case INSTANCE:
+ if (enumBindingKeys.contains(bindingKey)
+ && bindingKey.key().type().getKind().equals(DECLARED)
+ && !((DeclaredType) bindingKey.key().type()).getTypeArguments().isEmpty()) {
+ // If using a parameterized enum type, then we need to store the factory
+ // in a temporary variable, in order to help javac be able to infer
+ // the generics of the Factory.create methods.
+ TypeName factoryType =
+ ParameterizedTypeName.create(
+ Provider.class, TypeNames.forTypeMirror(requestType.getReturnType()));
+ interfaceMethod
+ .body()
+ .addSnippet(
+ "%s factory = %s;", factoryType, getMemberSelectSnippet(bindingKey));
+ interfaceMethod.body().addSnippet("return factory.get();");
+ break;
+ }
+ // fall through in the else case.
+ case LAZY:
+ case PRODUCED:
+ case PRODUCER:
+ case PROVIDER:
+ case FUTURE:
+ interfaceMethod
+ .body()
+ .addSnippet(
+ "return %s;",
+ frameworkTypeUsageStatement(
+ getMemberSelectSnippet(bindingKey), interfaceRequest.kind()));
+ break;
+ default:
+ throw new AssertionError();
+ }
+ }
+ }
+ }
+ }
+
+ private void addSubcomponents() {
+ for (Map.Entry<ExecutableElement, BindingGraph> subgraphEntry : graph.subgraphs().entrySet()) {
+ SubcomponentWriter subcomponent =
+ new SubcomponentWriter(this, subgraphEntry.getKey(), subgraphEntry.getValue());
+ javaWriters.addAll(subcomponent.write());
+ }
+ }
+
+ private void initializeFrameworkTypes() {
+ List<List<BindingKey>> partitions =
+ Lists.partition(graph.resolvedBindings().keySet().asList(), 100);
+ for (int i = 0; i < partitions.size(); i++) {
+ MethodWriter initializeMethod =
+ componentWriter.addMethod(VoidName.VOID, "initialize" + ((i == 0) ? "" : i));
+ initializeMethod.body();
+ initializeMethod.addModifiers(PRIVATE);
+ if (builderName.isPresent()) {
+ initializeMethod.addParameter(builderName.get(), "builder").addModifiers(FINAL);
+ constructorWriter.body().addSnippet("%s(builder);", initializeMethod.name());
+ } else {
+ constructorWriter.body().addSnippet("%s();", initializeMethod.name());
+ }
+ for (BindingKey bindingKey : partitions.get(i)) {
+ ResolvedBindings resolvedBindings = graph.resolvedBindings().get(bindingKey);
+ switch (bindingKey.kind()) {
+ case CONTRIBUTION:
+ ImmutableSet<? extends ContributionBinding> bindings =
+ resolvedBindings.contributionBindings();
+
+ switch (ContributionBinding.bindingTypeFor(bindings)) {
+ case SET:
+ boolean hasOnlyProvisions =
+ Iterables.all(bindings, Predicates.instanceOf(ProvisionBinding.class));
+ ImmutableList.Builder<Snippet> parameterSnippets = ImmutableList.builder();
+ for (ContributionBinding binding : bindings) {
+ Optional<MemberSelect> multibindingContributionSnippet =
+ getMultibindingContributionSnippet(binding);
+ checkState(
+ multibindingContributionSnippet.isPresent(), "%s was not found", binding);
+ Snippet snippet = multibindingContributionSnippet.get().getSnippetFor(name);
+ if (multibindingContributionSnippet.get().owningClass().equals(name)) {
+ Snippet initializeSnippet = initializeFactoryForContributionBinding(binding);
+ initializeMethod.body().addSnippet("this.%s = %s;", snippet, initializeSnippet);
+ }
+ parameterSnippets.add(snippet);
+ }
+ Snippet initializeSetSnippet =
+ Snippet.format(
+ "%s.create(%s)",
+ hasOnlyProvisions
+ ? ClassName.fromClass(SetFactory.class)
+ : ClassName.fromClass(SetProducer.class),
+ Snippet.makeParametersSnippet(parameterSnippets.build()));
+ initializeMember(initializeMethod, bindingKey, initializeSetSnippet);
+ break;
+ case MAP:
+ if (Sets.filter(bindings, Predicates.instanceOf(ProductionBinding.class))
+ .isEmpty()) {
+ @SuppressWarnings("unchecked") // checked by the instanceof filter above
+ ImmutableSet<ProvisionBinding> provisionBindings =
+ (ImmutableSet<ProvisionBinding>) bindings;
+ for (ProvisionBinding provisionBinding : provisionBindings) {
+ Optional<MemberSelect> multibindingContributionSnippet =
+ getMultibindingContributionSnippet(provisionBinding);
+ if (!isMapWithNonProvidedValues(provisionBinding.key().type())
+ && multibindingContributionSnippet.isPresent()
+ && multibindingContributionSnippet.get().owningClass().equals(name)) {
+ initializeMethod
+ .body()
+ .addSnippet(
+ "this.%s = %s;",
+ multibindingContributionSnippet.get().getSnippetFor(name),
+ initializeFactoryForProvisionBinding(provisionBinding));
+ }
+ }
+ initializeMember(
+ initializeMethod, bindingKey, initializeMapBinding(provisionBindings));
+ } else {
+ // TODO(beder): Implement producer map bindings.
+ throw new IllegalStateException("producer map bindings not implemented yet");
+ }
+ break;
+ case UNIQUE:
+ if (!resolvedBindings.ownedContributionBindings().isEmpty()) {
+ ContributionBinding binding = Iterables.getOnlyElement(bindings);
+ if (binding instanceof ProvisionBinding) {
+ ProvisionBinding provisionBinding = (ProvisionBinding) binding;
+ if (!provisionBinding.factoryCreationStrategy().equals(ENUM_INSTANCE)
+ || provisionBinding.scope().isPresent()) {
+ initializeDelegateFactories(binding, initializeMethod);
+ initializeMember(
+ initializeMethod,
+ bindingKey,
+ initializeFactoryForProvisionBinding(provisionBinding));
+ }
+ } else if (binding instanceof ProductionBinding) {
+ ProductionBinding productionBinding = (ProductionBinding) binding;
+ initializeMember(
+ initializeMethod,
+ bindingKey,
+ initializeFactoryForProductionBinding(productionBinding));
+ } else {
+ throw new AssertionError();
+ }
+ }
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ break;
+ case MEMBERS_INJECTION:
+ MembersInjectionBinding binding =
+ Iterables.getOnlyElement(resolvedBindings.membersInjectionBindings());
+ if (!binding.injectionStrategy().equals(MembersInjectionBinding.Strategy.NO_OP)) {
+ initializeDelegateFactories(binding, initializeMethod);
+ initializeMember(
+ initializeMethod, bindingKey, initializeMembersInjectorForBinding(binding));
+ }
+ break;
+ default:
+ throw new AssertionError();
+ }
+ }
+ }
+ }
+
+ private void initializeDelegateFactories(Binding binding, MethodWriter initializeMethod) {
+ for (Collection<DependencyRequest> requestsForKey :
+ indexDependenciesByUnresolvedKey(types, binding.dependencies()).asMap().values()) {
+ BindingKey dependencyKey =
+ Iterables.getOnlyElement(
+ FluentIterable.from(requestsForKey)
+ .transform(DependencyRequest.BINDING_KEY_FUNCTION)
+ .toSet());
+ if (!getMemberSelect(dependencyKey).staticMember()
+ && getInitializationState(dependencyKey).equals(UNINITIALIZED)) {
+ initializeMethod
+ .body()
+ .addSnippet(
+ "this.%s = new %s();",
+ getMemberSelectSnippet(dependencyKey),
+ ClassName.fromClass(DelegateFactory.class));
+ setInitializationState(dependencyKey, DELEGATED);
+ }
+ }
+ }
+
+ private void initializeMember(
+ MethodWriter initializeMethod, BindingKey bindingKey, Snippet initializationSnippet) {
+ Snippet memberSelect = getMemberSelectSnippet(bindingKey);
+ Snippet delegateFactoryVariable = delegateFactoryVariableSnippet(bindingKey);
+ if (getInitializationState(bindingKey).equals(DELEGATED)) {
+ initializeMethod
+ .body()
+ .addSnippet(
+ "%1$s %2$s = (%1$s) %3$s;",
+ ClassName.fromClass(DelegateFactory.class),
+ delegateFactoryVariable,
+ memberSelect);
+ }
+ initializeMethod.body().addSnippet("this.%s = %s;", memberSelect, initializationSnippet);
+ if (getInitializationState(bindingKey).equals(DELEGATED)) {
+ initializeMethod
+ .body()
+ .addSnippet("%s.setDelegatedProvider(%s);", delegateFactoryVariable, memberSelect);
+ }
+ setInitializationState(bindingKey, INITIALIZED);
+ }
+
+ private Snippet delegateFactoryVariableSnippet(BindingKey key) {
+ return Snippet.format("%sDelegate", getMemberSelectSnippet(key).toString().replace('.', '_'));
+ }
+
+ private Snippet initializeFactoryForContributionBinding(ContributionBinding binding) {
+ if (binding instanceof ProvisionBinding) {
+ return initializeFactoryForProvisionBinding((ProvisionBinding) binding);
+ } else if (binding instanceof ProductionBinding) {
+ return initializeFactoryForProductionBinding((ProductionBinding) binding);
+ } else {
+ throw new AssertionError();
+ }
+ }
+
+ private Snippet initializeFactoryForProvisionBinding(ProvisionBinding binding) {
+ TypeName bindingKeyTypeName = TypeNames.forTypeMirror(binding.key().type());
+ switch (binding.bindingKind()) {
+ case COMPONENT:
+ return Snippet.format(
+ "%s.<%s>create(%s)",
+ ClassName.fromClass(InstanceFactory.class),
+ bindingKeyTypeName,
+ bindingKeyTypeName.equals(componentDefinitionTypeName())
+ ? "this"
+ : getComponentContributionSnippet(MoreTypes.asTypeElement(binding.key().type())));
+ case COMPONENT_PROVISION:
+ TypeElement bindingTypeElement =
+ graph.componentDescriptor().dependencyMethodIndex().get(binding.bindingElement());
+ if (binding.nullableType().isPresent()
+ || nullableValidationType.equals(Diagnostic.Kind.WARNING)) {
+ Snippet nullableSnippet =
+ binding.nullableType().isPresent()
+ ? Snippet.format("@%s ", TypeNames.forTypeMirror(binding.nullableType().get()))
+ : Snippet.format("");
+ return Snippet.format(
+ Joiner.on('\n')
+ .join(
+ "new %1$s<%2$s>() {",
+ " private final %6$s %7$s = %3$s;",
+ " %5$s@Override public %2$s get() {",
+ " return %7$s.%4$s();",
+ " }",
+ "}"),
+ /* 1 */ ClassName.fromClass(Factory.class),
+ /* 2 */ bindingKeyTypeName,
+ /* 3 */ getComponentContributionSnippet(bindingTypeElement),
+ /* 4 */ binding.bindingElement().getSimpleName().toString(),
+ /* 5 */ nullableSnippet,
+ /* 6 */ TypeNames.forTypeMirror(bindingTypeElement.asType()),
+ /* 7 */ simpleVariableName(bindingTypeElement));
+ } else {
+ // TODO(sameb): This throws a very vague NPE right now. The stack trace doesn't
+ // help to figure out what the method or return type is. If we include a string
+ // of the return type or method name in the error message, that can defeat obfuscation.
+ // We can easily include the raw type (no generics) + annotation type (no values),
+ // using .class & String.format -- but that wouldn't be the whole story.
+ // What should we do?
+ StringLiteral failMsg =
+ StringLiteral.forValue(CANNOT_RETURN_NULL_FROM_NON_NULLABLE_COMPONENT_METHOD);
+ return Snippet.format(
+ Joiner.on('\n')
+ .join(
+ "new %1$s<%2$s>() {",
+ " private final %6$s %7$s = %3$s;",
+ " @Override public %2$s get() {",
+ " %2$s provided = %7$s.%4$s();",
+ " if (provided == null) {",
+ " throw new NullPointerException(%5$s);",
+ " }",
+ " return provided;",
+ " }",
+ "}"),
+ /* 1 */ ClassName.fromClass(Factory.class),
+ /* 2 */ bindingKeyTypeName,
+ /* 3 */ getComponentContributionSnippet(bindingTypeElement),
+ /* 4 */ binding.bindingElement().getSimpleName().toString(),
+ /* 5 */ failMsg,
+ /* 6 */ TypeNames.forTypeMirror(bindingTypeElement.asType()),
+ /* 7 */ simpleVariableName(bindingTypeElement));
+ }
+ case INJECTION:
+ case PROVISION:
+ List<Snippet> parameters =
+ Lists.newArrayListWithCapacity(binding.dependencies().size() + 1);
+ if (binding.bindingKind().equals(PROVISION)
+ && !binding.bindingElement().getModifiers().contains(STATIC)) {
+ parameters.add(getComponentContributionSnippet(binding.contributedBy().get()));
+ }
+ parameters.addAll(getDependencyParameters(binding));
+
+ Snippet factorySnippet =
+ Snippet.format(
+ "%s.create(%s)",
+ factoryNameForProvisionBinding(binding),
+ Snippet.makeParametersSnippet(parameters));
+ return binding.scope().isPresent()
+ ? Snippet.format(
+ "%s.create(%s)", ClassName.fromClass(ScopedProvider.class), factorySnippet)
+ : factorySnippet;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private Snippet initializeFactoryForProductionBinding(ProductionBinding binding) {
+ switch (binding.bindingKind()) {
+ case COMPONENT_PRODUCTION:
+ TypeElement bindingTypeElement =
+ graph.componentDescriptor().dependencyMethodIndex().get(binding.bindingElement());
+ return Snippet.format(
+ Joiner.on('\n')
+ .join(
+ "new %1$s<%2$s>() {",
+ " private final %6$s %7$s = %4$s;",
+ " @Override public %3$s<%2$s> get() {",
+ " return %7$s.%5$s();",
+ " }",
+ "}"),
+ /* 1 */ ClassName.fromClass(Producer.class),
+ /* 2 */ TypeNames.forTypeMirror(binding.key().type()),
+ /* 3 */ ClassName.fromClass(ListenableFuture.class),
+ /* 4 */ getComponentContributionSnippet(bindingTypeElement),
+ /* 5 */ binding.bindingElement().getSimpleName().toString(),
+ /* 6 */ TypeNames.forTypeMirror(bindingTypeElement.asType()),
+ /* 7 */ simpleVariableName(bindingTypeElement));
+ case IMMEDIATE:
+ case FUTURE_PRODUCTION:
+ List<Snippet> parameters =
+ Lists.newArrayListWithCapacity(binding.dependencies().size() + 3);
+ // TODO(beder): Pass the actual ProductionComponentMonitor.
+ parameters.add(Snippet.format("null"));
+ if (!binding.bindingElement().getModifiers().contains(STATIC)) {
+ parameters.add(getComponentContributionSnippet(binding.bindingTypeElement()));
+ }
+ parameters.add(
+ getComponentContributionSnippet(
+ graph.componentDescriptor().executorDependency().get()));
+ parameters.addAll(getProducerDependencyParameters(binding));
+
+ return Snippet.format(
+ "new %s(%s)",
+ factoryNameForProductionBinding(binding),
+ Snippet.makeParametersSnippet(parameters));
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private Snippet initializeMembersInjectorForBinding(MembersInjectionBinding binding) {
+ switch (binding.injectionStrategy()) {
+ case NO_OP:
+ return Snippet.format("%s.noOp()", ClassName.fromClass(MembersInjectors.class));
+ case INJECT_MEMBERS:
+ List<Snippet> parameters = getDependencyParameters(binding);
+ return Snippet.format(
+ "%s.create(%s)",
+ membersInjectorNameForType(binding.bindingElement()),
+ Snippet.makeParametersSnippet(parameters));
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private List<Snippet> getDependencyParameters(Binding binding) {
+ ImmutableList.Builder<Snippet> parameters = ImmutableList.builder();
+ Set<Key> keysSeen = new HashSet<>();
+ for (Collection<DependencyRequest> requestsForKey :
+ indexDependenciesByUnresolvedKey(types, binding.implicitDependencies()).asMap().values()) {
+ Set<BindingKey> requestedBindingKeys = new HashSet<>();
+ for (DependencyRequest dependencyRequest : requestsForKey) {
+ Element requestElement = dependencyRequest.requestElement();
+ TypeMirror typeMirror = typeMirrorAsMemberOf(binding.bindingTypeElement(), requestElement);
+ Key key = keyFactory.forQualifiedType(dependencyRequest.key().qualifier(), typeMirror);
+ if (keysSeen.add(key)) {
+ requestedBindingKeys.add(dependencyRequest.bindingKey());
+ }
+ }
+ if (!requestedBindingKeys.isEmpty()) {
+ BindingKey key = Iterables.getOnlyElement(requestedBindingKeys);
+ parameters.add(getMemberSelect(key).getSnippetWithRawTypeCastFor(name));
+ }
+ }
+ return parameters.build();
+ }
+
+ // TODO(dpb): Investigate use of asMemberOf here. Why aren't the dependency requests already
+ // resolved?
+ private TypeMirror typeMirrorAsMemberOf(TypeElement bindingTypeElement, Element requestElement) {
+ TypeMirror requestType = requestElement.asType();
+ if (requestType.getKind() == TypeKind.TYPEVAR) {
+ return types.asMemberOf(
+ MoreTypes.asDeclared(bindingTypeElement.asType()),
+ (requestElement.getKind() == ElementKind.PARAMETER)
+ ? MoreTypes.asElement(requestType)
+ : requestElement);
+ } else {
+ return requestType;
+ }
+ }
+
+ private List<Snippet> getProducerDependencyParameters(Binding binding) {
+ ImmutableList.Builder<Snippet> parameters = ImmutableList.builder();
+ for (Collection<DependencyRequest> requestsForKey :
+ SourceFiles.indexDependenciesByUnresolvedKey(
+ types, binding.dependencies()).asMap().values()) {
+ BindingKey key = Iterables.getOnlyElement(FluentIterable.from(requestsForKey)
+ .transform(DependencyRequest.BINDING_KEY_FUNCTION));
+ ResolvedBindings resolvedBindings = graph.resolvedBindings().get(key);
+ Class<?> frameworkClass =
+ DependencyRequestMapper.FOR_PRODUCER.getFrameworkClass(requestsForKey);
+ if (FrameworkField.frameworkClassForResolvedBindings(resolvedBindings).equals(Provider.class)
+ && frameworkClass.equals(Producer.class)) {
+ parameters.add(
+ Snippet.format(
+ "%s.producerFromProvider(%s)",
+ ClassName.fromClass(Producers.class),
+ getMemberSelectSnippet(key)));
+ } else {
+ parameters.add(getMemberSelectSnippet(key));
+ }
+ }
+ return parameters.build();
+ }
+
+ private Snippet initializeMapBinding(Set<ProvisionBinding> bindings) {
+ // Get type information from the first binding.
+ ProvisionBinding firstBinding = bindings.iterator().next();
+ DeclaredType mapType = asDeclared(firstBinding.key().type());
+
+ if (isMapWithNonProvidedValues(mapType)) {
+ return Snippet.format(
+ "%s.create(%s)",
+ ClassName.fromClass(MapFactory.class),
+ getMemberSelectSnippet(getOnlyElement(firstBinding.dependencies()).bindingKey()));
+ }
+
+ ImmutableList.Builder<dagger.internal.codegen.writer.Snippet> snippets =
+ ImmutableList.builder();
+ snippets.add(Snippet.format("%s.<%s, %s>builder(%d)",
+ ClassName.fromClass(MapProviderFactory.class),
+ TypeNames.forTypeMirror(getKeyTypeOfMap(mapType)),
+ TypeNames.forTypeMirror(getProvidedValueTypeOfMap(mapType)), // V of Map<K, Provider<V>>
+ bindings.size()));
+
+ for (ProvisionBinding binding : bindings) {
+ snippets.add(
+ Snippet.format(
+ " .put(%s, %s)",
+ getMapKeySnippet(binding.bindingElement()),
+ getMultibindingContributionSnippet(binding).get().getSnippetFor(name)));
+ }
+
+ snippets.add(Snippet.format(" .build()"));
+
+ return Snippet.join(Joiner.on('\n'), snippets.build());
+ }
+
+ private static String simpleVariableName(TypeElement typeElement) {
+ return UPPER_CAMEL.to(LOWER_CAMEL, typeElement.getSimpleName().toString());
+ }
+
+ /**
+ * Initialization state for a factory field.
+ */
+ enum InitializationState {
+ /** The field is {@code null}. */
+ UNINITIALIZED,
+
+ /** The field is set to a {@link DelegateFactory}. */
+ DELEGATED,
+
+ /** The field is set to an undelegated factory. */
+ INITIALIZED;
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/Binding.java b/compiler/src/main/java/dagger/internal/codegen/Binding.java
new file mode 100644
index 000000000..29f17b3c5
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/Binding.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import java.util.List;
+import java.util.Set;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.WildcardType;
+import javax.lang.model.util.SimpleElementVisitor6;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.Types;
+
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+/**
+ * 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 subtypes.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+abstract class Binding {
+ static Optional<String> bindingPackageFor(Iterable<? extends Binding> bindings) {
+ ImmutableSet.Builder<String> bindingPackagesBuilder = ImmutableSet.builder();
+ for (Binding binding : bindings) {
+ bindingPackagesBuilder.addAll(binding.bindingPackage().asSet());
+ }
+ ImmutableSet<String> bindingPackages = bindingPackagesBuilder.build();
+ switch (bindingPackages.size()) {
+ case 0:
+ return Optional.absent();
+ case 1:
+ return Optional.of(bindingPackages.iterator().next());
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /** The {@link Key} that is provided by this binding. */
+ protected abstract Key key();
+
+ /** Returns the {@link Element} instance that is responsible for declaring the binding. */
+ abstract Element bindingElement();
+
+ /** The type enclosing the binding {@link #bindingElement()}. */
+ TypeElement bindingTypeElement() {
+ return BINDING_TYPE_ELEMENT.visit(bindingElement());
+ }
+
+ private static final ElementVisitor<TypeElement, Void> BINDING_TYPE_ELEMENT =
+ new SimpleElementVisitor6<TypeElement, Void>() {
+ @Override
+ protected TypeElement defaultAction(Element e, Void p) {
+ return visit(e.getEnclosingElement());
+ }
+
+ @Override
+ public TypeElement visitType(TypeElement e, Void p) {
+ return e;
+ }
+ };
+
+ /**
+ * The explicit set of {@link DependencyRequest dependencies} required to satisfy this binding.
+ */
+ abstract ImmutableSet<DependencyRequest> dependencies();
+
+ /**
+ * The set of {@link DependencyRequest dependencies} required to satisfy this binding. This is a
+ * superset of {@link #dependencies()}. This returns an unmodifiable set.
+ */
+ abstract Set<DependencyRequest> implicitDependencies();
+
+ /**
+ * Returns the name of the package in which this binding must be managed. E.g.: a binding
+ * may reference non-public types.
+ */
+ abstract Optional<String> bindingPackage();
+
+ protected static Optional<String> findBindingPackage(Key bindingKey) {
+ Set<String> packages = nonPublicPackageUse(bindingKey.type());
+ switch (packages.size()) {
+ case 0:
+ return Optional.absent();
+ case 1:
+ return Optional.of(packages.iterator().next());
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+ private static Set<String> nonPublicPackageUse(TypeMirror typeMirror) {
+ ImmutableSet.Builder<String> packages = ImmutableSet.builder();
+ typeMirror.accept(new SimpleTypeVisitor6<Void, ImmutableSet.Builder<String>>() {
+ @Override
+ public Void visitArray(ArrayType t, ImmutableSet.Builder<String> p) {
+ return t.getComponentType().accept(this, p);
+ }
+
+ @Override
+ public Void visitDeclared(DeclaredType t, ImmutableSet.Builder<String> p) {
+ for (TypeMirror typeArgument : t.getTypeArguments()) {
+ typeArgument.accept(this, p);
+ }
+ // TODO(gak): address public nested types in non-public types
+ TypeElement typeElement = MoreElements.asType(t.asElement());
+ if (!typeElement.getModifiers().contains(PUBLIC)) {
+ PackageElement elementPackage = MoreElements.getPackage(typeElement);
+ Name qualifiedName = elementPackage.getQualifiedName();
+ p.add(qualifiedName.toString());
+ }
+ // Also make sure enclosing types are visible, otherwise we're fooled by
+ // class Foo { public class Bar }
+ // (Note: we can't use t.getEnclosingType() because it doesn't work!)
+ typeElement.getEnclosingElement().asType().accept(this, p);
+ return null;
+ }
+
+ @Override
+ public Void visitWildcard(WildcardType t, ImmutableSet.Builder<String> p) {
+ if (t.getExtendsBound() != null) {
+ t.getExtendsBound().accept(this, p);
+ }
+ if (t.getSuperBound() != null) {
+ t.getSuperBound().accept(this, p);
+ }
+ return null;
+ }
+ }, packages);
+ return packages.build();
+ }
+
+ /**
+ * Returns true if this is a binding for a key that has a different type parameter list than the
+ * element it's providing.
+ */
+ abstract boolean hasNonDefaultTypeParameters();
+
+ // TODO(sameb): Remove the TypeElement parameter and pull it from the TypeMirror.
+ static boolean hasNonDefaultTypeParameters(TypeElement element, TypeMirror type, Types 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/compiler/src/main/java/dagger/internal/codegen/BindingGraph.java b/compiler/src/main/java/dagger/internal/codegen/BindingGraph.java
new file mode 100644
index 000000000..f170f3988
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/BindingGraph.java
@@ -0,0 +1,642 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.collect.TreeTraverser;
+import dagger.Component;
+import dagger.Subcomponent;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.producers.ProductionComponent;
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static com.google.common.base.Predicates.in;
+import static com.google.common.base.Verify.verify;
+import static dagger.internal.codegen.BindingKey.Kind.CONTRIBUTION;
+import static dagger.internal.codegen.ComponentDescriptor.isComponentContributionMethod;
+import static dagger.internal.codegen.ComponentDescriptor.isComponentProductionMethod;
+import static dagger.internal.codegen.ComponentDescriptor.Kind.PRODUCTION_COMPONENT;
+import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies;
+import static dagger.internal.codegen.MembersInjectionBinding.Strategy.INJECT_MEMBERS;
+import static dagger.internal.codegen.MembersInjectionBinding.Strategy.NO_OP;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * The canonical representation of a full-resolved graph.
+ *
+ * @author Gregory Kick
+ */
+@AutoValue
+abstract class BindingGraph {
+ abstract ComponentDescriptor componentDescriptor();
+ abstract ImmutableMap<BindingKey, ResolvedBindings> resolvedBindings();
+ abstract ImmutableMap<ExecutableElement, BindingGraph> subgraphs();
+
+ /**
+ * Returns the set of modules that are owned by this graph regardless of whether or not any of
+ * their bindings are used in this graph. For graphs representing top-level {@link Component
+ * components}, this set will be the same as
+ * {@linkplain ComponentDescriptor#transitiveModules the component's transitive modules}. For
+ * {@linkplain Subcomponent subcomponents}, this set will be the transitive modules that are not
+ * owned by any of their ancestors.
+ */
+ abstract ImmutableSet<ModuleDescriptor> ownedModules();
+
+ ImmutableSet<TypeElement> ownedModuleTypes() {
+ return FluentIterable.from(ownedModules())
+ .transform(ModuleDescriptor.getModuleElement())
+ .toSet();
+ }
+
+ private static final TreeTraverser<BindingGraph> SUBGRAPH_TRAVERSER =
+ new TreeTraverser<BindingGraph>() {
+ @Override
+ public Iterable<BindingGraph> children(BindingGraph node) {
+ return node.subgraphs().values();
+ }
+ };
+
+ /**
+ * Returns the set of types necessary to implement the component, but are not part of the injected
+ * graph. This includes modules, component dependencies and an {@link Executor} in the case of
+ * {@link ProductionComponent}.
+ */
+ ImmutableSet<TypeElement> componentRequirements() {
+ return SUBGRAPH_TRAVERSER.preOrderTraversal(this)
+ .transformAndConcat(new Function<BindingGraph, Iterable<ResolvedBindings>>() {
+ @Override
+ public Iterable<ResolvedBindings> apply(BindingGraph input) {
+ return input.resolvedBindings().values();
+ }
+ })
+ .transformAndConcat(new Function<ResolvedBindings, Set<? extends ContributionBinding>>() {
+ @Override
+ public Set<? extends ContributionBinding> apply(ResolvedBindings input) {
+ return (input.bindingKey().kind().equals(CONTRIBUTION))
+ ? input.contributionBindings()
+ : ImmutableSet.<ContributionBinding>of();
+ }
+ })
+ .transformAndConcat(new Function<ContributionBinding, Set<TypeElement>>() {
+ @Override
+ public Set<TypeElement> apply(ContributionBinding input) {
+ return input.bindingElement().getModifiers().contains(STATIC)
+ ? ImmutableSet.<TypeElement>of()
+ : input.contributedBy().asSet();
+ }
+ })
+ .filter(in(ownedModuleTypes()))
+ .append(componentDescriptor().dependencies())
+ .append(componentDescriptor().executorDependency().asSet())
+ .toSet();
+ }
+
+ ImmutableSet<TypeElement> availableDependencies() {
+ return new ImmutableSet.Builder<TypeElement>()
+ .addAll(componentDescriptor().transitiveModuleTypes())
+ .addAll(componentDescriptor().dependencies())
+ .addAll(componentDescriptor().executorDependency().asSet())
+ .build();
+ }
+
+ static final class Factory {
+ private final Elements elements;
+ private final InjectBindingRegistry injectBindingRegistry;
+ private final Key.Factory keyFactory;
+ private final DependencyRequest.Factory dependencyRequestFactory;
+ private final ProvisionBinding.Factory provisionBindingFactory;
+ private final ProductionBinding.Factory productionBindingFactory;
+
+ Factory(Elements elements,
+ InjectBindingRegistry injectBindingRegistry,
+ Key.Factory keyFactory,
+ DependencyRequest.Factory dependencyRequestFactory,
+ ProvisionBinding.Factory provisionBindingFactory,
+ ProductionBinding.Factory productionBindingFactory) {
+ this.elements = elements;
+ this.injectBindingRegistry = injectBindingRegistry;
+ this.keyFactory = keyFactory;
+ this.dependencyRequestFactory = dependencyRequestFactory;
+ this.provisionBindingFactory = provisionBindingFactory;
+ this.productionBindingFactory = productionBindingFactory;
+ }
+
+ BindingGraph create(ComponentDescriptor componentDescriptor) {
+ return create(Optional.<Resolver>absent(), componentDescriptor);
+ }
+
+ private BindingGraph create(
+ Optional<Resolver> parentResolver, ComponentDescriptor componentDescriptor) {
+ ImmutableSet.Builder<ProvisionBinding> explicitProvisionBindingsBuilder =
+ ImmutableSet.builder();
+ ImmutableSet.Builder<ProductionBinding> explicitProductionBindingsBuilder =
+ ImmutableSet.builder();
+
+ // binding for the component itself
+ TypeElement componentDefinitionType = componentDescriptor.componentDefinitionType();
+ ProvisionBinding componentBinding =
+ provisionBindingFactory.forComponent(componentDefinitionType);
+ explicitProvisionBindingsBuilder.add(componentBinding);
+
+ // Collect Component dependencies.
+ Optional<AnnotationMirror> componentMirror =
+ getAnnotationMirror(componentDefinitionType, Component.class)
+ .or(getAnnotationMirror(componentDefinitionType, ProductionComponent.class));
+ ImmutableSet<TypeElement> componentDependencyTypes = componentMirror.isPresent()
+ ? MoreTypes.asTypeElements(getComponentDependencies(componentMirror.get()))
+ : ImmutableSet.<TypeElement>of();
+ for (TypeElement componentDependency : componentDependencyTypes) {
+ explicitProvisionBindingsBuilder.add(
+ provisionBindingFactory.forComponent(componentDependency));
+ List<ExecutableElement> dependencyMethods =
+ ElementFilter.methodsIn(elements.getAllMembers(componentDependency));
+ for (ExecutableElement method : dependencyMethods) {
+ // MembersInjection methods aren't "provided" explicitly, so ignore them.
+ if (isComponentContributionMethod(elements, method)) {
+ if (componentDescriptor.kind().equals(PRODUCTION_COMPONENT)
+ && isComponentProductionMethod(elements, method)) {
+ explicitProductionBindingsBuilder.add(
+ productionBindingFactory.forComponentMethod(method));
+ } else {
+ explicitProvisionBindingsBuilder.add(
+ provisionBindingFactory.forComponentMethod(method));
+ }
+ }
+ }
+ }
+
+ // Collect transitive module bindings.
+ for (ModuleDescriptor moduleDescriptor : componentDescriptor.transitiveModules()) {
+ for (ContributionBinding binding : moduleDescriptor.bindings()) {
+ if (binding instanceof ProvisionBinding) {
+ explicitProvisionBindingsBuilder.add((ProvisionBinding) binding);
+ }
+ if (binding instanceof ProductionBinding) {
+ explicitProductionBindingsBuilder.add((ProductionBinding) binding);
+ }
+ }
+ }
+
+ Resolver requestResolver =
+ new Resolver(
+ parentResolver,
+ componentDescriptor,
+ explicitBindingsByKey(explicitProvisionBindingsBuilder.build()),
+ explicitBindingsByKey(explicitProductionBindingsBuilder.build()));
+ for (ComponentMethodDescriptor componentMethod : componentDescriptor.componentMethods()) {
+ Optional<DependencyRequest> componentMethodRequest = componentMethod.dependencyRequest();
+ if (componentMethodRequest.isPresent()) {
+ requestResolver.resolve(componentMethodRequest.get());
+ }
+ }
+
+ ImmutableMap.Builder<ExecutableElement, BindingGraph> subgraphsBuilder =
+ ImmutableMap.builder();
+ for (Entry<ComponentMethodDescriptor, ComponentDescriptor> subcomponentEntry :
+ componentDescriptor.subcomponents().entrySet()) {
+ subgraphsBuilder.put(
+ subcomponentEntry.getKey().methodElement(),
+ create(Optional.of(requestResolver), subcomponentEntry.getValue()));
+ }
+
+ for (ResolvedBindings resolvedBindings : requestResolver.getResolvedBindings().values()) {
+ verify(
+ resolvedBindings.owningComponent().equals(componentDescriptor),
+ "%s is not owned by %s",
+ resolvedBindings,
+ componentDescriptor);
+ }
+
+ return new AutoValue_BindingGraph(
+ componentDescriptor,
+ requestResolver.getResolvedBindings(),
+ subgraphsBuilder.build(),
+ requestResolver.getOwnedModules());
+ }
+
+ private <B extends ContributionBinding> ImmutableSetMultimap<Key, B> explicitBindingsByKey(
+ Iterable<? extends B> bindings) {
+ // Multimaps.index() doesn't do ImmutableSetMultimaps.
+ ImmutableSetMultimap.Builder<Key, B> builder = ImmutableSetMultimap.builder();
+ for (B binding : bindings) {
+ builder.put(binding.key(), binding);
+ }
+ return builder.build();
+ }
+
+ private final class Resolver {
+ final Optional<Resolver> parentResolver;
+ final ComponentDescriptor componentDescriptor;
+ final ImmutableSetMultimap<Key, ProvisionBinding> explicitProvisionBindings;
+ final ImmutableSet<ProvisionBinding> explicitProvisionBindingsSet;
+ final ImmutableSetMultimap<Key, ProductionBinding> explicitProductionBindings;
+ final Map<BindingKey, ResolvedBindings> resolvedBindings;
+ final Deque<BindingKey> cycleStack = new ArrayDeque<>();
+ final Cache<BindingKey, Boolean> dependsOnLocalMultibindingsCache =
+ CacheBuilder.newBuilder().<BindingKey, Boolean>build();
+
+ Resolver(
+ Optional<Resolver> parentResolver,
+ ComponentDescriptor componentDescriptor,
+ ImmutableSetMultimap<Key, ProvisionBinding> explicitProvisionBindings,
+ ImmutableSetMultimap<Key, ProductionBinding> explicitProductionBindings) {
+ assert parentResolver != null;
+ this.parentResolver = parentResolver;
+ assert componentDescriptor != null;
+ this.componentDescriptor = componentDescriptor;
+ assert explicitProvisionBindings != null;
+ this.explicitProvisionBindings = explicitProvisionBindings;
+ this.explicitProvisionBindingsSet = ImmutableSet.copyOf(explicitProvisionBindings.values());
+ assert explicitProductionBindings != null;
+ this.explicitProductionBindings = explicitProductionBindings;
+ this.resolvedBindings = Maps.newLinkedHashMap();
+ }
+
+ /**
+ * Looks up the bindings associated with a given dependency request and returns them. In the
+ * event that the binding is owned by a parent component it will trigger resolution in that
+ * component's resolver but will return an {@link Optional#absent} value.
+ */
+ ResolvedBindings lookUpBindings(DependencyRequest request) {
+ BindingKey bindingKey = request.bindingKey();
+ switch (bindingKey.kind()) {
+ case CONTRIBUTION:
+ // First, check for explicit keys (those from modules and components)
+ ImmutableSet<ProvisionBinding> explicitProvisionBindingsForKey =
+ getExplicitProvisionBindings(bindingKey.key());
+ ImmutableSet<ProductionBinding> explicitProductionBindingsForKey =
+ getExplicitProductionBindings(bindingKey.key());
+
+ // If the key is Map<K, V>, get its implicit binding keys, which are either
+ // Map<K, Provider<V>> or Map<K, Producer<V>>, and grab their explicit bindings.
+ Optional<Key> mapProviderKey = keyFactory.implicitMapProviderKeyFrom(bindingKey.key());
+ ImmutableSet<ProvisionBinding> explicitMapProvisionBindings = ImmutableSet.of();
+ if (mapProviderKey.isPresent()) {
+ explicitMapProvisionBindings = getExplicitProvisionBindings(mapProviderKey.get());
+ }
+
+ Optional<Key> mapProducerKey = keyFactory.implicitMapProducerKeyFrom(bindingKey.key());
+ ImmutableSet<ProductionBinding> explicitMapProductionBindings = ImmutableSet.of();
+ if (mapProducerKey.isPresent()) {
+ explicitMapProductionBindings = getExplicitProductionBindings(mapProducerKey.get());
+ }
+
+ if (!explicitProvisionBindingsForKey.isEmpty()
+ || !explicitProductionBindingsForKey.isEmpty()) {
+ // we have some explicit binding for this key, so we collect all explicit implicit map
+ // bindings that might conflict with this and let the validator sort it out
+ ImmutableSet.Builder<ContributionBinding> ownedBindings = ImmutableSet.builder();
+ ImmutableSetMultimap.Builder<ComponentDescriptor, ContributionBinding>
+ inheritedBindings = ImmutableSetMultimap.builder();
+ for (ProvisionBinding provisionBinding :
+ Sets.union(explicitProvisionBindingsForKey, explicitMapProvisionBindings)) {
+ if (isResolvedInParent(request, provisionBinding)
+ && !shouldOwnParentBinding(request, provisionBinding)) {
+ inheritedBindings.put(
+ getOwningResolver(provisionBinding).get().componentDescriptor,
+ provisionBinding);
+ } else {
+ ownedBindings.add(provisionBinding);
+ }
+ }
+ return ResolvedBindings.create(bindingKey,
+ componentDescriptor,
+ ownedBindings
+ .addAll(explicitProductionBindingsForKey)
+ .addAll(explicitMapProductionBindings)
+ .build(),
+ inheritedBindings.build());
+ } else {
+ if (!explicitMapProductionBindings.isEmpty()) {
+ // if we have any explicit Map<K, Producer<V>> bindings, then this Map<K, V> binding
+ // must be considered an implicit ProductionBinding
+ DependencyRequest implicitRequest =
+ dependencyRequestFactory.forImplicitMapBinding(request, mapProducerKey.get());
+ return ResolvedBindings.create(
+ bindingKey,
+ componentDescriptor,
+ productionBindingFactory.forImplicitMapBinding(request, implicitRequest));
+ } else if (!explicitMapProvisionBindings.isEmpty()) {
+ // if there are Map<K, Provider<V>> bindings, then it'll be an implicit
+ // ProvisionBinding
+ DependencyRequest implicitRequest =
+ dependencyRequestFactory.forImplicitMapBinding(request, mapProviderKey.get());
+ return ResolvedBindings.create(
+ bindingKey,
+ componentDescriptor,
+ provisionBindingFactory.forImplicitMapBinding(request, implicitRequest));
+ } else {
+ // no explicit binding, look it up.
+ Optional<ProvisionBinding> provisionBinding =
+ injectBindingRegistry.getOrFindProvisionBinding(bindingKey.key());
+ if (provisionBinding.isPresent()) {
+ if (isResolvedInParent(request, provisionBinding.get())
+ && !shouldOwnParentBinding(request, provisionBinding.get())) {
+ return ResolvedBindings.create(
+ bindingKey,
+ componentDescriptor,
+ ImmutableSet.<Binding>of(),
+ ImmutableSetMultimap.of(
+ getOwningResolver(provisionBinding.get()).get().componentDescriptor,
+ provisionBinding.get()));
+ }
+ }
+ return ResolvedBindings.create(
+ bindingKey,
+ componentDescriptor,
+ provisionBinding.asSet(),
+ ImmutableSetMultimap.<ComponentDescriptor, Binding>of());
+ }
+ }
+ case MEMBERS_INJECTION:
+ // no explicit deps for members injection, so just look it up
+ return ResolvedBindings.create(
+ bindingKey,
+ componentDescriptor,
+ rollUpMembersInjectionBindings(bindingKey.key()));
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Returns {@code true} if {@code provisionBinding} is owned by a parent resolver. If so,
+ * calls {@link #resolve(DependencyRequest) resolve(request)} on that resolver.
+ */
+ private boolean isResolvedInParent(
+ DependencyRequest request, ProvisionBinding provisionBinding) {
+ Optional<Resolver> owningResolver = getOwningResolver(provisionBinding);
+ if (owningResolver.isPresent() && !owningResolver.get().equals(this)) {
+ owningResolver.get().resolve(request);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns {@code true} if {@code provisionBinding}, which was previously resolved by a parent
+ * resolver, should be moved into this resolver's bindings for {@code request} because it is
+ * unscoped and {@linkplain #dependsOnLocalMultibindings(ResolvedBindings) depends on local
+ * multibindings}, or {@code false} if it can satisfy {@code request} as an inherited binding.
+ */
+ private boolean shouldOwnParentBinding(
+ DependencyRequest request, ProvisionBinding provisionBinding) {
+ return !isScoped(provisionBinding)
+ && dependsOnLocalMultibindings(
+ getPreviouslyResolvedBindings(request.bindingKey()).get());
+ }
+
+ private MembersInjectionBinding rollUpMembersInjectionBindings(Key key) {
+ MembersInjectionBinding membersInjectionBinding =
+ injectBindingRegistry.getOrFindMembersInjectionBinding(key);
+
+ if (membersInjectionBinding.parentInjectorRequest().isPresent()
+ && membersInjectionBinding.injectionStrategy().equals(INJECT_MEMBERS)) {
+ MembersInjectionBinding parentBinding =
+ rollUpMembersInjectionBindings(
+ membersInjectionBinding.parentInjectorRequest().get().key());
+ if (parentBinding.injectionStrategy().equals(NO_OP)) {
+ return membersInjectionBinding.withoutParentInjectorRequest();
+ }
+ }
+
+ return membersInjectionBinding;
+ }
+
+ private Optional<Resolver> getOwningResolver(ProvisionBinding provisionBinding) {
+ for (Resolver requestResolver : getResolverLineage().reverse()) {
+ if (requestResolver.explicitProvisionBindingsSet.contains(provisionBinding)) {
+ return Optional.of(requestResolver);
+ }
+ }
+
+ // look for scope separately. we do this for the case where @Singleton can appear twice
+ // in the † compatibility mode
+ Scope bindingScope = provisionBinding.scope();
+ if (bindingScope.isPresent()) {
+ for (Resolver requestResolver : getResolverLineage().reverse()) {
+ if (bindingScope.equals(requestResolver.componentDescriptor.scope())) {
+ return Optional.of(requestResolver);
+ }
+ }
+ }
+ return Optional.absent();
+ }
+
+ /** Returns the resolver lineage from parent to child. */
+ private ImmutableList<Resolver> getResolverLineage() {
+ List<Resolver> resolverList = Lists.newArrayList();
+ for (Optional<Resolver> currentResolver = Optional.of(this);
+ currentResolver.isPresent();
+ currentResolver = currentResolver.get().parentResolver) {
+ resolverList.add(currentResolver.get());
+ }
+ return ImmutableList.copyOf(Lists.reverse(resolverList));
+ }
+
+ private ImmutableSet<ProvisionBinding> getExplicitProvisionBindings(Key requestKey) {
+ ImmutableSet.Builder<ProvisionBinding> explicitBindingsForKey = ImmutableSet.builder();
+ for (Resolver resolver : getResolverLineage()) {
+ explicitBindingsForKey.addAll(resolver.explicitProvisionBindings.get(requestKey));
+ }
+ return explicitBindingsForKey.build();
+ }
+
+ private ImmutableSet<ProductionBinding> getExplicitProductionBindings(Key requestKey) {
+ ImmutableSet.Builder<ProductionBinding> explicitBindingsForKey = ImmutableSet.builder();
+ for (Resolver resolver : getResolverLineage()) {
+ explicitBindingsForKey.addAll(resolver.explicitProductionBindings.get(requestKey));
+ }
+ return explicitBindingsForKey.build();
+ }
+
+ private Optional<ResolvedBindings> getPreviouslyResolvedBindings(
+ final BindingKey bindingKey) {
+ Optional<ResolvedBindings> result = Optional.fromNullable(resolvedBindings.get(bindingKey));
+ if (result.isPresent()) {
+ return result;
+ } else if (parentResolver.isPresent()) {
+ return parentResolver.get().getPreviouslyResolvedBindings(bindingKey);
+ } else {
+ return Optional.absent();
+ }
+ }
+
+ void resolve(DependencyRequest request) {
+ BindingKey bindingKey = request.bindingKey();
+
+ // If we find a cycle, stop resolving. The original request will add it with all of the
+ // other resolved deps.
+ if (cycleStack.contains(bindingKey)) {
+ return;
+ }
+
+ // If the binding was previously resolved in this (sub)component, don't resolve it again.
+ if (resolvedBindings.containsKey(bindingKey)) {
+ return;
+ }
+
+ // If the binding was previously resolved in a supercomponent, then test to see if it
+ // depends on multibindings with contributions from this subcomponent. If it does, then we
+ // have to resolve it in this subcomponent so that it sees the local contributions. If it
+ // does not, then we can stop resolving it in this subcomponent and rely on the
+ // supercomponent resolution.
+ Optional<ResolvedBindings> bindingsPreviouslyResolvedInParent =
+ getPreviouslyResolvedBindings(bindingKey);
+ if (bindingsPreviouslyResolvedInParent.isPresent()
+ && !dependsOnLocalMultibindings(bindingsPreviouslyResolvedInParent.get())) {
+ return;
+ }
+
+ cycleStack.push(bindingKey);
+ try {
+ ResolvedBindings bindings = lookUpBindings(request);
+ for (Binding binding : bindings.ownedBindings()) {
+ for (DependencyRequest dependency : binding.implicitDependencies()) {
+ resolve(dependency);
+ }
+ }
+ resolvedBindings.put(bindingKey, bindings);
+ } finally {
+ cycleStack.pop();
+ }
+ }
+
+ /**
+ * Returns {@code true} if {@code previouslyResolvedBindings} is multibindings with
+ * contributions declared within this (sub)component's modules, or if any of its unscoped
+ * provision-dependencies depend on such local multibindings.
+ *
+ * <p>We don't care about scoped dependencies or production bindings because they will never
+ * depend on multibindings with contributions from subcomponents.
+ */
+ private boolean dependsOnLocalMultibindings(ResolvedBindings previouslyResolvedBindings) {
+ return dependsOnLocalMultibindings(previouslyResolvedBindings, new HashSet<BindingKey>());
+ }
+
+ private boolean dependsOnLocalMultibindings(
+ final ResolvedBindings previouslyResolvedBindings, final Set<BindingKey> cycleChecker) {
+ // Don't recur infinitely if there are valid cycles in the dependency graph.
+ if (!cycleChecker.add(previouslyResolvedBindings.bindingKey())) {
+ return false;
+ }
+ try {
+ return dependsOnLocalMultibindingsCache.get(
+ previouslyResolvedBindings.bindingKey(),
+ new Callable<Boolean>() {
+ @Override
+ public Boolean call() {
+ if (previouslyResolvedBindings.isMultibindings()
+ && hasLocalContributions(previouslyResolvedBindings)) {
+ return true;
+ }
+
+ for (Binding binding : previouslyResolvedBindings.bindings()) {
+ if (!isScoped(binding) && !(binding instanceof ProductionBinding)) {
+ for (DependencyRequest dependency : binding.implicitDependencies()) {
+ if (dependsOnLocalMultibindings(
+ getPreviouslyResolvedBindings(dependency.bindingKey()).get(),
+ cycleChecker)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+ });
+ } catch (ExecutionException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private boolean hasLocalContributions(ResolvedBindings resolvedBindings) {
+ return !explicitProvisionBindings.get(resolvedBindings.bindingKey().key()).isEmpty()
+ || !explicitProductionBindings.get(resolvedBindings.bindingKey().key()).isEmpty();
+ }
+
+ private boolean isScoped(Binding binding) {
+ if (binding instanceof ProvisionBinding) {
+ ProvisionBinding provisionBinding = (ProvisionBinding) binding;
+ return provisionBinding.scope().isPresent();
+ }
+ return false;
+ }
+
+ ImmutableMap<BindingKey, ResolvedBindings> getResolvedBindings() {
+ ImmutableMap.Builder<BindingKey, ResolvedBindings> resolvedBindingsBuilder =
+ ImmutableMap.builder();
+ resolvedBindingsBuilder.putAll(resolvedBindings);
+ if (parentResolver.isPresent()) {
+ Collection<ResolvedBindings> bindingsResolvedInParent =
+ Maps.difference(parentResolver.get().getResolvedBindings(), resolvedBindings)
+ .entriesOnlyOnLeft()
+ .values();
+ for (ResolvedBindings resolvedInParent : bindingsResolvedInParent) {
+ resolvedBindingsBuilder.put(
+ resolvedInParent.bindingKey(),
+ resolvedInParent.asInheritedIn(componentDescriptor));
+ }
+ }
+ return resolvedBindingsBuilder.build();
+ }
+
+ ImmutableSet<ModuleDescriptor> getInheritedModules() {
+ return parentResolver.isPresent()
+ ? Sets.union(
+ parentResolver.get().getInheritedModules(),
+ parentResolver.get().componentDescriptor.transitiveModules())
+ .immutableCopy()
+ : ImmutableSet.<ModuleDescriptor>of();
+ }
+
+ ImmutableSet<ModuleDescriptor> getOwnedModules() {
+ return Sets.difference(componentDescriptor.transitiveModules(), getInheritedModules())
+ .immutableCopy();
+ }
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java b/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java
new file mode 100644
index 000000000..3af59d61b
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java
@@ -0,0 +1,1165 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+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.Iterables;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Ordering;
+import com.google.common.collect.Sets;
+import dagger.Component;
+import dagger.Lazy;
+import dagger.MapKey;
+import dagger.internal.codegen.ComponentDescriptor.BuilderSpec;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.ContributionBinding.BindingType;
+import dagger.internal.codegen.writer.TypeNames;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Formatter;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+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.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;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static com.google.auto.common.MoreTypes.asDeclared;
+import static com.google.common.base.Predicates.equalTo;
+import static com.google.common.base.Predicates.not;
+import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.google.common.collect.Iterables.indexOf;
+import static com.google.common.collect.Iterables.skip;
+import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies;
+import static dagger.internal.codegen.ContributionBinding.indexMapBindingsByAnnotationType;
+import static dagger.internal.codegen.ContributionBinding.indexMapBindingsByMapKey;
+import static dagger.internal.codegen.ErrorMessages.DUPLICATE_SIZE_LIMIT;
+import static dagger.internal.codegen.ErrorMessages.INDENT;
+import static dagger.internal.codegen.ErrorMessages.MEMBERS_INJECTION_WITH_UNBOUNDED_TYPE;
+import static dagger.internal.codegen.ErrorMessages.NULLABLE_TO_NON_NULLABLE;
+import static dagger.internal.codegen.ErrorMessages.REQUIRES_AT_INJECT_CONSTRUCTOR_OR_PROVIDER_FORMAT;
+import static dagger.internal.codegen.ErrorMessages.REQUIRES_AT_INJECT_CONSTRUCTOR_OR_PROVIDER_OR_PRODUCER_FORMAT;
+import static dagger.internal.codegen.ErrorMessages.REQUIRES_PROVIDER_FORMAT;
+import static dagger.internal.codegen.ErrorMessages.REQUIRES_PROVIDER_OR_PRODUCER_FORMAT;
+import static dagger.internal.codegen.ErrorMessages.duplicateMapKeysError;
+import static dagger.internal.codegen.ErrorMessages.inconsistentMapKeyAnnotationsError;
+import static dagger.internal.codegen.ErrorMessages.stripCommonTypePrefixes;
+import static dagger.internal.codegen.Util.getKeyTypeOfMap;
+import static dagger.internal.codegen.Util.getProvidedValueTypeOfMap;
+import static dagger.internal.codegen.Util.getValueTypeOfMap;
+import static dagger.internal.codegen.Util.isMapWithNonProvidedValues;
+import static dagger.internal.codegen.Util.isMapWithProvidedValues;
+import static javax.tools.Diagnostic.Kind.ERROR;
+import static javax.tools.Diagnostic.Kind.WARNING;
+
+public class BindingGraphValidator {
+
+ private final Types types;
+ private final InjectBindingRegistry injectBindingRegistry;
+ private final ValidationType scopeCycleValidationType;
+ private final Diagnostic.Kind nullableValidationType;
+ private final ProvisionBindingFormatter provisionBindingFormatter;
+ private final ProductionBindingFormatter productionBindingFormatter;
+ private final MethodSignatureFormatter methodSignatureFormatter;
+ private final DependencyRequestFormatter dependencyRequestFormatter;
+ private final KeyFormatter keyFormatter;
+
+ BindingGraphValidator(
+ Types types,
+ InjectBindingRegistry injectBindingRegistry,
+ ValidationType scopeCycleValidationType,
+ Diagnostic.Kind nullableValidationType,
+ ProvisionBindingFormatter provisionBindingFormatter,
+ ProductionBindingFormatter productionBindingFormatter,
+ MethodSignatureFormatter methodSignatureFormatter,
+ DependencyRequestFormatter dependencyRequestFormatter,
+ KeyFormatter keyFormatter) {
+ this.types = types;
+ this.injectBindingRegistry = injectBindingRegistry;
+ this.scopeCycleValidationType = scopeCycleValidationType;
+ this.nullableValidationType = nullableValidationType;
+ this.provisionBindingFormatter = provisionBindingFormatter;
+ this.productionBindingFormatter = productionBindingFormatter;
+ this.methodSignatureFormatter = methodSignatureFormatter;
+ this.dependencyRequestFormatter = dependencyRequestFormatter;
+ this.keyFormatter = keyFormatter;
+ }
+
+ private class Validation {
+ final BindingGraph topLevelGraph;
+ final BindingGraph subject;
+ final ValidationReport.Builder<TypeElement> reportBuilder;
+
+ Validation(BindingGraph topLevelGraph, BindingGraph subject) {
+ this.topLevelGraph = topLevelGraph;
+ this.subject = subject;
+ this.reportBuilder =
+ ValidationReport.about(subject.componentDescriptor().componentDefinitionType());
+ }
+
+ Validation(BindingGraph topLevelGraph) {
+ this(topLevelGraph, topLevelGraph);
+ }
+
+ ValidationReport<TypeElement> buildReport() {
+ return reportBuilder.build();
+ }
+
+ void validateSubgraph() {
+ validateComponentScope();
+ validateDependencyScopes();
+ validateComponentHierarchy();
+ validateBuilders();
+
+ for (ComponentMethodDescriptor componentMethod :
+ subject.componentDescriptor().componentMethods()) {
+ Optional<DependencyRequest> entryPoint = componentMethod.dependencyRequest();
+ if (entryPoint.isPresent()) {
+ traverseRequest(
+ entryPoint.get(),
+ new ArrayDeque<ResolvedRequest>(),
+ new LinkedHashSet<BindingKey>(),
+ subject,
+ new HashSet<DependencyRequest>());
+ }
+ }
+
+ for (BindingGraph subgraph : subject.subgraphs().values()) {
+ Validation subgraphValidation =
+ new Validation(topLevelGraph, subgraph);
+ subgraphValidation.validateSubgraph();
+ reportBuilder.addSubreport(subgraphValidation.buildReport());
+ }
+ }
+
+ /**
+ * Traverse the resolved dependency requests, validating resolved bindings, and reporting any
+ * cycles found.
+ *
+ * @param request the current dependency request
+ * @param bindingPath the dependency request path from the parent of {@code request} at the head
+ * up to the root dependency request from the component method at the tail
+ * @param keysInPath the binding keys corresponding to the dependency requests in
+ * {@code bindingPath}, but in reverse order: the first element is the binding key from the
+ * component method
+ * @param resolvedRequests the requests that have already been resolved, so we can avoid
+ * traversing that part of the graph again
+ */
+ // TODO(dpb): It might be simpler to invert bindingPath's order.
+ private void traverseRequest(
+ DependencyRequest request,
+ Deque<ResolvedRequest> bindingPath,
+ LinkedHashSet<BindingKey> keysInPath,
+ BindingGraph graph,
+ Set<DependencyRequest> resolvedRequests) {
+ verify(bindingPath.size() == keysInPath.size(),
+ "mismatched path vs keys -- (%s vs %s)", bindingPath, keysInPath);
+ BindingKey requestKey = request.bindingKey();
+ if (keysInPath.contains(requestKey)) {
+ reportCycle(
+ // Invert bindingPath to match keysInPath's order
+ ImmutableList.copyOf(bindingPath).reverse(),
+ request,
+ indexOf(keysInPath, equalTo(requestKey)));
+ return;
+ }
+
+ // If request has already been resolved, avoid re-traversing the binding path.
+ if (resolvedRequests.add(request)) {
+ ResolvedRequest resolvedRequest = ResolvedRequest.create(request, graph);
+ bindingPath.push(resolvedRequest);
+ keysInPath.add(requestKey);
+ validateResolvedBinding(bindingPath, resolvedRequest.binding());
+
+ for (Binding binding : resolvedRequest.binding().bindings()) {
+ for (DependencyRequest nextRequest : binding.implicitDependencies()) {
+ traverseRequest(nextRequest, bindingPath, keysInPath, graph, resolvedRequests);
+ }
+ }
+ bindingPath.poll();
+ keysInPath.remove(requestKey);
+ }
+ }
+
+ /**
+ * Validates that the set of bindings resolved is consistent with the type of the binding, and
+ * returns true if the bindings are valid.
+ */
+ private boolean validateResolvedBinding(
+ Deque<ResolvedRequest> path, ResolvedBindings resolvedBinding) {
+ if (resolvedBinding.bindings().isEmpty()) {
+ reportMissingBinding(path);
+ return false;
+ }
+
+ ImmutableSet.Builder<ProvisionBinding> provisionBindingsBuilder =
+ ImmutableSet.builder();
+ ImmutableSet.Builder<ProductionBinding> productionBindingsBuilder =
+ ImmutableSet.builder();
+ ImmutableSet.Builder<MembersInjectionBinding> membersInjectionBindingsBuilder =
+ ImmutableSet.builder();
+ for (Binding binding : resolvedBinding.bindings()) {
+ if (binding instanceof ProvisionBinding) {
+ provisionBindingsBuilder.add((ProvisionBinding) binding);
+ }
+ if (binding instanceof ProductionBinding) {
+ productionBindingsBuilder.add((ProductionBinding) binding);
+ }
+ if (binding instanceof MembersInjectionBinding) {
+ membersInjectionBindingsBuilder.add((MembersInjectionBinding) binding);
+ }
+ }
+ ImmutableSet<ProvisionBinding> provisionBindings = provisionBindingsBuilder.build();
+ ImmutableSet<ProductionBinding> productionBindings = productionBindingsBuilder.build();
+ ImmutableSet<MembersInjectionBinding> membersInjectionBindings =
+ membersInjectionBindingsBuilder.build();
+
+ switch (resolvedBinding.bindingKey().kind()) {
+ case CONTRIBUTION:
+ if (!membersInjectionBindings.isEmpty()) {
+ throw new IllegalArgumentException(
+ "contribution binding keys should never have members injection bindings");
+ }
+ Set<ContributionBinding> combined = Sets.union(provisionBindings, productionBindings);
+ if (!validateNullability(path.peek().request(), combined)) {
+ return false;
+ }
+ if (!productionBindings.isEmpty() && doesPathRequireProvisionOnly(path)) {
+ reportProviderMayNotDependOnProducer(path);
+ return false;
+ }
+ if (combined.size() <= 1) {
+ return true;
+ }
+ ImmutableListMultimap<BindingType, ContributionBinding> bindingsByType =
+ ContributionBinding.bindingTypesFor(combined);
+ if (bindingsByType.keySet().size() > 1) {
+ reportMultipleBindingTypes(path);
+ return false;
+ }
+ switch (getOnlyElement(bindingsByType.keySet())) {
+ case UNIQUE:
+ reportDuplicateBindings(path);
+ return false;
+ case MAP:
+ boolean duplicateMapKeys = hasDuplicateMapKeys(path, combined);
+ boolean inconsistentMapKeyAnnotationTypes =
+ hasInconsistentMapKeyAnnotationTypes(path, combined);
+ return !duplicateMapKeys && !inconsistentMapKeyAnnotationTypes;
+ case SET:
+ break;
+ default:
+ throw new AssertionError();
+ }
+ break;
+ case MEMBERS_INJECTION:
+ if (!provisionBindings.isEmpty() || !productionBindings.isEmpty()) {
+ throw new IllegalArgumentException(
+ "members injection binding keys should never have contribution bindings");
+ }
+ if (membersInjectionBindings.size() > 1) {
+ reportDuplicateBindings(path);
+ return false;
+ }
+ if (membersInjectionBindings.size() == 1) {
+ MembersInjectionBinding binding = getOnlyElement(membersInjectionBindings);
+ if (!validateMembersInjectionBinding(binding, path)) {
+ return false;
+ }
+ }
+ break;
+ default:
+ throw new AssertionError();
+ }
+ return true;
+ }
+
+ /** Ensures that if the request isn't nullable, then each contribution is also not nullable. */
+ private boolean validateNullability(
+ DependencyRequest request, Set<ContributionBinding> bindings) {
+ boolean valid = true;
+ if (!request.isNullable()) {
+ String typeName = null;
+ for (ContributionBinding binding : bindings) {
+ if (binding.nullableType().isPresent()) {
+ String methodSignature;
+ if (binding instanceof ProvisionBinding) {
+ ProvisionBinding provisionBinding = (ProvisionBinding) binding;
+ methodSignature = provisionBindingFormatter.format(provisionBinding);
+ } else {
+ ProductionBinding productionBinding = (ProductionBinding) binding;
+ methodSignature = productionBindingFormatter.format(productionBinding);
+ }
+ // Note: the method signature will include the @Nullable in it!
+ // TODO(sameb): Sometimes javac doesn't include the Element in its output.
+ // (Maybe this happens if the code was already compiled before this point?)
+ // ... we manually print ouf the request in that case, otherwise the error
+ // message is kind of useless.
+ if (typeName == null) {
+ typeName = TypeNames.forTypeMirror(request.key().type()).toString();
+ }
+ reportBuilder.addItem(
+ String.format(NULLABLE_TO_NON_NULLABLE, typeName, methodSignature)
+ + "\n at: " + dependencyRequestFormatter.format(request),
+ nullableValidationType,
+ request.requestElement());
+ valid = false;
+ }
+ }
+ }
+ return valid;
+ }
+
+ /**
+ * Returns {@code true} (and reports errors) if {@code mapBindings} has more than one binding
+ * for the same map key.
+ */
+ private boolean hasDuplicateMapKeys(
+ Deque<ResolvedRequest> path, Set<ContributionBinding> mapBindings) {
+ boolean hasDuplicateMapKeys = false;
+ for (Collection<ContributionBinding> mapBindingsForMapKey :
+ indexMapBindingsByMapKey(mapBindings).asMap().values()) {
+ if (mapBindingsForMapKey.size() > 1) {
+ hasDuplicateMapKeys = true;
+ reportDuplicateMapKeys(path, mapBindingsForMapKey);
+ }
+ }
+ return hasDuplicateMapKeys;
+ }
+
+ /**
+ * Returns {@code true} (and reports errors) if {@code mapBindings} uses more than one
+ * {@link MapKey} annotation type.
+ */
+ private boolean hasInconsistentMapKeyAnnotationTypes(
+ Deque<ResolvedRequest> path, Set<ContributionBinding> mapBindings) {
+ ImmutableSetMultimap<Equivalence.Wrapper<DeclaredType>, ContributionBinding>
+ mapBindingsByAnnotationType = indexMapBindingsByAnnotationType(mapBindings);
+ if (mapBindingsByAnnotationType.keySet().size() > 1) {
+ reportInconsistentMapKeyAnnotations(path, mapBindingsByAnnotationType);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Validates a members injection binding, returning false (and reporting the error) if it wasn't
+ * valid.
+ */
+ private boolean validateMembersInjectionBinding(
+ MembersInjectionBinding binding, final Deque<ResolvedRequest> path) {
+ return binding
+ .key()
+ .type()
+ .accept(
+ new SimpleTypeVisitor6<Boolean, Void>() {
+ @Override
+ protected Boolean defaultAction(TypeMirror e, Void p) {
+ reportBuilder.addError(
+ "Invalid members injection request.", path.peek().request().requestElement());
+ return false;
+ }
+
+ @Override
+ public Boolean visitDeclared(DeclaredType type, Void ignored) {
+ // 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. If the arg was an array, validate the type
+ // of the array.
+ for (TypeMirror arg : type.getTypeArguments()) {
+ boolean declared;
+ switch (arg.getKind()) {
+ case ARRAY:
+ declared =
+ MoreTypes.asArray(arg)
+ .getComponentType()
+ .accept(
+ new SimpleTypeVisitor6<Boolean, Void>() {
+ @Override
+ protected Boolean defaultAction(TypeMirror e, Void p) {
+ return false;
+ }
+
+ @Override
+ public Boolean visitDeclared(DeclaredType t, Void p) {
+ for (TypeMirror arg : t.getTypeArguments()) {
+ if (!arg.accept(this, null)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public Boolean visitArray(ArrayType t, Void p) {
+ return t.getComponentType().accept(this, null);
+ }
+
+ @Override
+ public Boolean visitPrimitive(PrimitiveType t, Void p) {
+ return true;
+ }
+ },
+ null);
+ break;
+ case DECLARED:
+ declared = true;
+ break;
+ default:
+ declared = false;
+ }
+ if (!declared) {
+ ImmutableList<String> printableDependencyPath =
+ FluentIterable.from(path)
+ .transform(REQUEST_FROM_RESOLVED_REQUEST)
+ .transform(dependencyRequestFormatter)
+ .filter(Predicates.not(Predicates.equalTo("")))
+ .toList()
+ .reverse();
+ reportBuilder.addError(
+ String.format(
+ MEMBERS_INJECTION_WITH_UNBOUNDED_TYPE,
+ arg.toString(),
+ type.toString(),
+ Joiner.on('\n').join(printableDependencyPath)),
+ path.peek().request().requestElement());
+ return false;
+ }
+ }
+
+ TypeElement element = MoreElements.asType(type.asElement());
+ // 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.)
+ if (!MoreTypes.asDeclared(element.asType()).getTypeArguments().isEmpty()
+ && types.isSameType(types.erasure(element.asType()), type)) {
+ ImmutableList<String> printableDependencyPath =
+ FluentIterable.from(path)
+ .transform(REQUEST_FROM_RESOLVED_REQUEST)
+ .transform(dependencyRequestFormatter)
+ .filter(Predicates.not(Predicates.equalTo("")))
+ .toList()
+ .reverse();
+ reportBuilder.addError(
+ String.format(
+ ErrorMessages.MEMBERS_INJECTION_WITH_RAW_TYPE,
+ type.toString(),
+ Joiner.on('\n').join(printableDependencyPath)),
+ path.peek().request().requestElement());
+ return false;
+ }
+
+ return true; // valid
+ }
+ },
+ null);
+ }
+
+ /**
+ * Validates that component dependencies do not form a cycle.
+ */
+ private void validateComponentHierarchy() {
+ ComponentDescriptor descriptor = subject.componentDescriptor();
+ TypeElement componentType = descriptor.componentDefinitionType();
+ validateComponentHierarchy(componentType, componentType, new ArrayDeque<TypeElement>());
+ }
+
+ /**
+ * Recursive method to validate that component dependencies do not form a cycle.
+ */
+ private void validateComponentHierarchy(
+ TypeElement rootComponent,
+ TypeElement componentType,
+ Deque<TypeElement> componentStack) {
+
+ if (componentStack.contains(componentType)) {
+ // Current component has already appeared in the component chain.
+ StringBuilder message = new StringBuilder();
+ message.append(rootComponent.getQualifiedName());
+ message.append(" contains a cycle in its component dependencies:\n");
+ componentStack.push(componentType);
+ appendIndentedComponentsList(message, componentStack);
+ componentStack.pop();
+ reportBuilder.addItem(message.toString(),
+ scopeCycleValidationType.diagnosticKind().get(),
+ rootComponent, getAnnotationMirror(rootComponent, Component.class).get());
+ } else {
+ Optional<AnnotationMirror> componentAnnotation =
+ getAnnotationMirror(componentType, Component.class);
+ if (componentAnnotation.isPresent()) {
+ componentStack.push(componentType);
+
+ ImmutableSet<TypeElement> dependencies =
+ MoreTypes.asTypeElements(getComponentDependencies(componentAnnotation.get()));
+ for (TypeElement dependency : dependencies) {
+ validateComponentHierarchy(rootComponent, dependency, componentStack);
+ }
+
+ componentStack.pop();
+ }
+ }
+ }
+
+ /**
+ * Validates that among the dependencies are at most one scoped dependency,
+ * that there are no cycles within the scoping chain, and that singleton
+ * components have no scoped dependencies.
+ */
+ private void validateDependencyScopes() {
+ ComponentDescriptor descriptor = subject.componentDescriptor();
+ Scope scope = descriptor.scope();
+ ImmutableSet<TypeElement> scopedDependencies = scopedTypesIn(descriptor.dependencies());
+ if (scope.isPresent()) {
+ // Dagger 1.x scope compatibility requires this be suppress-able.
+ if (scopeCycleValidationType.diagnosticKind().isPresent()
+ && scope.isSingleton()) {
+ // Singleton is a special-case representing the longest lifetime, and therefore
+ // @Singleton components may not depend on scoped components
+ if (!scopedDependencies.isEmpty()) {
+ StringBuilder message = new StringBuilder(
+ "This @Singleton component cannot depend on scoped components:\n");
+ appendIndentedComponentsList(message, scopedDependencies);
+ reportBuilder.addItem(message.toString(),
+ scopeCycleValidationType.diagnosticKind().get(),
+ descriptor.componentDefinitionType(),
+ descriptor.componentAnnotation());
+ }
+ } else if (scopedDependencies.size() > 1) {
+ // Scoped components may depend on at most one scoped component.
+ StringBuilder message = new StringBuilder(scope.getReadableSource())
+ .append(' ')
+ .append(descriptor.componentDefinitionType().getQualifiedName())
+ .append(" depends on more than one scoped component:\n");
+ appendIndentedComponentsList(message, scopedDependencies);
+ reportBuilder.addError(
+ message.toString(),
+ descriptor.componentDefinitionType(),
+ descriptor.componentAnnotation());
+ } else {
+ // Dagger 1.x scope compatibility requires this be suppress-able.
+ if (!scopeCycleValidationType.equals(ValidationType.NONE)) {
+ validateScopeHierarchy(descriptor.componentDefinitionType(),
+ descriptor.componentDefinitionType(),
+ new ArrayDeque<Scope>(),
+ new ArrayDeque<TypeElement>());
+ }
+ }
+ } else {
+ // Scopeless components may not depend on scoped components.
+ if (!scopedDependencies.isEmpty()) {
+ StringBuilder message =
+ new StringBuilder(descriptor.componentDefinitionType().getQualifiedName())
+ .append(" (unscoped) cannot depend on scoped components:\n");
+ appendIndentedComponentsList(message, scopedDependencies);
+ reportBuilder.addError(
+ message.toString(),
+ descriptor.componentDefinitionType(),
+ descriptor.componentAnnotation());
+ }
+ }
+ }
+
+ private void validateBuilders() {
+ ComponentDescriptor componentDesc = subject.componentDescriptor();
+ if (!componentDesc.builderSpec().isPresent()) {
+ // If no builder, nothing to validate.
+ return;
+ }
+
+ Set<TypeElement> availableDependencies = subject.availableDependencies();
+ Set<TypeElement> requiredDependencies =
+ Sets.filter(
+ availableDependencies,
+ new Predicate<TypeElement>() {
+ @Override
+ public boolean apply(TypeElement input) {
+ return !Util.componentCanMakeNewInstances(input);
+ }
+ });
+ final BuilderSpec spec = componentDesc.builderSpec().get();
+ Map<TypeElement, ExecutableElement> allSetters = spec.methodMap();
+
+ ErrorMessages.ComponentBuilderMessages msgs =
+ ErrorMessages.builderMsgsFor(subject.componentDescriptor().kind());
+ Set<TypeElement> extraSetters = Sets.difference(allSetters.keySet(), availableDependencies);
+ if (!extraSetters.isEmpty()) {
+ Collection<ExecutableElement> excessMethods =
+ Maps.filterKeys(allSetters, Predicates.in(extraSetters)).values();
+ Iterable<String> formatted = FluentIterable.from(excessMethods).transform(
+ new Function<ExecutableElement, String>() {
+ @Override public String apply(ExecutableElement input) {
+ return methodSignatureFormatter.format(input,
+ Optional.of(MoreTypes.asDeclared(spec.builderDefinitionType().asType())));
+ }});
+ reportBuilder.addError(
+ String.format(msgs.extraSetters(), formatted), spec.builderDefinitionType());
+ }
+
+ Set<TypeElement> missingSetters = Sets.difference(requiredDependencies, allSetters.keySet());
+ if (!missingSetters.isEmpty()) {
+ reportBuilder.addError(
+ String.format(msgs.missingSetters(), missingSetters), spec.builderDefinitionType());
+ }
+ }
+
+ /**
+ * Validates that scopes do not participate in a scoping cycle - that is to say, scoped
+ * components are in a hierarchical relationship terminating with Singleton.
+ *
+ * <p>As a side-effect, this means scoped components cannot have a dependency cycle between
+ * themselves, since a component's presence within its own dependency path implies a cyclical
+ * relationship between scopes. However, cycles in component dependencies are explicitly
+ * checked in {@link #validateComponentHierarchy()}.
+ */
+ private void validateScopeHierarchy(TypeElement rootComponent,
+ TypeElement componentType,
+ Deque<Scope> scopeStack,
+ Deque<TypeElement> scopedDependencyStack) {
+ Scope scope = Scope.scopeOf(componentType);
+ if (scope.isPresent()) {
+ if (scopeStack.contains(scope)) {
+ scopedDependencyStack.push(componentType);
+ // Current scope has already appeared in the component chain.
+ StringBuilder message = new StringBuilder();
+ message.append(rootComponent.getQualifiedName());
+ message.append(" depends on scoped components in a non-hierarchical scope ordering:\n");
+ appendIndentedComponentsList(message, scopedDependencyStack);
+ if (scopeCycleValidationType.diagnosticKind().isPresent()) {
+ reportBuilder.addItem(message.toString(),
+ scopeCycleValidationType.diagnosticKind().get(),
+ rootComponent, getAnnotationMirror(rootComponent, Component.class).get());
+ }
+ scopedDependencyStack.pop();
+ } else {
+ Optional<AnnotationMirror> componentAnnotation =
+ getAnnotationMirror(componentType, Component.class);
+ if (componentAnnotation.isPresent()) {
+ ImmutableSet<TypeElement> scopedDependencies = scopedTypesIn(
+ MoreTypes.asTypeElements(getComponentDependencies(componentAnnotation.get())));
+ if (scopedDependencies.size() == 1) {
+ // empty can be ignored (base-case), and > 1 is a different error reported separately.
+ scopeStack.push(scope);
+ scopedDependencyStack.push(componentType);
+ validateScopeHierarchy(rootComponent, getOnlyElement(scopedDependencies),
+ scopeStack, scopedDependencyStack);
+ scopedDependencyStack.pop();
+ scopeStack.pop();
+ }
+ } // else: we skip component dependencies which are not components
+ }
+ }
+ }
+
+ /**
+ * Validates that the scope (if any) of this component are compatible with the scopes of the
+ * bindings available in this component
+ */
+ void validateComponentScope() {
+ ImmutableMap<BindingKey, ResolvedBindings> resolvedBindings = subject.resolvedBindings();
+ Scope componentScope = subject.componentDescriptor().scope();
+ ImmutableSet.Builder<String> incompatiblyScopedMethodsBuilder = ImmutableSet.builder();
+ for (ResolvedBindings bindings : resolvedBindings.values()) {
+ if (bindings.bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION)) {
+ for (ContributionBinding contributionBinding : bindings.ownedContributionBindings()) {
+ if (contributionBinding instanceof ProvisionBinding) {
+ ProvisionBinding provisionBinding = (ProvisionBinding) contributionBinding;
+ Scope bindingScope = provisionBinding.scope();
+ if (bindingScope.isPresent() && !componentScope.equals(bindingScope)) {
+ // Scoped components cannot reference bindings to @Provides methods or @Inject
+ // types decorated by a different scope annotation. Unscoped components cannot
+ // reference to scoped @Provides methods or @Inject types decorated by any
+ // scope annotation.
+ switch (provisionBinding.bindingKind()) {
+ case PROVISION:
+ ExecutableElement provisionMethod =
+ MoreElements.asExecutable(provisionBinding.bindingElement());
+ incompatiblyScopedMethodsBuilder.add(
+ methodSignatureFormatter.format(provisionMethod));
+ break;
+ case INJECTION:
+ incompatiblyScopedMethodsBuilder.add(bindingScope.getReadableSource()
+ + " class " + provisionBinding.bindingTypeElement().getQualifiedName());
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ }
+ }
+ }
+ }
+ }
+ ImmutableSet<String> incompatiblyScopedMethods = incompatiblyScopedMethodsBuilder.build();
+ if (!incompatiblyScopedMethods.isEmpty()) {
+ TypeElement componentType = subject.componentDescriptor().componentDefinitionType();
+ StringBuilder message = new StringBuilder(componentType.getQualifiedName());
+ if (componentScope.isPresent()) {
+ message.append(" scoped with ");
+ message.append(componentScope.getReadableSource());
+ message.append(" may not reference bindings with different scopes:\n");
+ } else {
+ message.append(" (unscoped) may not reference scoped bindings:\n");
+ }
+ for (String method : incompatiblyScopedMethods) {
+ message.append(ErrorMessages.INDENT).append(method).append("\n");
+ }
+ reportBuilder.addError(
+ message.toString(), componentType, subject.componentDescriptor().componentAnnotation());
+ }
+ }
+
+ @SuppressWarnings("resource") // Appendable is a StringBuilder.
+ private void reportProviderMayNotDependOnProducer(Deque<ResolvedRequest> path) {
+ StringBuilder errorMessage = new StringBuilder();
+ if (path.size() == 1) {
+ new Formatter(errorMessage)
+ .format(
+ ErrorMessages.PROVIDER_ENTRY_POINT_MAY_NOT_DEPEND_ON_PRODUCER_FORMAT,
+ formatRootRequestKey(path));
+ } else {
+ ImmutableSet<ProvisionBinding> dependentProvisions =
+ provisionsDependingOnLatestRequest(path);
+ // TODO(beder): Consider displaying all dependent provisions in the error message. If we do
+ // that, should we display all productions that depend on them also?
+ new Formatter(errorMessage).format(ErrorMessages.PROVIDER_MAY_NOT_DEPEND_ON_PRODUCER_FORMAT,
+ keyFormatter.format(dependentProvisions.iterator().next().key()));
+ }
+ reportBuilder.addError(errorMessage.toString(), path.getLast().request().requestElement());
+ }
+
+ private void reportMissingBinding(Deque<ResolvedRequest> path) {
+ Key key = path.peek().request().key();
+ BindingKey bindingKey = path.peek().request().bindingKey();
+ TypeMirror type = key.type();
+ String typeName = TypeNames.forTypeMirror(type).toString();
+ boolean requiresContributionMethod = !key.isValidImplicitProvisionKey(types);
+ boolean requiresProvision = doesPathRequireProvisionOnly(path);
+ StringBuilder errorMessage = new StringBuilder();
+ String requiresErrorMessageFormat = requiresContributionMethod
+ ? requiresProvision
+ ? REQUIRES_PROVIDER_FORMAT
+ : REQUIRES_PROVIDER_OR_PRODUCER_FORMAT
+ : requiresProvision
+ ? REQUIRES_AT_INJECT_CONSTRUCTOR_OR_PROVIDER_FORMAT
+ : REQUIRES_AT_INJECT_CONSTRUCTOR_OR_PROVIDER_OR_PRODUCER_FORMAT;
+ errorMessage.append(String.format(requiresErrorMessageFormat, typeName));
+ if (key.isValidMembersInjectionKey()
+ && !injectBindingRegistry.getOrFindMembersInjectionBinding(key).injectionSites()
+ .isEmpty()) {
+ errorMessage.append(" ").append(ErrorMessages.MEMBERS_INJECTION_DOES_NOT_IMPLY_PROVISION);
+ }
+ ImmutableList<String> printableDependencyPath =
+ FluentIterable.from(path)
+ .transform(REQUEST_FROM_RESOLVED_REQUEST)
+ .transform(dependencyRequestFormatter)
+ .filter(Predicates.not(Predicates.equalTo("")))
+ .toList()
+ .reverse();
+ for (String dependency :
+ printableDependencyPath.subList(1, printableDependencyPath.size())) {
+ errorMessage.append('\n').append(dependency);
+ }
+ for (String suggestion : MissingBindingSuggestions.forKey(topLevelGraph, bindingKey)) {
+ errorMessage.append('\n').append(suggestion);
+ }
+ reportBuilder.addError(errorMessage.toString(), path.getLast().request().requestElement());
+ }
+
+ @SuppressWarnings("resource") // Appendable is a StringBuilder.
+ private void reportDuplicateBindings(Deque<ResolvedRequest> path) {
+ ResolvedBindings resolvedBinding = path.peek().binding();
+ StringBuilder builder = new StringBuilder();
+ new Formatter(builder)
+ .format(ErrorMessages.DUPLICATE_BINDINGS_FOR_KEY_FORMAT, formatRootRequestKey(path));
+ for (Binding binding : Iterables.limit(resolvedBinding.bindings(), DUPLICATE_SIZE_LIMIT)) {
+ builder.append('\n').append(INDENT).append(formatBinding(binding));
+ }
+ int numberOfOtherBindings = resolvedBinding.bindings().size() - DUPLICATE_SIZE_LIMIT;
+ if (numberOfOtherBindings > 0) {
+ builder.append('\n').append(INDENT)
+ .append("and ").append(numberOfOtherBindings).append(" other");
+ }
+ if (numberOfOtherBindings > 1) {
+ builder.append('s');
+ }
+ reportBuilder.addError(builder.toString(), path.getLast().request().requestElement());
+ }
+
+ @SuppressWarnings("resource") // Appendable is a StringBuilder.
+ private void reportMultipleBindingTypes(Deque<ResolvedRequest> path) {
+ ResolvedBindings resolvedBinding = path.peek().binding();
+ StringBuilder builder = new StringBuilder();
+ new Formatter(builder)
+ .format(ErrorMessages.MULTIPLE_BINDING_TYPES_FOR_KEY_FORMAT, formatRootRequestKey(path));
+ ImmutableListMultimap<BindingType, ContributionBinding> bindingsByType =
+ ContributionBinding.<ContributionBinding>bindingTypesFor(
+ resolvedBinding.contributionBindings());
+ for (BindingType type : Ordering.natural().immutableSortedCopy(bindingsByType.keySet())) {
+ builder.append(INDENT);
+ builder.append(formatBindingType(type));
+ builder.append(" bindings:\n");
+ for (ContributionBinding binding : bindingsByType.get(type)) {
+ builder.append(INDENT).append(INDENT);
+ if (binding instanceof ProvisionBinding) {
+ builder.append(provisionBindingFormatter.format((ProvisionBinding) binding));
+ } else if (binding instanceof ProductionBinding) {
+ builder.append(productionBindingFormatter.format((ProductionBinding) binding));
+ }
+ builder.append('\n');
+ }
+ }
+ reportBuilder.addError(builder.toString(), path.getLast().request().requestElement());
+ }
+
+ private void reportDuplicateMapKeys(
+ Deque<ResolvedRequest> path, Collection<? extends ContributionBinding> mapBindings) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(duplicateMapKeysError(formatRootRequestKey(path)));
+ appendBindings(builder, mapBindings, 1);
+ reportBuilder.addError(builder.toString(), path.getLast().request().requestElement());
+ }
+
+ private void reportInconsistentMapKeyAnnotations(
+ Deque<ResolvedRequest> path,
+ Multimap<Equivalence.Wrapper<DeclaredType>, ContributionBinding>
+ mapBindingsByAnnotationType) {
+ StringBuilder builder =
+ new StringBuilder(inconsistentMapKeyAnnotationsError(formatRootRequestKey(path)));
+ for (Map.Entry<Equivalence.Wrapper<DeclaredType>, Collection<ContributionBinding>> entry :
+ mapBindingsByAnnotationType.asMap().entrySet()) {
+ DeclaredType annotationType = entry.getKey().get();
+ Collection<ContributionBinding> bindings = entry.getValue();
+
+ builder
+ .append('\n')
+ .append(INDENT)
+ .append(annotationType)
+ .append(':');
+
+ appendBindings(builder, bindings, 2);
+ }
+ reportBuilder.addError(builder.toString(), path.getLast().request().requestElement());
+ }
+
+ /**
+ * Reports a cycle in the binding path.
+ *
+ * @param bindingPath the binding path, starting with the component provision dependency, and
+ * ending with the binding that depends on {@code request}
+ * @param request the request that would have been added to the binding path if its
+ * {@linkplain DependencyRequest#bindingKey() binding key} wasn't already in it
+ * @param indexOfDuplicatedKey the index of the dependency request in {@code bindingPath} whose
+ * {@linkplain DependencyRequest#bindingKey() binding key} matches {@code request}'s
+ */
+ private void reportCycle(
+ Iterable<ResolvedRequest> bindingPath,
+ DependencyRequest request,
+ int indexOfDuplicatedKey) {
+ ImmutableList<DependencyRequest> requestPath =
+ FluentIterable.from(bindingPath)
+ .transform(REQUEST_FROM_RESOLVED_REQUEST)
+ .append(request)
+ .toList();
+ Element rootRequestElement = requestPath.get(0).requestElement();
+ ImmutableList<DependencyRequest> cycle =
+ requestPath.subList(indexOfDuplicatedKey, requestPath.size());
+ Diagnostic.Kind kind = cycleHasProviderOrLazy(cycle) ? WARNING : ERROR;
+ if (kind == WARNING
+ && (suppressCycleWarnings(rootRequestElement)
+ || suppressCycleWarnings(rootRequestElement.getEnclosingElement())
+ || suppressCycleWarnings(cycle))) {
+ return;
+ }
+ // TODO(cgruber): Provide a hint for the start and end of the cycle.
+ TypeElement componentType = MoreElements.asType(rootRequestElement.getEnclosingElement());
+ reportBuilder.addItem(
+ String.format(
+ ErrorMessages.CONTAINS_DEPENDENCY_CYCLE_FORMAT,
+ componentType.getQualifiedName(),
+ rootRequestElement.getSimpleName(),
+ Joiner.on("\n")
+ .join(
+ FluentIterable.from(requestPath)
+ .transform(dependencyRequestFormatter)
+ .filter(not(equalTo("")))
+ .skip(1))),
+ kind,
+ rootRequestElement);
+ }
+
+ /**
+ * Returns {@code true} if any step of a dependency cycle after the first is a {@link Provider}
+ * or {@link Lazy} or a {@code Map<K, Provider<V>>}.
+ *
+ * <p>If an implicit {@link Provider} dependency on {@code Map<K, Provider<V>>} is immediately
+ * preceded by a dependency on {@code Map<K, V>}, which means that the map's {@link Provider}s'
+ * {@link Provider#get() get()} methods are called during provision and so the cycle is not
+ * really broken.
+ */
+ private boolean cycleHasProviderOrLazy(ImmutableList<DependencyRequest> cycle) {
+ DependencyRequest lastDependencyRequest = cycle.get(0);
+ for (DependencyRequest dependencyRequest : skip(cycle, 1)) {
+ switch (dependencyRequest.kind()) {
+ case PROVIDER:
+ if (!isImplicitProviderMapForValueMap(dependencyRequest, lastDependencyRequest)) {
+ return true;
+ }
+ break;
+
+ case LAZY:
+ return true;
+
+ case INSTANCE:
+ if (isMapWithProvidedValues(dependencyRequest.key().type())) {
+ return true;
+ } else {
+ break;
+ }
+
+ default:
+ break;
+ }
+ lastDependencyRequest = dependencyRequest;
+ }
+ return false;
+ }
+
+ /**
+ * Returns {@code true} if {@code maybeValueMapRequest}'s key type is {@code Map<K, V>} and
+ * {@code maybeProviderMapRequest}'s key type is {@code Map<K, Provider<V>>}, and both keys have
+ * the same qualifier.
+ */
+ private boolean isImplicitProviderMapForValueMap(
+ DependencyRequest maybeProviderMapRequest, DependencyRequest maybeValueMapRequest) {
+ TypeMirror maybeProviderMapRequestType = maybeProviderMapRequest.key().type();
+ TypeMirror maybeValueMapRequestType = maybeValueMapRequest.key().type();
+ return maybeProviderMapRequest
+ .key()
+ .wrappedQualifier()
+ .equals(maybeValueMapRequest.key().wrappedQualifier())
+ && isMapWithProvidedValues(maybeProviderMapRequestType)
+ && isMapWithNonProvidedValues(maybeValueMapRequestType)
+ && types.isSameType(
+ getKeyTypeOfMap(asDeclared(maybeProviderMapRequestType)),
+ getKeyTypeOfMap(asDeclared(maybeValueMapRequestType)))
+ && types.isSameType(
+ getProvidedValueTypeOfMap(asDeclared(maybeProviderMapRequestType)),
+ getValueTypeOfMap(asDeclared(maybeValueMapRequestType)));
+ }
+ }
+
+ private boolean suppressCycleWarnings(Element requestElement) {
+ SuppressWarnings suppressions = requestElement.getAnnotation(SuppressWarnings.class);
+ return suppressions != null && Arrays.asList(suppressions.value()).contains("dependency-cycle");
+ }
+
+ private boolean suppressCycleWarnings(ImmutableList<DependencyRequest> pathElements) {
+ for (DependencyRequest dependencyRequest : pathElements) {
+ if (suppressCycleWarnings(dependencyRequest.requestElement())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ValidationReport<TypeElement> validate(BindingGraph subject) {
+ Validation validation = new Validation(subject);
+ validation.validateSubgraph();
+ return validation.buildReport();
+ }
+
+ /**
+ * Append and format a list of indented component types (with their scope annotations)
+ */
+ private void appendIndentedComponentsList(StringBuilder message, Iterable<TypeElement> types) {
+ for (TypeElement scopedComponent : types) {
+ message.append(INDENT);
+ Scope scope = Scope.scopeOf(scopedComponent);
+ if (scope.isPresent()) {
+ message.append(scope.getReadableSource()).append(' ');
+ }
+ message.append(stripCommonTypePrefixes(scopedComponent.getQualifiedName().toString()))
+ .append('\n');
+ }
+ }
+
+ /**
+ * Returns a set of type elements containing only those found in the input set that have
+ * a scoping annotation.
+ */
+ private ImmutableSet<TypeElement> scopedTypesIn(Set<TypeElement> types) {
+ return FluentIterable.from(types).filter(new Predicate<TypeElement>() {
+ @Override public boolean apply(TypeElement input) {
+ return Scope.scopeOf(input).isPresent();
+ }
+ }).toSet();
+ }
+
+ /**
+ * Returns whether the given dependency path would require the most recent request to be resolved
+ * by only provision bindings.
+ */
+ private boolean doesPathRequireProvisionOnly(Deque<ResolvedRequest> path) {
+ if (path.size() == 1) {
+ // if this is an entry-point, then we check the request
+ switch (path.peek().request().kind()) {
+ case INSTANCE:
+ case PROVIDER:
+ case LAZY:
+ case MEMBERS_INJECTOR:
+ return true;
+ case PRODUCER:
+ case PRODUCED:
+ case FUTURE:
+ return false;
+ default:
+ throw new AssertionError();
+ }
+ }
+ // otherwise, the second-most-recent bindings determine whether the most recent one must be a
+ // provision
+ ImmutableSet<ProvisionBinding> dependentProvisions = provisionsDependingOnLatestRequest(path);
+ return !dependentProvisions.isEmpty();
+ }
+
+ /**
+ * Returns any provision bindings resolved for the second-most-recent request in the given path;
+ * that is, returns those provision bindings that depend on the latest request in the path.
+ */
+ private ImmutableSet<ProvisionBinding> provisionsDependingOnLatestRequest(
+ Deque<ResolvedRequest> path) {
+ Iterator<ResolvedRequest> iterator = path.iterator();
+ final DependencyRequest request = iterator.next().request();
+ ResolvedRequest previousResolvedRequest = iterator.next();
+ @SuppressWarnings("unchecked") // validated by instanceof below
+ ImmutableSet<ProvisionBinding> bindings = (ImmutableSet<ProvisionBinding>) FluentIterable
+ .from(previousResolvedRequest.binding().bindings())
+ .filter(new Predicate<Binding>() {
+ @Override public boolean apply(Binding binding) {
+ return binding instanceof ProvisionBinding
+ && binding.implicitDependencies().contains(request);
+ }
+ }).toSet();
+ return bindings;
+ }
+
+ private String formatBindingType(BindingType type) {
+ switch(type) {
+ case MAP:
+ return "Map";
+ case SET:
+ return "Set";
+ case UNIQUE:
+ return "Unique";
+ default:
+ throw new IllegalStateException("Unknown binding type: " + type);
+ }
+ }
+
+ private String formatBinding(Binding binding) {
+ // TODO(beder): Refactor the formatters so we don't need these instanceof checks.
+ if (binding instanceof ProvisionBinding) {
+ return provisionBindingFormatter.format((ProvisionBinding) binding);
+ } else if (binding instanceof ProductionBinding) {
+ return productionBindingFormatter.format((ProductionBinding) binding);
+ } else {
+ throw new IllegalArgumentException(
+ "Expected either a ProvisionBinding or a ProductionBinding, not " + binding);
+ }
+ }
+
+ private String formatRootRequestKey(Deque<ResolvedRequest> path) {
+ return keyFormatter.format(path.peek().request().key());
+ }
+
+ private void appendBindings(
+ StringBuilder builder, Collection<? extends Binding> bindings, int indentLevel) {
+ for (Binding binding : Iterables.limit(bindings, DUPLICATE_SIZE_LIMIT)) {
+ builder.append('\n');
+ for (int i = 0; i < indentLevel; i++) {
+ builder.append(INDENT);
+ }
+ builder.append(formatBinding(binding));
+ }
+ int numberOfOtherBindings = bindings.size() - DUPLICATE_SIZE_LIMIT;
+ if (numberOfOtherBindings > 0) {
+ builder.append('\n');
+ for (int i = 0; i < indentLevel; i++) {
+ builder.append(INDENT);
+ }
+ builder.append("and ").append(numberOfOtherBindings).append(" other");
+ }
+ if (numberOfOtherBindings > 1) {
+ builder.append('s');
+ }
+ }
+
+ @AutoValue
+ abstract static class ResolvedRequest {
+ abstract DependencyRequest request();
+ abstract ResolvedBindings binding();
+
+ static ResolvedRequest create(DependencyRequest request, BindingGraph graph) {
+ BindingKey bindingKey = request.bindingKey();
+ ResolvedBindings resolvedBindings = graph.resolvedBindings().get(bindingKey);
+ return new AutoValue_BindingGraphValidator_ResolvedRequest(request,
+ resolvedBindings == null
+ ? ResolvedBindings.create(bindingKey,
+ graph.componentDescriptor(),
+ ImmutableSet.<Binding>of(),
+ ImmutableSetMultimap.<ComponentDescriptor, Binding>of())
+ : resolvedBindings);
+ }
+ }
+
+ private static final Function<ResolvedRequest, DependencyRequest> REQUEST_FROM_RESOLVED_REQUEST =
+ new Function<ResolvedRequest, DependencyRequest>() {
+ @Override public DependencyRequest apply(ResolvedRequest resolvedRequest) {
+ return resolvedRequest.request();
+ }
+ };
+}
+
diff --git a/compiler/src/main/java/dagger/internal/codegen/BindingKey.java b/compiler/src/main/java/dagger/internal/codegen/BindingKey.java
new file mode 100644
index 000000000..cd29d8d69
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/BindingKey.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.value.AutoValue;
+
+/**
+ * A value object that pairs a {@link Key} with the style of its binding (i.e., whether it's a
+ * members injector or normal contribution).
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@AutoValue
+abstract class BindingKey {
+ /** The style of binding that makes a {@link Key} available. */
+ enum Kind {
+ CONTRIBUTION, MEMBERS_INJECTION;
+ }
+
+ static BindingKey create(Kind kind, Key key) {
+ return new AutoValue_BindingKey(kind, key);
+ }
+
+ abstract Kind kind();
+ abstract Key key();
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/BuilderValidator.java b/compiler/src/main/java/dagger/internal/codegen/BuilderValidator.java
new file mode 100644
index 000000000..ba96ebfd3
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/BuilderValidator.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreTypes;
+import com.google.common.base.Equivalence;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+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.type.ExecutableType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * Validates {@link dagger.Component.Builder} annotations.
+ *
+ * @author sameb@google.com (Sam Berlin)
+ */
+class BuilderValidator {
+ private final Elements elements;
+ private final Types types;
+ private final ComponentDescriptor.Kind componentType;
+
+ BuilderValidator(Elements elements, Types types, ComponentDescriptor.Kind componentType) {
+ this.elements = elements;
+ this.types = types;
+ this.componentType = componentType;
+ }
+
+ public ValidationReport<TypeElement> validate(TypeElement subject) {
+ ValidationReport.Builder<TypeElement> builder = ValidationReport.about(subject);
+
+ Element componentElement = subject.getEnclosingElement();
+ ErrorMessages.ComponentBuilderMessages msgs = ErrorMessages.builderMsgsFor(componentType);
+ Class<? extends Annotation> componentAnnotation = componentType.annotationType();
+ Class<? extends Annotation> builderAnnotation = componentType.builderAnnotationType();
+ checkArgument(subject.getAnnotation(builderAnnotation) != null);
+
+ if (!isAnnotationPresent(componentElement, componentAnnotation)) {
+ builder.addError(msgs.mustBeInComponent(), subject);
+ }
+
+ switch (subject.getKind()) {
+ case CLASS:
+ List<? extends Element> allElements = subject.getEnclosedElements();
+ List<ExecutableElement> cxtors = ElementFilter.constructorsIn(allElements);
+ if (cxtors.size() != 1 || getOnlyElement(cxtors).getParameters().size() != 0) {
+ builder.addError(msgs.cxtorOnlyOneAndNoArgs(), subject);
+ }
+ break;
+ case INTERFACE:
+ break;
+ default:
+ // If not the correct type, exit early since the rest of the messages will be bogus.
+ builder.addError(msgs.mustBeClassOrInterface(), subject);
+ return builder.build();
+ }
+
+ if (!subject.getTypeParameters().isEmpty()) {
+ builder.addError(msgs.generics(), subject);
+ }
+
+ Set<Modifier> modifiers = subject.getModifiers();
+ if (modifiers.contains(PRIVATE)) {
+ builder.addError(msgs.isPrivate(), subject);
+ }
+ if (!modifiers.contains(STATIC)) {
+ builder.addError(msgs.mustBeStatic(), subject);
+ }
+ // Note: Must be abstract, so no need to check for final.
+ if (!modifiers.contains(ABSTRACT)) {
+ builder.addError(msgs.mustBeAbstract(), subject);
+ }
+
+ ExecutableElement buildMethod = null;
+ Multimap<Equivalence.Wrapper<TypeMirror>, ExecutableElement> methodsPerParam =
+ LinkedHashMultimap.create();
+ for (ExecutableElement method : Util.getUnimplementedMethods(elements, subject)) {
+ ExecutableType resolvedMethodType =
+ MoreTypes.asExecutable(types.asMemberOf(MoreTypes.asDeclared(subject.asType()), method));
+ TypeMirror returnType = resolvedMethodType.getReturnType();
+ if (method.getParameters().size() == 0) {
+ // If this is potentially a build() method, validate it returns the correct type.
+ if (types.isSameType(returnType, componentElement.asType())) {
+ if (buildMethod != null) {
+ // If we found more than one build-like method, fail.
+ error(builder, method, msgs.twoBuildMethods(), msgs.inheritedTwoBuildMethods(),
+ buildMethod);
+ }
+ } else {
+ error(builder, method, msgs.buildMustReturnComponentType(),
+ msgs.inheritedBuildMustReturnComponentType());
+ }
+ // We set the buildMethod regardless of the return type to reduce error spam.
+ buildMethod = method;
+ } else if (method.getParameters().size() > 1) {
+ // If this is a setter, make sure it has one arg.
+ error(builder, method, msgs.methodsMustTakeOneArg(), msgs.inheritedMethodsMustTakeOneArg());
+ } else if (returnType.getKind() != TypeKind.VOID
+ && !types.isSubtype(subject.asType(), returnType)) {
+ // If this correctly had one arg, make sure the return types are valid.
+ error(builder, method, msgs.methodsMustReturnVoidOrBuilder(),
+ msgs.inheritedMethodsMustReturnVoidOrBuilder());
+ } else {
+ // If the return types are valid, record the method.
+ methodsPerParam.put(
+ MoreTypes.equivalence().<TypeMirror>wrap(
+ Iterables.getOnlyElement(resolvedMethodType.getParameterTypes())),
+ method);
+ }
+
+ if (!method.getTypeParameters().isEmpty()) {
+ error(builder, method, msgs.methodsMayNotHaveTypeParameters(),
+ msgs.inheritedMethodsMayNotHaveTypeParameters());
+ }
+ }
+
+ if (buildMethod == null) {
+ builder.addError(msgs.missingBuildMethod(), subject);
+ }
+
+ // Go back through each recorded method per param type. If we had more than one method
+ // for a given param, fail.
+ for (Map.Entry<Equivalence.Wrapper<TypeMirror>, Collection<ExecutableElement>> entry :
+ methodsPerParam.asMap().entrySet()) {
+ if (entry.getValue().size() > 1) {
+ TypeMirror type = entry.getKey().get();
+ builder.addError(String.format(msgs.manyMethodsForType(), type, entry.getValue()), subject);
+ }
+ }
+
+ // Note: there's more validation in BindingGraphValidator,
+ // specifically to make sure the setter methods mirror the deps.
+
+ return builder.build();
+ }
+
+ /**
+ * Generates one of two error messages. If the method is enclosed in the subject, we target the
+ * error to the method itself. Otherwise we target the error to the subject and list the method as
+ * an argumnent. (Otherwise we have no way of knowing if the method is being compiled in this pass
+ * too, so javac might not be able to pinpoint it's line of code.)
+ */
+ /*
+ * For Component.Builder, the prototypical example would be if someone had:
+ * libfoo: interface SharedBuilder { void badSetter(A a, B b); }
+ * libbar: BarComponent { BarBuilder extends SharedBuilder } }
+ * ... the compiler only validates BarBuilder when compiling libbar, but it fails because
+ * of libfoo's SharedBuilder (which could have been compiled in a previous pass).
+ * So we can't point to SharedBuilder#badSetter as the subject of the BarBuilder validation
+ * failure.
+ *
+ * This check is a little more strict than necessary -- ideally we'd check if method's enclosing
+ * class was included in this compile run. But that's hard, and this is close enough.
+ */
+ private void error(
+ ValidationReport.Builder<TypeElement> builder,
+ ExecutableElement method,
+ String enclosedError,
+ String inheritedError,
+ Object... extraArgs) {
+ if (method.getEnclosingElement().equals(builder.getSubject())) {
+ builder.addError(String.format(enclosedError, extraArgs), method);
+ } else {
+ Object[] newArgs = new Object[extraArgs.length + 1];
+ newArgs[0] = method;
+ System.arraycopy(extraArgs, 0, newArgs, 1, extraArgs.length);
+ builder.addError(String.format(inheritedError, newArgs), builder.getSubject());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java b/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java
new file mode 100644
index 000000000..7a5c13520
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java
@@ -0,0 +1,450 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.Component;
+import dagger.Lazy;
+import dagger.MembersInjector;
+import dagger.Module;
+import dagger.Subcomponent;
+import dagger.producers.ProductionComponent;
+import java.lang.annotation.Annotation;
+import java.util.EnumSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import javax.inject.Provider;
+import javax.lang.model.element.AnnotationMirror;
+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;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.ConfigurationAnnotations.enclosedBuilders;
+import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies;
+import static dagger.internal.codegen.ConfigurationAnnotations.getComponentModules;
+import static dagger.internal.codegen.ConfigurationAnnotations.isComponent;
+import static javax.lang.model.type.TypeKind.DECLARED;
+import static javax.lang.model.type.TypeKind.VOID;
+
+/**
+ * The logical representation of a {@link Component} or {@link ProductionComponent} definition.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@AutoValue
+abstract class ComponentDescriptor {
+ ComponentDescriptor() {}
+
+ enum Kind {
+ COMPONENT(Component.class, Component.Builder.class, true),
+ SUBCOMPONENT(Subcomponent.class, Subcomponent.Builder.class, false),
+ PRODUCTION_COMPONENT(ProductionComponent.class, null, true);
+
+ private final Class<? extends Annotation> annotationType;
+ private final Class<? extends Annotation> builderType;
+ private final boolean isTopLevel;
+
+ /**
+ * Returns the kind of an annotated element if it is annotated with one of the
+ * {@linkplain #annotationType() annotation types}.
+ *
+ * @throws IllegalArgumentException if the element is annotated with more than one of the
+ * annotation types
+ */
+ static Optional<Kind> forAnnotatedElement(TypeElement element) {
+ Set<Kind> kinds = EnumSet.noneOf(Kind.class);
+ for (Kind kind : values()) {
+ if (MoreElements.isAnnotationPresent(element, kind.annotationType())) {
+ kinds.add(kind);
+ }
+ }
+ checkArgument(
+ kinds.size() <= 1, "%s cannot be annotated with more than one of %s", element, kinds);
+ return Optional.fromNullable(getOnlyElement(kinds, null));
+ }
+
+ Kind(
+ Class<? extends Annotation> annotationType,
+ Class<? extends Annotation> builderType,
+ boolean isTopLevel) {
+ this.annotationType = annotationType;
+ this.builderType = builderType;
+ this.isTopLevel = isTopLevel;
+ }
+
+ Class<? extends Annotation> annotationType() {
+ return annotationType;
+ }
+
+ Class<? extends Annotation> builderAnnotationType() {
+ return builderType;
+ }
+
+ boolean isTopLevel() {
+ return isTopLevel;
+ }
+ }
+
+ abstract Kind kind();
+
+ abstract AnnotationMirror componentAnnotation();
+
+ /**
+ * The type (interface or abstract class) that defines the component. This is the element to which
+ * the {@link Component} annotation was applied.
+ */
+ abstract TypeElement componentDefinitionType();
+
+ /**
+ * The set of component dependencies listed in {@link Component#dependencies}.
+ */
+ abstract ImmutableSet<TypeElement> dependencies();
+
+ /**
+ * The set of {@link ModuleDescriptor modules} declared directly in {@link Component#modules}.
+ * Use {@link #transitiveModules} to get the full set of modules available upon traversing
+ * {@link Module#includes}.
+ */
+ abstract ImmutableSet<ModuleDescriptor> modules();
+
+ /**
+ * Returns the set of {@link ModuleDescriptor modules} declared in {@link Component#modules} and
+ * those reachable by traversing {@link Module#includes}.
+ *
+ * <p>Note that for subcomponents this <em>will not</em> include descriptors for any modules that
+ * are declared in parent components.
+ */
+ ImmutableSet<ModuleDescriptor> transitiveModules() {
+ Set<ModuleDescriptor> transitiveModules = new LinkedHashSet<>();
+ for (ModuleDescriptor module : modules()) {
+ addTransitiveModules(transitiveModules, module);
+ }
+ return ImmutableSet.copyOf(transitiveModules);
+ }
+
+ ImmutableSet<TypeElement> transitiveModuleTypes() {
+ return FluentIterable.from(transitiveModules())
+ .transform(ModuleDescriptor.getModuleElement())
+ .toSet();
+ }
+
+ private static Set<ModuleDescriptor> addTransitiveModules(
+ Set<ModuleDescriptor> transitiveModules, ModuleDescriptor module) {
+ if (transitiveModules.add(module)) {
+ for (ModuleDescriptor includedModule : module.includedModules()) {
+ addTransitiveModules(transitiveModules, includedModule);
+ }
+ }
+ return transitiveModules;
+ }
+
+ /**
+ * An index of the type to which this component holds a reference (the type listed in
+ * {@link Component#dependencies} or {@link ProductionComponent#dependencies} as opposed to the
+ * enclosing type) for each method from a component dependency that can be used for binding.
+ */
+ abstract ImmutableMap<ExecutableElement, TypeElement> dependencyMethodIndex();
+
+ /**
+ * The element representing {@link Executor}, if it should be a dependency of this component.
+ */
+ abstract Optional<TypeElement> executorDependency();
+
+ /**
+ * The scope of the component.
+ */
+ abstract Scope scope();
+
+ abstract ImmutableMap<ComponentMethodDescriptor, ComponentDescriptor> subcomponents();
+
+ abstract ImmutableSet<ComponentMethodDescriptor> componentMethods();
+
+ // TODO(gak): Consider making this non-optional and revising the
+ // interaction between the spec & generation
+ abstract Optional<BuilderSpec> builderSpec();
+
+ @AutoValue
+ static abstract class ComponentMethodDescriptor {
+ abstract ComponentMethodKind kind();
+ abstract Optional<DependencyRequest> dependencyRequest();
+ abstract ExecutableElement methodElement();
+ }
+
+ enum ComponentMethodKind {
+ PROVISON,
+ PRODUCTION,
+ MEMBERS_INJECTION,
+ SUBCOMPONENT,
+ SUBCOMPONENT_BUILDER,
+ }
+
+ @AutoValue
+ static abstract class BuilderSpec {
+ abstract TypeElement builderDefinitionType();
+ abstract Map<TypeElement, ExecutableElement> methodMap();
+ abstract ExecutableElement buildMethod();
+ abstract TypeMirror componentType();
+ }
+
+ static final class Factory {
+ private final Elements elements;
+ private final Types types;
+ private final DependencyRequest.Factory dependencyRequestFactory;
+ private final ModuleDescriptor.Factory moduleDescriptorFactory;
+
+ Factory(
+ Elements elements,
+ Types types,
+ DependencyRequest.Factory dependencyRequestFactory,
+ ModuleDescriptor.Factory moduleDescriptorFactory) {
+ this.elements = elements;
+ this.types = types;
+ this.dependencyRequestFactory = dependencyRequestFactory;
+ this.moduleDescriptorFactory = moduleDescriptorFactory;
+ }
+
+ /**
+ * Returns a component descriptor for a type annotated with either {@link Component @Component}
+ * or {@link ProductionComponent @ProductionComponent}.
+ */
+ ComponentDescriptor forComponent(TypeElement componentDefinitionType) {
+ Optional<Kind> kind = Kind.forAnnotatedElement(componentDefinitionType);
+ checkArgument(
+ kind.isPresent() && kind.get().isTopLevel(),
+ "%s must be annotated with @Component or @ProductionComponent",
+ componentDefinitionType);
+ return create(componentDefinitionType, kind.get());
+ }
+
+ private ComponentDescriptor create(TypeElement componentDefinitionType, Kind kind) {
+ DeclaredType declaredComponentType = MoreTypes.asDeclared(componentDefinitionType.asType());
+ AnnotationMirror componentMirror =
+ getAnnotationMirror(componentDefinitionType, kind.annotationType())
+ .or(getAnnotationMirror(componentDefinitionType, Subcomponent.class))
+ .get();
+ ImmutableSet<TypeElement> componentDependencyTypes =
+ isComponent(componentDefinitionType)
+ ? MoreTypes.asTypeElements(getComponentDependencies(componentMirror))
+ : ImmutableSet.<TypeElement>of();
+
+ ImmutableMap.Builder<ExecutableElement, TypeElement> dependencyMethodIndex =
+ ImmutableMap.builder();
+
+ for (TypeElement componentDependency : componentDependencyTypes) {
+ List<ExecutableElement> dependencyMethods =
+ ElementFilter.methodsIn(elements.getAllMembers(componentDependency));
+ for (ExecutableElement dependencyMethod : dependencyMethods) {
+ if (isComponentContributionMethod(elements, dependencyMethod)) {
+ dependencyMethodIndex.put(dependencyMethod, componentDependency);
+ }
+ }
+ }
+
+ Optional<TypeElement> executorDependency =
+ kind.equals(Kind.PRODUCTION_COMPONENT)
+ ? Optional.of(elements.getTypeElement(Executor.class.getCanonicalName()))
+ : Optional.<TypeElement>absent();
+
+ ImmutableSet.Builder<ModuleDescriptor> modules = ImmutableSet.builder();
+ for (TypeMirror moduleIncludesType : getComponentModules(componentMirror)) {
+ modules.add(moduleDescriptorFactory.create(MoreTypes.asTypeElement(moduleIncludesType)));
+ }
+
+ ImmutableSet<ExecutableElement> unimplementedMethods =
+ Util.getUnimplementedMethods(elements, componentDefinitionType);
+
+ ImmutableSet.Builder<ComponentMethodDescriptor> componentMethodsBuilder =
+ ImmutableSet.builder();
+
+ ImmutableMap.Builder<ComponentMethodDescriptor, ComponentDescriptor> subcomponentDescriptors =
+ ImmutableMap.builder();
+ for (ExecutableElement componentMethod : unimplementedMethods) {
+ ExecutableType resolvedMethod =
+ MoreTypes.asExecutable(types.asMemberOf(declaredComponentType, componentMethod));
+ ComponentMethodDescriptor componentMethodDescriptor =
+ getDescriptorForComponentMethod(componentDefinitionType, kind, componentMethod);
+ componentMethodsBuilder.add(componentMethodDescriptor);
+ switch (componentMethodDescriptor.kind()) {
+ case SUBCOMPONENT:
+ subcomponentDescriptors.put(
+ componentMethodDescriptor,
+ create(
+ MoreElements.asType(MoreTypes.asElement(resolvedMethod.getReturnType())),
+ Kind.SUBCOMPONENT));
+ break;
+ case SUBCOMPONENT_BUILDER:
+ subcomponentDescriptors.put(
+ componentMethodDescriptor,
+ create(
+ MoreElements.asType(
+ MoreTypes.asElement(resolvedMethod.getReturnType()).getEnclosingElement()),
+ Kind.SUBCOMPONENT));
+ break;
+ default: // nothing special to do for other methods.
+ }
+
+ }
+
+ ImmutableList<DeclaredType> enclosedBuilders = kind.builderAnnotationType() == null
+ ? ImmutableList.<DeclaredType>of()
+ : enclosedBuilders(componentDefinitionType, kind.builderAnnotationType());
+ Optional<DeclaredType> builderType =
+ Optional.fromNullable(getOnlyElement(enclosedBuilders, null));
+
+ Scope scope = Scope.scopeOf(componentDefinitionType);
+ return new AutoValue_ComponentDescriptor(
+ kind,
+ componentMirror,
+ componentDefinitionType,
+ componentDependencyTypes,
+ modules.build(),
+ dependencyMethodIndex.build(),
+ executorDependency,
+ scope,
+ subcomponentDescriptors.build(),
+ componentMethodsBuilder.build(),
+ createBuilderSpec(builderType));
+ }
+
+ private ComponentMethodDescriptor getDescriptorForComponentMethod(TypeElement componentElement,
+ Kind componentKind,
+ ExecutableElement componentMethod) {
+ ExecutableType resolvedComponentMethod = MoreTypes.asExecutable(types.asMemberOf(
+ MoreTypes.asDeclared(componentElement.asType()), componentMethod));
+ TypeMirror returnType = resolvedComponentMethod.getReturnType();
+ if (returnType.getKind().equals(DECLARED)) {
+ if (MoreTypes.isTypeOf(Provider.class, returnType)
+ || MoreTypes.isTypeOf(Lazy.class, returnType)) {
+ return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
+ ComponentMethodKind.PROVISON,
+ Optional.of(dependencyRequestFactory.forComponentProvisionMethod(componentMethod,
+ resolvedComponentMethod)),
+ componentMethod);
+ } else if (MoreTypes.isTypeOf(MembersInjector.class, returnType)) {
+ return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
+ ComponentMethodKind.MEMBERS_INJECTION,
+ Optional.of(dependencyRequestFactory.forComponentMembersInjectionMethod(
+ componentMethod,
+ resolvedComponentMethod)),
+ componentMethod);
+ } else if (isAnnotationPresent(MoreTypes.asElement(returnType), Subcomponent.class)) {
+ return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
+ ComponentMethodKind.SUBCOMPONENT,
+ Optional.<DependencyRequest>absent(),
+ componentMethod);
+ } else if (isAnnotationPresent(MoreTypes.asElement(returnType),
+ Subcomponent.Builder.class)) {
+ return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
+ ComponentMethodKind.SUBCOMPONENT_BUILDER,
+ Optional.<DependencyRequest>absent(),
+ componentMethod);
+ }
+ }
+
+ // a typical provision method
+ if (componentMethod.getParameters().isEmpty()
+ && !componentMethod.getReturnType().getKind().equals(VOID)) {
+ switch (componentKind) {
+ case COMPONENT:
+ case SUBCOMPONENT:
+ return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
+ ComponentMethodKind.PROVISON,
+ Optional.of(dependencyRequestFactory.forComponentProvisionMethod(componentMethod,
+ resolvedComponentMethod)),
+ componentMethod);
+ case PRODUCTION_COMPONENT:
+ return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
+ ComponentMethodKind.PRODUCTION,
+ Optional.of(dependencyRequestFactory.forComponentProductionMethod(componentMethod,
+ resolvedComponentMethod)),
+ componentMethod);
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ List<? extends TypeMirror> parameterTypes = resolvedComponentMethod.getParameterTypes();
+ if (parameterTypes.size() == 1
+ && (returnType.getKind().equals(VOID)
+ || MoreTypes.equivalence().equivalent(returnType, parameterTypes.get(0)))) {
+ return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
+ ComponentMethodKind.MEMBERS_INJECTION,
+ Optional.of(dependencyRequestFactory.forComponentMembersInjectionMethod(
+ componentMethod,
+ resolvedComponentMethod)),
+ componentMethod);
+ }
+
+ throw new IllegalArgumentException("not a valid component method: " + componentMethod);
+ }
+
+ private Optional<BuilderSpec> createBuilderSpec(Optional<DeclaredType> builderType) {
+ if (!builderType.isPresent()) {
+ return Optional.absent();
+ }
+ TypeElement element = MoreTypes.asTypeElement(builderType.get());
+ ImmutableSet<ExecutableElement> methods = Util.getUnimplementedMethods(elements, element);
+ ImmutableMap.Builder<TypeElement, ExecutableElement> map = ImmutableMap.builder();
+ ExecutableElement buildMethod = null;
+ for (ExecutableElement method : methods) {
+ if (method.getParameters().isEmpty()) {
+ buildMethod = method;
+ } else {
+ ExecutableType resolved =
+ MoreTypes.asExecutable(types.asMemberOf(builderType.get(), method));
+ map.put(MoreTypes.asTypeElement(getOnlyElement(resolved.getParameterTypes())), method);
+ }
+ }
+ verify(buildMethod != null); // validation should have ensured this.
+ return Optional.<BuilderSpec>of(new AutoValue_ComponentDescriptor_BuilderSpec(element,
+ map.build(), buildMethod, element.getEnclosingElement().asType()));
+ }
+ }
+
+ static boolean isComponentContributionMethod(Elements elements, ExecutableElement method) {
+ return method.getParameters().isEmpty()
+ && !method.getReturnType().getKind().equals(VOID)
+ && !elements.getTypeElement(Object.class.getCanonicalName())
+ .equals(method.getEnclosingElement());
+ }
+
+ static boolean isComponentProductionMethod(Elements elements, ExecutableElement method) {
+ return isComponentContributionMethod(elements, method)
+ && MoreTypes.isTypeOf(ListenableFuture.class, method.getReturnType());
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java
new file mode 100644
index 000000000..bb75e14bd
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.value.AutoValue;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import dagger.Component;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ClassWriter;
+import dagger.internal.codegen.writer.FieldWriter;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.TypeName;
+import javax.annotation.processing.Filer;
+import javax.lang.model.element.Element;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+
+/**
+ * Generates the implementation of the abstract types annotated with {@link Component}.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class ComponentGenerator extends SourceFileGenerator<BindingGraph> {
+ private final Types types;
+ private final Elements elements;
+ private final Key.Factory keyFactory;
+ private final Diagnostic.Kind nullableValidationType;
+
+ ComponentGenerator(
+ Filer filer,
+ Elements elements,
+ Types types,
+ Key.Factory keyFactory,
+ Diagnostic.Kind nullableValidationType) {
+ super(filer);
+ this.types = types;
+ this.elements = elements;
+ this.keyFactory = keyFactory;
+ this.nullableValidationType = nullableValidationType;
+ }
+
+ @Override
+ ClassName nameGeneratedType(BindingGraph input) {
+ ClassName componentDefinitionClassName =
+ ClassName.fromTypeElement(input.componentDescriptor().componentDefinitionType());
+ String componentName = "Dagger" + componentDefinitionClassName.classFileName('_');
+ return componentDefinitionClassName.topLevelClassName().peerNamed(componentName);
+ }
+
+ @Override
+ Iterable<? extends Element> getOriginatingElements(BindingGraph input) {
+ return ImmutableSet.of(input.componentDescriptor().componentDefinitionType());
+ }
+
+ @Override
+ Optional<? extends Element> getElementForErrorReporting(BindingGraph input) {
+ return Optional.of(input.componentDescriptor().componentDefinitionType());
+ }
+
+ @AutoValue
+ static abstract class ProxyClassAndField {
+ abstract ClassWriter proxyWriter();
+ abstract FieldWriter proxyFieldWriter();
+
+ static ProxyClassAndField create(ClassWriter proxyWriter, FieldWriter proxyFieldWriter) {
+ return new AutoValue_ComponentGenerator_ProxyClassAndField(proxyWriter, proxyFieldWriter);
+ }
+ }
+
+ @AutoValue static abstract class MemberSelect {
+ static MemberSelect instanceSelect(ClassName owningClass, Snippet snippet) {
+ return new AutoValue_ComponentGenerator_MemberSelect(
+ Optional.<TypeName> absent(), owningClass, false, snippet);
+ }
+
+ static MemberSelect staticSelect(ClassName owningClass, Snippet snippet) {
+ return new AutoValue_ComponentGenerator_MemberSelect(
+ Optional.<TypeName> absent(), owningClass, true, snippet);
+ }
+
+ static MemberSelect staticMethodInvocationWithCast(
+ ClassName owningClass, Snippet snippet, TypeName castType) {
+ return new AutoValue_ComponentGenerator_MemberSelect(
+ Optional.of(castType), owningClass, true, snippet);
+ }
+
+ /**
+ * This exists only to facilitate edge cases in which we need to select a member, but that
+ * member uses a type parameter that can't be inferred.
+ */
+ abstract Optional<TypeName> selectedCast();
+ abstract ClassName owningClass();
+ abstract boolean staticMember();
+ abstract Snippet snippet();
+
+ private Snippet qualifiedSelectSnippet() {
+ return Snippet.format(
+ "%s" + (staticMember() ? "" : ".this") + ".%s",
+ owningClass(), snippet());
+ }
+
+ Snippet getSnippetWithRawTypeCastFor(ClassName usingClass) {
+ Snippet snippet = getSnippetFor(usingClass);
+ return selectedCast().isPresent()
+ ? Snippet.format("(%s) %s", selectedCast().get(), snippet)
+ : snippet;
+ }
+
+ Snippet getSnippetFor(ClassName usingClass) {
+ return owningClass().equals(usingClass) ? snippet() : qualifiedSelectSnippet();
+ }
+ }
+
+ @Override
+ ImmutableSet<JavaWriter> write(ClassName componentName, BindingGraph input) {
+ return new ComponentWriter(
+ types, elements, keyFactory, nullableValidationType, componentName, input)
+ .write();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentHierarchyValidator.java b/compiler/src/main/java/dagger/internal/codegen/ComponentHierarchyValidator.java
new file mode 100644
index 000000000..8fb4191a5
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ComponentHierarchyValidator.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import dagger.internal.codegen.ComponentDescriptor.BuilderSpec;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import java.util.Map;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+
+import static com.google.common.base.Functions.constant;
+
+/**
+ * Validates the relationships between parent components and subcomponents.
+ */
+final class ComponentHierarchyValidator {
+ ValidationReport<TypeElement> validate(ComponentDescriptor componentDescriptor) {
+ return validateSubcomponentMethods(
+ componentDescriptor,
+ Maps.toMap(
+ componentDescriptor.transitiveModuleTypes(),
+ constant(componentDescriptor.componentDefinitionType())));
+ }
+
+ private ValidationReport<TypeElement> validateSubcomponentMethods(
+ ComponentDescriptor componentDescriptor,
+ Map<TypeElement, TypeElement> existingModuleToOwners) {
+ ValidationReport.Builder<TypeElement> reportBuilder =
+ ValidationReport.about(componentDescriptor.componentDefinitionType());
+ for (Map.Entry<ComponentMethodDescriptor, ComponentDescriptor> subcomponentEntry :
+ componentDescriptor.subcomponents().entrySet()) {
+ ComponentMethodDescriptor subcomponentMethodDescriptor = subcomponentEntry.getKey();
+ ComponentDescriptor subcomponentDescriptor = subcomponentEntry.getValue();
+ // validate the way that we create subcomponents
+ switch (subcomponentMethodDescriptor.kind()) {
+ case SUBCOMPONENT:
+ for (VariableElement factoryMethodParameter :
+ subcomponentMethodDescriptor.methodElement().getParameters()) {
+ TypeElement origininatingComponent =
+ existingModuleToOwners.get(
+ MoreTypes.asTypeElement(factoryMethodParameter.asType()));
+ if (origininatingComponent != null) {
+ /* Factory method tries to pass a module that is already present in the parent.
+ * This is an error. */
+ reportBuilder.addError(
+ String.format(
+ "This module is present in %s. Subcomponents cannot use an instance of a "
+ + "module that differs from its parent.",
+ origininatingComponent.getQualifiedName()),
+ factoryMethodParameter);
+ }
+ }
+ break;
+ case SUBCOMPONENT_BUILDER:
+ BuilderSpec subcomponentBuilderSpec = subcomponentDescriptor.builderSpec().get();
+ for (Map.Entry<TypeElement, ExecutableElement> builderMethodEntry :
+ subcomponentBuilderSpec.methodMap().entrySet()) {
+ TypeElement origininatingComponent =
+ existingModuleToOwners.get(builderMethodEntry.getKey());
+ if (origininatingComponent != null) {
+ /* A subcomponent builder allows you to pass a module that is already present in the
+ * parent. This can't be an error because it might be valid in _other_ components, so
+ * we warn here. */
+ ExecutableElement builderMethodElement = builderMethodEntry.getValue();
+ /* TODO(gak): consider putting this on the builder method directly if it's in the
+ * component being compiled */
+ reportBuilder.addWarning(
+ String.format(
+ "This module is present in %s. Subcomponents cannot use an instance of a "
+ + "module that differs from its parent. The implementation of %s "
+ + "in this component will throw %s.",
+ origininatingComponent.getQualifiedName(),
+ builderMethodElement.getSimpleName(),
+ UnsupportedOperationException.class.getSimpleName()),
+ builderMethodElement);
+ }
+ }
+ break;
+ default:
+ throw new AssertionError();
+ }
+ reportBuilder.addSubreport(
+ validateSubcomponentMethods(
+ subcomponentDescriptor,
+ new ImmutableMap.Builder<TypeElement, TypeElement>()
+ .putAll(existingModuleToOwners)
+ .putAll(
+ Maps.toMap(
+ Sets.difference(
+ subcomponentDescriptor.transitiveModuleTypes(),
+ existingModuleToOwners.keySet()),
+ constant(subcomponentDescriptor.componentDefinitionType())))
+ .build()));
+ }
+ return reportBuilder.build();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentProcessingStep.java b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessingStep.java
new file mode 100644
index 000000000..39b21ca32
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessingStep.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.BasicAnnotationProcessor.ProcessingStep;
+import com.google.auto.common.MoreElements;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.SetMultimap;
+import dagger.Component;
+import dagger.Subcomponent;
+import dagger.internal.codegen.ComponentDescriptor.Factory;
+import dagger.internal.codegen.ComponentValidator.ComponentValidationReport;
+import java.lang.annotation.Annotation;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * A {@link ProcessingStep} that is responsible for dealing with the {@link Component} annotation
+ * as part of the {@link ComponentProcessor}.
+ *
+ * @author Gregory Kick
+ */
+final class ComponentProcessingStep extends AbstractComponentProcessingStep {
+ private final Messager messager;
+ private final ComponentValidator componentValidator;
+ private final ComponentValidator subcomponentValidator;
+ private final BuilderValidator componentBuilderValidator;
+ private final BuilderValidator subcomponentBuilderValidator;
+
+ ComponentProcessingStep(
+ Messager messager,
+ ComponentValidator componentValidator,
+ ComponentValidator subcomponentValidator,
+ BuilderValidator componentBuilderValidator,
+ BuilderValidator subcomponentBuilderValidator,
+ ComponentHierarchyValidator componentHierarchyValidator,
+ BindingGraphValidator bindingGraphValidator,
+ Factory componentDescriptorFactory,
+ BindingGraph.Factory bindingGraphFactory,
+ ComponentGenerator componentGenerator) {
+ super(
+ Component.class,
+ messager,
+ componentHierarchyValidator,
+ bindingGraphValidator,
+ componentDescriptorFactory,
+ bindingGraphFactory,
+ componentGenerator);
+ this.messager = messager;
+ this.componentValidator = componentValidator;
+ this.subcomponentValidator = subcomponentValidator;
+ this.componentBuilderValidator = componentBuilderValidator;
+ this.subcomponentBuilderValidator = subcomponentBuilderValidator;
+ }
+
+ @Override
+ public Set<Class<? extends Annotation>> annotations() {
+ return ImmutableSet.<Class<? extends Annotation>>of(Component.class, Component.Builder.class,
+ Subcomponent.class, Subcomponent.Builder.class);
+ }
+
+ @Override
+ protected ComponentElementValidator componentElementValidator(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ final Map<Element, ValidationReport<TypeElement>> builderReportsByComponent =
+ processComponentBuilders(elementsByAnnotation.get(Component.Builder.class));
+ final Set<Element> subcomponentBuilderElements =
+ elementsByAnnotation.get(Subcomponent.Builder.class);
+ final Map<Element, ValidationReport<TypeElement>> builderReportsBySubcomponent =
+ processSubcomponentBuilders(subcomponentBuilderElements);
+ final Set<Element> subcomponentElements = elementsByAnnotation.get(Subcomponent.class);
+ final Map<Element, ValidationReport<TypeElement>> reportsBySubcomponent =
+ processSubcomponents(subcomponentElements, subcomponentBuilderElements);
+ return new ComponentElementValidator() {
+ @Override
+ boolean validateComponent(TypeElement componentTypeElement, Messager messager) {
+ ComponentValidationReport validationReport =
+ componentValidator.validate(
+ componentTypeElement, subcomponentElements, subcomponentBuilderElements);
+ validationReport.report().printMessagesTo(messager);
+ return isClean(
+ validationReport,
+ builderReportsByComponent,
+ reportsBySubcomponent,
+ builderReportsBySubcomponent);
+ }
+ };
+ }
+
+ private Map<Element, ValidationReport<TypeElement>> processComponentBuilders(
+ Set<? extends Element> componentBuilderElements) {
+ Map<Element, ValidationReport<TypeElement>> builderReportsByComponent = Maps.newHashMap();
+ for (Element element : componentBuilderElements) {
+ ValidationReport<TypeElement> report =
+ componentBuilderValidator.validate(MoreElements.asType(element));
+ report.printMessagesTo(messager);
+ builderReportsByComponent.put(element.getEnclosingElement(), report);
+ }
+ return builderReportsByComponent;
+ }
+
+ private Map<Element, ValidationReport<TypeElement>> processSubcomponentBuilders(
+ Set<? extends Element> subcomponentBuilderElements) {
+ Map<Element, ValidationReport<TypeElement>> builderReportsBySubcomponent = Maps.newHashMap();
+ for (Element element : subcomponentBuilderElements) {
+ ValidationReport<TypeElement> report =
+ subcomponentBuilderValidator.validate(MoreElements.asType(element));
+ report.printMessagesTo(messager);
+ builderReportsBySubcomponent.put(element, report);
+ }
+ return builderReportsBySubcomponent;
+ }
+
+ private Map<Element, ValidationReport<TypeElement>> processSubcomponents(
+ Set<? extends Element> subcomponentElements,
+ Set<? extends Element> subcomponentBuilderElements) {
+ Map<Element, ValidationReport<TypeElement>> reportsBySubcomponent = Maps.newHashMap();
+ for (Element element : subcomponentElements) {
+ ComponentValidationReport report = subcomponentValidator.validate(
+ MoreElements.asType(element), subcomponentElements, subcomponentBuilderElements);
+ report.report().printMessagesTo(messager);
+ reportsBySubcomponent.put(element, report.report());
+ }
+ return reportsBySubcomponent;
+ }
+
+ /**
+ * Returns true if the component's report is clean, its builder report is clean, and all
+ * referenced subcomponent reports & subcomponent builder reports are clean.
+ */
+ private boolean isClean(ComponentValidationReport report,
+ Map<Element, ValidationReport<TypeElement>> builderReportsByComponent,
+ Map<Element, ValidationReport<TypeElement>> reportsBySubcomponent,
+ Map<Element, ValidationReport<TypeElement>> builderReportsBySubcomponent) {
+ Element component = report.report().subject();
+ ValidationReport<?> componentReport = report.report();
+ if (!componentReport.isClean()) {
+ return false;
+ }
+ ValidationReport<?> builderReport = builderReportsByComponent.get(component);
+ if (builderReport != null && !builderReport.isClean()) {
+ return false;
+ }
+ for (Element element : report.referencedSubcomponents()) {
+ ValidationReport<?> subcomponentBuilderReport = builderReportsBySubcomponent.get(element);
+ if (subcomponentBuilderReport != null && !subcomponentBuilderReport.isClean()) {
+ return false;
+ }
+ ValidationReport<?> subcomponentReport = reportsBySubcomponent.get(element);
+ if (subcomponentReport != null && !subcomponentReport.isClean()) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java
new file mode 100644
index 000000000..1e96a534a
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.BasicAnnotationProcessor;
+import com.google.auto.service.AutoService;
+import com.google.common.base.Ascii;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import dagger.Module;
+import dagger.Provides;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.lang.annotation.Annotation;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.Messager;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.Processor;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+/**
+ * The annotation processor responsible for generating the classes that drive the Dagger 2.0
+ * implementation.
+ *
+ * TODO(gak): give this some better documentation
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@AutoService(Processor.class)
+public final class ComponentProcessor extends BasicAnnotationProcessor {
+ private InjectBindingRegistry injectBindingRegistry;
+ private FactoryGenerator factoryGenerator;
+ private MembersInjectorGenerator membersInjectorGenerator;
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latestSupported();
+ }
+
+ @Override
+ public Set<String> getSupportedOptions() {
+ return ImmutableSet.of(
+ DISABLE_INTER_COMPONENT_SCOPE_VALIDATION_KEY,
+ NULLABLE_VALIDATION_KEY,
+ PRIVATE_MEMBER_VALIDATION_TYPE_KEY,
+ STATIC_MEMBER_VALIDATION_TYPE_KEY
+ );
+ }
+
+ @Override
+ protected Iterable<ProcessingStep> initSteps() {
+ Messager messager = processingEnv.getMessager();
+ Types types = processingEnv.getTypeUtils();
+ Elements elements = processingEnv.getElementUtils();
+ Filer filer = processingEnv.getFiler();
+
+ Diagnostic.Kind nullableDiagnosticType =
+ nullableValidationType(processingEnv).diagnosticKind().get();
+
+ MethodSignatureFormatter methodSignatureFormatter = new MethodSignatureFormatter(types);
+ ProvisionBindingFormatter provisionBindingFormatter =
+ new ProvisionBindingFormatter(methodSignatureFormatter);
+ ProductionBindingFormatter productionBindingFormatter =
+ new ProductionBindingFormatter(methodSignatureFormatter);
+ DependencyRequestFormatter dependencyRequestFormatter = new DependencyRequestFormatter(types);
+ KeyFormatter keyFormatter = new KeyFormatter();
+
+ InjectConstructorValidator injectConstructorValidator = new InjectConstructorValidator();
+ InjectFieldValidator injectFieldValidator = new InjectFieldValidator(
+ privateMemberValidationType(processingEnv).diagnosticKind().get(),
+ staticMemberValidationType(processingEnv).diagnosticKind().get());
+ InjectMethodValidator injectMethodValidator = new InjectMethodValidator(
+ privateMemberValidationType(processingEnv).diagnosticKind().get(),
+ staticMemberValidationType(processingEnv).diagnosticKind().get());
+ ModuleValidator moduleValidator =
+ new ModuleValidator(
+ types,
+ elements,
+ methodSignatureFormatter,
+ Module.class,
+ ImmutableList.<Class<? extends Annotation>>of(Module.class),
+ Provides.class);
+ ProvidesMethodValidator providesMethodValidator = new ProvidesMethodValidator(elements);
+ BuilderValidator componentBuilderValidator =
+ new BuilderValidator(elements, types, ComponentDescriptor.Kind.COMPONENT);
+ BuilderValidator subcomponentBuilderValidator =
+ new BuilderValidator(elements, types, ComponentDescriptor.Kind.SUBCOMPONENT);
+ ComponentValidator subcomponentValidator = ComponentValidator.createForSubcomponent(elements,
+ types, moduleValidator, subcomponentBuilderValidator);
+ ComponentValidator componentValidator = ComponentValidator.createForComponent(elements, types,
+ moduleValidator, subcomponentValidator, subcomponentBuilderValidator);
+ MapKeyValidator mapKeyValidator = new MapKeyValidator();
+ ModuleValidator producerModuleValidator =
+ new ModuleValidator(
+ types,
+ elements,
+ methodSignatureFormatter,
+ ProducerModule.class,
+ ImmutableList.of(Module.class, ProducerModule.class),
+ Produces.class);
+ ProducesMethodValidator producesMethodValidator = new ProducesMethodValidator(elements);
+ ProductionComponentValidator productionComponentValidator = new ProductionComponentValidator();
+
+ Key.Factory keyFactory = new Key.Factory(types, elements);
+
+ this.factoryGenerator =
+ new FactoryGenerator(filer, DependencyRequestMapper.FOR_PROVIDER, nullableDiagnosticType);
+ this.membersInjectorGenerator =
+ new MembersInjectorGenerator(filer, DependencyRequestMapper.FOR_PROVIDER);
+ ComponentGenerator componentGenerator =
+ new ComponentGenerator(filer, elements, types, keyFactory, nullableDiagnosticType);
+ ProducerFactoryGenerator producerFactoryGenerator =
+ new ProducerFactoryGenerator(filer, DependencyRequestMapper.FOR_PRODUCER);
+
+ DependencyRequest.Factory dependencyRequestFactory = new DependencyRequest.Factory(keyFactory);
+ ProvisionBinding.Factory provisionBindingFactory =
+ new ProvisionBinding.Factory(elements, types, keyFactory, dependencyRequestFactory);
+ ProductionBinding.Factory productionBindingFactory =
+ new ProductionBinding.Factory(types, keyFactory, dependencyRequestFactory);
+
+ MembersInjectionBinding.Factory membersInjectionBindingFactory =
+ new MembersInjectionBinding.Factory(elements, types, keyFactory, dependencyRequestFactory);
+
+ this.injectBindingRegistry = new InjectBindingRegistry(
+ elements, types, messager, provisionBindingFactory, membersInjectionBindingFactory);
+
+ ModuleDescriptor.Factory moduleDescriptorFactory = new ModuleDescriptor.Factory(
+ elements, provisionBindingFactory, productionBindingFactory);
+
+ ComponentDescriptor.Factory componentDescriptorFactory = new ComponentDescriptor.Factory(
+ elements, types, dependencyRequestFactory, moduleDescriptorFactory);
+
+ BindingGraph.Factory bindingGraphFactory = new BindingGraph.Factory(
+ elements,
+ injectBindingRegistry,
+ keyFactory,
+ dependencyRequestFactory,
+ provisionBindingFactory,
+ productionBindingFactory);
+
+ MapKeyGenerator mapKeyGenerator = new MapKeyGenerator(filer);
+ ComponentHierarchyValidator componentHierarchyValidator = new ComponentHierarchyValidator();
+ BindingGraphValidator bindingGraphValidator =
+ new BindingGraphValidator(
+ types,
+ injectBindingRegistry,
+ scopeValidationType(processingEnv),
+ nullableDiagnosticType,
+ provisionBindingFormatter,
+ productionBindingFormatter,
+ methodSignatureFormatter,
+ dependencyRequestFormatter,
+ keyFormatter);
+
+ return ImmutableList.<ProcessingStep>of(
+ new MapKeyProcessingStep(messager, types, mapKeyValidator, mapKeyGenerator),
+ new InjectProcessingStep(
+ messager,
+ injectConstructorValidator,
+ injectFieldValidator,
+ injectMethodValidator,
+ provisionBindingFactory,
+ membersInjectionBindingFactory,
+ injectBindingRegistry),
+ new ModuleProcessingStep(
+ messager,
+ moduleValidator,
+ providesMethodValidator,
+ provisionBindingFactory,
+ factoryGenerator),
+ new ComponentProcessingStep(
+ messager,
+ componentValidator,
+ subcomponentValidator,
+ componentBuilderValidator,
+ subcomponentBuilderValidator,
+ componentHierarchyValidator,
+ bindingGraphValidator,
+ componentDescriptorFactory,
+ bindingGraphFactory,
+ componentGenerator),
+ new ProducerModuleProcessingStep(
+ messager,
+ producerModuleValidator,
+ producesMethodValidator,
+ productionBindingFactory,
+ producerFactoryGenerator),
+ new ProductionComponentProcessingStep(
+ messager,
+ productionComponentValidator,
+ componentHierarchyValidator,
+ bindingGraphValidator,
+ componentDescriptorFactory,
+ bindingGraphFactory,
+ componentGenerator));
+ }
+
+ @Override
+ protected void postProcess() {
+ try {
+ injectBindingRegistry.generateSourcesForRequiredBindings(
+ factoryGenerator, membersInjectorGenerator);
+ } catch (SourceFileGenerationException e) {
+ e.printMessageTo(processingEnv.getMessager());
+ }
+ }
+
+ private static final String DISABLE_INTER_COMPONENT_SCOPE_VALIDATION_KEY =
+ "dagger.disableInterComponentScopeValidation";
+
+ private static final String NULLABLE_VALIDATION_KEY = "dagger.nullableValidation";
+
+ private static final String PRIVATE_MEMBER_VALIDATION_TYPE_KEY =
+ "dagger.privateMemberValidation";
+
+ private static final String STATIC_MEMBER_VALIDATION_TYPE_KEY =
+ "dagger.staticMemberValidation";
+
+ private static ValidationType scopeValidationType(ProcessingEnvironment processingEnv) {
+ return valueOf(processingEnv,
+ DISABLE_INTER_COMPONENT_SCOPE_VALIDATION_KEY,
+ ValidationType.ERROR,
+ EnumSet.allOf(ValidationType.class));
+ }
+
+ private static ValidationType nullableValidationType(ProcessingEnvironment processingEnv) {
+ return valueOf(processingEnv,
+ NULLABLE_VALIDATION_KEY,
+ ValidationType.ERROR,
+ EnumSet.of(ValidationType.ERROR, ValidationType.WARNING));
+ }
+
+ private static ValidationType privateMemberValidationType(ProcessingEnvironment processingEnv) {
+ return valueOf(processingEnv,
+ PRIVATE_MEMBER_VALIDATION_TYPE_KEY,
+ ValidationType.ERROR,
+ EnumSet.of(ValidationType.ERROR, ValidationType.WARNING));
+ }
+
+ private static ValidationType staticMemberValidationType(ProcessingEnvironment processingEnv) {
+ return valueOf(processingEnv,
+ STATIC_MEMBER_VALIDATION_TYPE_KEY,
+ ValidationType.ERROR,
+ EnumSet.of(ValidationType.ERROR, ValidationType.WARNING));
+ }
+
+ private static <T extends Enum<T>> T valueOf(ProcessingEnvironment processingEnv, String key,
+ T defaultValue, Set<T> validValues) {
+ Map<String, String> options = processingEnv.getOptions();
+ if (options.containsKey(key)) {
+ try {
+ T type = Enum.valueOf(
+ defaultValue.getDeclaringClass(),
+ Ascii.toUpperCase(options.get(key)));
+ if (!validValues.contains(type)) {
+ throw new IllegalArgumentException(); // let handler below print out good msg.
+ }
+ return type;
+ } catch (IllegalArgumentException e) {
+ processingEnv.getMessager().printMessage(ERROR, "Processor option -A"
+ + key + " may only have the values " + validValues
+ + " (case insensitive), found: " + options.get(key));
+ }
+ }
+ return defaultValue;
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentValidator.java b/compiler/src/main/java/dagger/internal/codegen/ComponentValidator.java
new file mode 100644
index 000000000..58fe1ca0c
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ComponentValidator.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
+import dagger.Component;
+import dagger.Module;
+import dagger.Subcomponent;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+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.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.Types;
+
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static dagger.internal.codegen.ConfigurationAnnotations.enclosedBuilders;
+import static dagger.internal.codegen.ConfigurationAnnotations.getComponentModules;
+import static dagger.internal.codegen.ConfigurationAnnotations.getTransitiveModules;
+import static dagger.internal.codegen.Util.componentCanMakeNewInstances;
+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;
+
+/**
+ * Performs superficial validation of the contract of the {@link Component} annotation.
+ *
+ * @author Gregory Kick
+ */
+final class ComponentValidator {
+ private final Elements elements;
+ private final Types types;
+ private final ComponentDescriptor.Kind componentType;
+ private final ModuleValidator moduleValidator;
+ private final ComponentValidator subcomponentValidator;
+ private final BuilderValidator subcomponentBuilderValidator;
+
+ private ComponentValidator(Elements elements,
+ Types types,
+ ModuleValidator moduleValidator,
+ BuilderValidator subcomponentBuilderValidator) {
+ this.elements = elements;
+ this.types = types;
+ this.componentType = ComponentDescriptor.Kind.SUBCOMPONENT;
+ this.moduleValidator = moduleValidator;
+ this.subcomponentValidator = this;
+ this.subcomponentBuilderValidator = subcomponentBuilderValidator;
+ }
+
+ private ComponentValidator(Elements elements,
+ Types types,
+ ModuleValidator moduleValidator,
+ ComponentValidator subcomponentValidator,
+ BuilderValidator subcomponentBuilderValidator) {
+ this.elements = elements;
+ this.types = types;
+ this.componentType = ComponentDescriptor.Kind.COMPONENT;
+ this.moduleValidator = moduleValidator;
+ this.subcomponentValidator = subcomponentValidator;
+ this.subcomponentBuilderValidator = subcomponentBuilderValidator;
+ }
+
+ static ComponentValidator createForComponent(Elements elements,
+ Types types,
+ ModuleValidator moduleValidator,
+ ComponentValidator subcomponentValidator,
+ BuilderValidator subcomponentBuilderValidator) {
+ return new ComponentValidator(elements,
+ types,
+ moduleValidator,
+ subcomponentValidator,
+ subcomponentBuilderValidator);
+ }
+
+ static ComponentValidator createForSubcomponent(Elements elements,
+ Types types,
+ ModuleValidator moduleValidator,
+ BuilderValidator subcomponentBuilderValidator) {
+ return new ComponentValidator(elements,
+ types,
+ moduleValidator,
+ subcomponentBuilderValidator);
+ }
+
+ @AutoValue
+ static abstract class ComponentValidationReport {
+ abstract Set<Element> referencedSubcomponents();
+ abstract ValidationReport<TypeElement> report();
+ }
+
+ /**
+ * Validates the given component subject. Also validates any referenced subcomponents that aren't
+ * already included in the {@code validatedSubcomponents} set.
+ */
+ public ComponentValidationReport validate(final TypeElement subject,
+ Set<? extends Element> validatedSubcomponents,
+ Set<? extends Element> validatedSubcomponentBuilders) {
+ ValidationReport.Builder<TypeElement> builder = ValidationReport.about(subject);
+
+ if (!subject.getKind().equals(INTERFACE)
+ && !(subject.getKind().equals(CLASS) && subject.getModifiers().contains(ABSTRACT))) {
+ builder.addError(
+ String.format(
+ "@%s may only be applied to an interface or abstract class",
+ componentType.annotationType().getSimpleName()),
+ subject);
+ }
+
+ ImmutableList<DeclaredType> builders =
+ enclosedBuilders(subject, componentType.builderAnnotationType());
+ if (builders.size() > 1) {
+ builder.addError(
+ String.format(ErrorMessages.builderMsgsFor(componentType).moreThanOne(), builders),
+ subject);
+ }
+
+ DeclaredType subjectType = MoreTypes.asDeclared(subject.asType());
+
+ // TODO(gak): This should use Util.findLocalAndInheritedMethods, otherwise
+ // it can return a logical method multiple times (including overrides, etc.)
+ List<? extends Element> members = elements.getAllMembers(subject);
+ Multimap<Element, ExecutableElement> referencedSubcomponents = LinkedHashMultimap.create();
+ for (ExecutableElement method : ElementFilter.methodsIn(members)) {
+ if (method.getModifiers().contains(ABSTRACT)) {
+ ExecutableType resolvedMethod =
+ MoreTypes.asExecutable(types.asMemberOf(subjectType, method));
+ List<? extends TypeMirror> parameterTypes = resolvedMethod.getParameterTypes();
+ List<? extends VariableElement> parameters = method.getParameters();
+ TypeMirror returnType = resolvedMethod.getReturnType();
+
+ // 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 =
+ checkForAnnotation(returnType, Subcomponent.class);
+ Optional<AnnotationMirror> subcomponentBuilderAnnotation =
+ checkForAnnotation(returnType, Subcomponent.Builder.class);
+ if (subcomponentAnnotation.isPresent()) {
+ referencedSubcomponents.put(MoreTypes.asElement(returnType), method);
+ validateSubcomponentMethod(builder,
+ method,
+ parameters,
+ parameterTypes,
+ returnType,
+ subcomponentAnnotation);
+ } else if (subcomponentBuilderAnnotation.isPresent()) {
+ referencedSubcomponents.put(MoreTypes.asElement(returnType).getEnclosingElement(),
+ method);
+ validateSubcomponentBuilderMethod(builder,
+ method,
+ parameters,
+ returnType,
+ validatedSubcomponentBuilders);
+ } else {
+ // if it's not a subcomponent...
+ switch (parameters.size()) {
+ case 0:
+ // no parameters means that it is a provision method
+ // basically, there are no restrictions here. \o/
+ break;
+ case 1:
+ // one parameter means that it's a members injection method
+ TypeMirror onlyParameter = Iterables.getOnlyElement(parameterTypes);
+ if (!(returnType.getKind().equals(VOID)
+ || types.isSameType(returnType, onlyParameter))) {
+ builder.addError(
+ "Members injection methods may only return the injected type or void.", method);
+ }
+ break;
+ default:
+ // this isn't any method that we know how to implement...
+ builder.addError(
+ "This method isn't a valid provision method, members injection method or "
+ + "subcomponent factory method. Dagger cannot implement this method",
+ method);
+ break;
+ }
+ }
+ }
+ }
+
+ for (Map.Entry<Element, Collection<ExecutableElement>> entry :
+ referencedSubcomponents.asMap().entrySet()) {
+ if (entry.getValue().size() > 1) {
+ builder.addError(
+ String.format(
+ ErrorMessages.SubcomponentBuilderMessages.INSTANCE.moreThanOneRefToSubcomponent(),
+ entry.getKey(),
+ entry.getValue()),
+ subject);
+ }
+ }
+
+ AnnotationMirror componentMirror =
+ getAnnotationMirror(subject, componentType.annotationType()).get();
+ ImmutableList<TypeMirror> moduleTypes = getComponentModules(componentMirror);
+ moduleValidator.validateReferencedModules(subject, builder, moduleTypes);
+
+ // Make sure we validate any subcomponents we're referencing, unless we know we validated
+ // them already in this pass.
+ // TODO(sameb): If subcomponents refer to each other and both aren't in
+ // 'validatedSubcomponents' (e.g, both aren't compiled in this pass),
+ // then this can loop forever.
+ ImmutableSet.Builder<Element> allSubcomponents =
+ ImmutableSet.<Element>builder().addAll(referencedSubcomponents.keySet());
+ for (Element subcomponent :
+ Sets.difference(referencedSubcomponents.keySet(), validatedSubcomponents)) {
+ ComponentValidationReport subreport = subcomponentValidator.validate(
+ MoreElements.asType(subcomponent), validatedSubcomponents, validatedSubcomponentBuilders);
+ builder.addItems(subreport.report().items());
+ allSubcomponents.addAll(subreport.referencedSubcomponents());
+ }
+
+ return new AutoValue_ComponentValidator_ComponentValidationReport(allSubcomponents.build(),
+ builder.build());
+ }
+
+ private void validateSubcomponentMethod(final ValidationReport.Builder<TypeElement> builder,
+ ExecutableElement method,
+ List<? extends VariableElement> parameters,
+ List<? extends TypeMirror> parameterTypes,
+ TypeMirror returnType,
+ Optional<AnnotationMirror> subcomponentAnnotation) {
+ ImmutableSet<TypeElement> moduleTypes =
+ MoreTypes.asTypeElements(getComponentModules(subcomponentAnnotation.get()));
+
+ // 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
+ ImmutableSet<TypeElement> transitiveModules =
+ getTransitiveModules(types, elements, moduleTypes);
+
+ ImmutableSet<TypeElement> requiredModules =
+ FluentIterable.from(transitiveModules)
+ .filter(new Predicate<TypeElement>() {
+ @Override public boolean apply(TypeElement input) {
+ return !componentCanMakeNewInstances(input);
+ }
+ })
+ .toSet();
+
+ Set<TypeElement> variableTypes = 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 SimpleTypeVisitor6<Optional<TypeElement>, Void>() {
+ @Override protected Optional<TypeElement> defaultAction(TypeMirror e, Void p) {
+ return Optional.absent();
+ }
+
+ @Override public Optional<TypeElement> visitDeclared(DeclaredType t, Void p) {
+ return MoreElements.isAnnotationPresent(t.asElement(), Module.class)
+ ? Optional.of(MoreTypes.asTypeElement(t))
+ : Optional.<TypeElement>absent();
+ }
+ }, null);
+ if (moduleType.isPresent()) {
+ if (variableTypes.contains(moduleType.get())) {
+ builder.addError(
+ String.format(
+ "A module may only occur once an an argument in a Subcomponent factory "
+ + "method, but %s was already passed.",
+ moduleType.get().getQualifiedName()),
+ parameter);
+ }
+ if (!transitiveModules.contains(moduleType.get())) {
+ builder.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()),
+ method);
+ }
+ variableTypes.add(moduleType.get());
+ } else {
+ builder.addError(
+ String.format(
+ "Subcomponent factory methods may only accept modules, but %s is not.",
+ parameterType),
+ parameter);
+ }
+ }
+
+ SetView<TypeElement> missingModules =
+ Sets.difference(requiredModules, ImmutableSet.copyOf(variableTypes));
+ if (!missingModules.isEmpty()) {
+ builder.addError(
+ String.format(
+ "%s requires modules which have no visible default constructors. "
+ + "Add the following modules as parameters to this method: %s",
+ MoreTypes.asTypeElement(returnType).getQualifiedName(),
+ Joiner.on(", ").join(missingModules)),
+ method);
+ }
+ }
+
+ private void validateSubcomponentBuilderMethod(ValidationReport.Builder<TypeElement> builder,
+ ExecutableElement method, List<? extends VariableElement> parameters, TypeMirror returnType,
+ Set<? extends Element> validatedSubcomponentBuilders) {
+
+ if (!parameters.isEmpty()) {
+ builder.addError(
+ ErrorMessages.SubcomponentBuilderMessages.INSTANCE.builderMethodRequiresNoArgs(), method);
+ }
+
+ // If we haven't already validated the subcomponent builder itself, validate it now.
+ TypeElement builderElement = MoreTypes.asTypeElement(returnType);
+ if (!validatedSubcomponentBuilders.contains(builderElement)) {
+ // TODO(sameb): The builder 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.
+ builder.addItems(subcomponentBuilderValidator.validate(builderElement).items());
+ }
+ }
+
+ private Optional<AnnotationMirror> checkForAnnotation(TypeMirror type,
+ final Class<? extends Annotation> annotation) {
+ return type.accept(new SimpleTypeVisitor6<Optional<AnnotationMirror>, Void>() {
+ @Override
+ protected Optional<AnnotationMirror> defaultAction(TypeMirror e, Void p) {
+ return Optional.absent();
+ }
+
+ @Override
+ public Optional<AnnotationMirror> visitDeclared(DeclaredType t, Void p) {
+ return MoreElements.getAnnotationMirror(t.asElement(), annotation);
+ }
+ }, null);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentWriter.java b/compiler/src/main/java/dagger/internal/codegen/ComponentWriter.java
new file mode 100644
index 000000000..5221cf0a2
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ComponentWriter.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.base.Predicate;
+import com.google.common.collect.Iterables;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ClassWriter;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.MethodWriter;
+import javax.annotation.Generated;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic.Kind;
+
+import static dagger.internal.codegen.Util.componentCanMakeNewInstances;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * Creates the implementation class for a component.
+ */
+class ComponentWriter extends AbstractComponentWriter {
+
+ ComponentWriter(
+ Types types,
+ Elements elements,
+ Key.Factory keyFactory,
+ Kind nullableValidationType,
+ ClassName name,
+ BindingGraph graph) {
+ super(types, elements, keyFactory, nullableValidationType, name, graph);
+ }
+
+ @Override
+ protected ClassWriter createComponentClass() {
+ JavaWriter javaWriter = JavaWriter.inPackage(name.packageName());
+ javaWriters.add(javaWriter);
+
+ ClassWriter componentWriter = javaWriter.addClass(name.simpleName());
+ componentWriter.annotate(Generated.class).setValue(ComponentProcessor.class.getCanonicalName());
+ componentWriter.addModifiers(PUBLIC, FINAL);
+ componentWriter.setSupertype(componentDefinitionType());
+ return componentWriter;
+ }
+
+ @Override
+ protected ClassWriter createBuilder() {
+ ClassWriter builderWriter = componentWriter.addNestedClass("Builder");
+ builderWriter.addModifiers(STATIC);
+
+ // Only top-level components have the factory builder() method.
+ // Mirror the user's builder API type if they had one.
+ MethodWriter builderFactoryMethod =
+ graph.componentDescriptor().builderSpec().isPresent()
+ ? componentWriter.addMethod(
+ graph
+ .componentDescriptor()
+ .builderSpec()
+ .get()
+ .builderDefinitionType()
+ .asType(),
+ "builder")
+ : componentWriter.addMethod(builderWriter, "builder");
+ builderFactoryMethod.addModifiers(PUBLIC, STATIC);
+ builderFactoryMethod.body().addSnippet("return new %s();", builderWriter.name());
+ return builderWriter;
+ }
+
+ @Override
+ protected void addFactoryMethods() {
+ if (canInstantiateAllRequirements()) {
+ MethodWriter factoryMethod =
+ componentWriter.addMethod(componentDefinitionTypeName(), "create");
+ factoryMethod.addModifiers(PUBLIC, STATIC);
+ // TODO(gak): replace this with something that doesn't allocate a builder
+ factoryMethod
+ .body()
+ .addSnippet(
+ "return builder().%s();",
+ graph.componentDescriptor().builderSpec().isPresent()
+ ? graph
+ .componentDescriptor()
+ .builderSpec()
+ .get()
+ .buildMethod()
+ .getSimpleName()
+ : "build");
+ }
+ }
+
+ /** {@code true} if all of the graph's required dependencies can be automatically constructed. */
+ private boolean canInstantiateAllRequirements() {
+ return Iterables.all(
+ graph.componentRequirements(),
+ new Predicate<TypeElement>() {
+ @Override
+ public boolean apply(TypeElement dependency) {
+ return componentCanMakeNewInstances(dependency);
+ }
+ });
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java b/compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java
new file mode 100644
index 000000000..50e343543
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import dagger.Component;
+import dagger.Module;
+import dagger.Subcomponent;
+import dagger.producers.ProducerModule;
+import dagger.producers.ProductionComponent;
+import java.lang.annotation.Annotation;
+import java.util.ArrayDeque;
+import java.util.List;
+import java.util.Queue;
+import java.util.Set;
+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.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleAnnotationValueVisitor6;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.Types;
+
+import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Utility methods related to dagger configuration annotations (e.g.: {@link Component}
+ * and {@link Module}).
+ *
+ * @author Gregory Kick
+ */
+final class ConfigurationAnnotations {
+
+ static boolean isComponent(TypeElement componentDefinitionType) {
+ return MoreElements.isAnnotationPresent(componentDefinitionType, Component.class)
+ || MoreElements.isAnnotationPresent(componentDefinitionType, ProductionComponent.class);
+ }
+
+ private static final String MODULES_ATTRIBUTE = "modules";
+
+ static ImmutableList<TypeMirror> getComponentModules(AnnotationMirror componentAnnotation) {
+ checkNotNull(componentAnnotation);
+ return convertClassArrayToListOfTypes(componentAnnotation, MODULES_ATTRIBUTE);
+ }
+
+ private static final String DEPENDENCIES_ATTRIBUTE = "dependencies";
+
+ static ImmutableList<TypeMirror> getComponentDependencies(AnnotationMirror componentAnnotation) {
+ checkNotNull(componentAnnotation);
+ return convertClassArrayToListOfTypes(componentAnnotation, DEPENDENCIES_ATTRIBUTE);
+ }
+
+ private static final String INCLUDES_ATTRIBUTE = "includes";
+
+ static ImmutableList<TypeMirror> getModuleIncludes(AnnotationMirror moduleAnnotation) {
+ checkNotNull(moduleAnnotation);
+ return convertClassArrayToListOfTypes(moduleAnnotation, INCLUDES_ATTRIBUTE);
+ }
+
+ private static final String INJECTS_ATTRIBUTE = "injects";
+
+ static ImmutableList<TypeMirror> getModuleInjects(AnnotationMirror moduleAnnotation) {
+ checkNotNull(moduleAnnotation);
+ return convertClassArrayToListOfTypes(moduleAnnotation, INJECTS_ATTRIBUTE);
+ }
+
+ /** Returns the first type that specifies this' nullability, or absent if none. */
+ static Optional<DeclaredType> getNullableType(Element element) {
+ List<? extends AnnotationMirror> mirrors = element.getAnnotationMirrors();
+ for (AnnotationMirror mirror : mirrors) {
+ if (mirror.getAnnotationType().asElement().getSimpleName().toString().equals("Nullable")) {
+ return Optional.of(mirror.getAnnotationType());
+ }
+ }
+ return Optional.absent();
+ }
+
+ /**
+ * Extracts the list of types that is the value of the annotation member {@code elementName} of
+ * {@code annotationMirror}.
+ *
+ * @throws IllegalArgumentException if no such member exists on {@code annotationMirror}, or it
+ * exists but is not an array
+ * @throws TypeNotPresentException if any of the values cannot be converted to a type
+ */
+ static ImmutableList<TypeMirror> convertClassArrayToListOfTypes(
+ AnnotationMirror annotationMirror, String elementName) {
+ return TO_LIST_OF_TYPES.visit(getAnnotationValue(annotationMirror, elementName), elementName);
+ }
+
+ private static final AnnotationValueVisitor<ImmutableList<TypeMirror>, String> TO_LIST_OF_TYPES =
+ new SimpleAnnotationValueVisitor6<ImmutableList<TypeMirror>, String>() {
+ @Override
+ public ImmutableList<TypeMirror> visitArray(
+ List<? extends AnnotationValue> vals, String elementName) {
+ return FluentIterable.from(vals)
+ .transform(
+ new Function<AnnotationValue, TypeMirror>() {
+ @Override
+ public TypeMirror apply(AnnotationValue typeValue) {
+ return TO_TYPE.visit(typeValue);
+ }
+ })
+ .toList();
+ }
+
+ @Override
+ protected ImmutableList<TypeMirror> defaultAction(Object o, String elementName) {
+ throw new IllegalArgumentException(elementName + " is not an array: " + o);
+ }
+ };
+
+ private static final AnnotationValueVisitor<TypeMirror, Void> TO_TYPE =
+ new SimpleAnnotationValueVisitor6<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 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#transitiveModules}.
+ */
+ @Deprecated
+ static ImmutableSet<TypeElement> getTransitiveModules(
+ Types types, Elements elements, Iterable<TypeElement> seedModules) {
+ TypeMirror objectType = elements.getTypeElement(Object.class.getCanonicalName()).asType();
+ Queue<TypeElement> moduleQueue = new ArrayDeque<>();
+ Iterables.addAll(moduleQueue, seedModules);
+ Set<TypeElement> moduleElements = Sets.newLinkedHashSet();
+ for (TypeElement moduleElement = moduleQueue.poll();
+ moduleElement != null;
+ moduleElement = moduleQueue.poll()) {
+ Optional<AnnotationMirror> moduleMirror = getAnnotationMirror(moduleElement, Module.class)
+ .or(getAnnotationMirror(moduleElement, ProducerModule.class));
+ if (moduleMirror.isPresent()) {
+ ImmutableSet.Builder<TypeElement> moduleDependenciesBuilder = ImmutableSet.builder();
+ moduleDependenciesBuilder.addAll(
+ MoreTypes.asTypeElements(getModuleIncludes(moduleMirror.get())));
+ // (note: we don't recurse 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 elements annotated with the given annotation type. */
+ static ImmutableList<DeclaredType> enclosedBuilders(TypeElement typeElement,
+ final Class<? extends Annotation> annotation) {
+ final ImmutableList.Builder<DeclaredType> builders = ImmutableList.builder();
+ for (TypeElement element : ElementFilter.typesIn(typeElement.getEnclosedElements())) {
+ if (MoreElements.isAnnotationPresent(element, annotation)) {
+ builders.add(MoreTypes.asDeclared(element.asType()));
+ }
+ }
+ return builders.build();
+ }
+
+ static boolean isSubcomponentType(TypeMirror type) {
+ return type.accept(new SubcomponentDetector(), null).isPresent();
+ }
+
+ private static final class SubcomponentDetector
+ extends SimpleTypeVisitor6<Optional<AnnotationMirror>, Void> {
+ @Override
+ protected Optional<AnnotationMirror> defaultAction(TypeMirror e, Void p) {
+ return Optional.absent();
+ }
+
+ @Override
+ public Optional<AnnotationMirror> visitDeclared(DeclaredType t, Void p) {
+ return MoreElements.getAnnotationMirror(t.asElement(), Subcomponent.class);
+ }
+ }
+
+ /** Traverses includes from superclasses and adds them into the builder. */
+ private static void addIncludesFromSuperclasses(Types 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));
+ Optional<AnnotationMirror> moduleMirror = getAnnotationMirror(element, Module.class)
+ .or(getAnnotationMirror(element, ProducerModule.class));
+ if (moduleMirror.isPresent()) {
+ builder.addAll(MoreTypes.asTypeElements(getModuleIncludes(moduleMirror.get())));
+ }
+ superclass = element.getSuperclass();
+ }
+ }
+
+ private ConfigurationAnnotations() {}
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ContributionBinding.java b/compiler/src/main/java/dagger/internal/codegen/ContributionBinding.java
new file mode 100644
index 000000000..a0a4dc148
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ContributionBinding.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreTypes;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Equivalence.Wrapper;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.Ordering;
+import dagger.MapKey;
+import java.util.EnumSet;
+import java.util.Set;
+import javax.inject.Provider;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.MapKeys.getMapKey;
+import static dagger.internal.codegen.MapKeys.unwrapValue;
+
+/**
+ * An abstract class for a value object representing the mechanism by which a {@link Key} can be
+ * contributed to a dependency graph.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+abstract class ContributionBinding extends Binding {
+ static enum BindingType {
+ /** Represents map bindings. */
+ MAP,
+ /** Represents set bindings. */
+ SET,
+ /** Represents a valid non-collection binding. */
+ UNIQUE;
+
+ boolean isMultibinding() {
+ return !this.equals(UNIQUE);
+ }
+ }
+
+ abstract BindingType bindingType();
+
+ /** Returns the type that specifies this' nullability, absent if not nullable. */
+ abstract Optional<DeclaredType> nullableType();
+
+ /**
+ * If this is a provision request from an {@code @Provides} or {@code @Produces} method, this will
+ * be the element that contributed it. In the case of subclassed modules, this may differ than the
+ * binding's enclosed element, as this will return the subclass whereas the enclosed element will
+ * be the superclass.
+ */
+ abstract Optional<TypeElement> contributedBy();
+
+ /**
+ * Returns whether this binding is synthetic, i.e., not explicitly tied to code, but generated
+ * implicitly by the framework.
+ */
+ // TODO(user): Remove the SYNTHETIC enums from ProvisionBinding and ProductionBinding and make
+ // this field the source of truth for synthetic bindings.
+ abstract boolean isSyntheticBinding();
+
+ /**
+ * Returns the framework class associated with this binding, e.g., {@link Provider} for a
+ * ProvisionBinding.
+ */
+ abstract Class<?> frameworkClass();
+
+ /**
+ * Returns the set of {@link BindingType} enum values implied by a given
+ * {@link ContributionBinding} collection.
+ */
+ static <B extends ContributionBinding> ImmutableListMultimap<BindingType, B> bindingTypesFor(
+ Iterable<? extends B> bindings) {
+ ImmutableListMultimap.Builder<BindingType, B> builder =
+ ImmutableListMultimap.builder();
+ builder.orderKeysBy(Ordering.<BindingType>natural());
+ for (B binding : bindings) {
+ builder.put(binding.bindingType(), binding);
+ }
+ return builder.build();
+ }
+
+ /**
+ * Returns a single {@code BindingsType} represented by a given collection of
+ * {@code ContributionBindings} or throws an IllegalArgumentException if the given bindings
+ * are not all of one type.
+ */
+ static BindingType bindingTypeFor(Iterable<? extends ContributionBinding> bindings) {
+ checkNotNull(bindings);
+ checkArgument(!Iterables.isEmpty(bindings), "no bindings");
+ Set<BindingType> types = EnumSet.noneOf(BindingType.class);
+ for (ContributionBinding binding : bindings) {
+ types.add(binding.bindingType());
+ }
+ if (types.size() > 1) {
+ throw new IllegalArgumentException(
+ String.format(ErrorMessages.MULTIPLE_BINDING_TYPES_FORMAT, types));
+ }
+ return Iterables.getOnlyElement(types);
+ }
+
+ /**
+ * Indexes map-multibindings by map key (the result of calling
+ * {@link AnnotationValue#getValue()} on a single member or the whole {@link AnnotationMirror}
+ * itself, depending on {@link MapKey#unwrapValue()}).
+ */
+ static ImmutableSetMultimap<Object, ContributionBinding> indexMapBindingsByMapKey(
+ Set<ContributionBinding> mapBindings) {
+ return ImmutableSetMultimap.copyOf(
+ Multimaps.index(
+ mapBindings,
+ new Function<ContributionBinding, Object>() {
+ @Override
+ public Object apply(ContributionBinding mapBinding) {
+ AnnotationMirror mapKey = getMapKey(mapBinding.bindingElement()).get();
+ Optional<? extends AnnotationValue> unwrappedValue = unwrapValue(mapKey);
+ return unwrappedValue.isPresent() ? unwrappedValue.get().getValue() : mapKey;
+ }
+ }));
+ }
+
+ /**
+ * Indexes map-multibindings by map key annotation type.
+ */
+ static ImmutableSetMultimap<Wrapper<DeclaredType>, ContributionBinding>
+ indexMapBindingsByAnnotationType(Set<ContributionBinding> mapBindings) {
+ return ImmutableSetMultimap.copyOf(
+ Multimaps.index(
+ mapBindings,
+ new Function<ContributionBinding, Equivalence.Wrapper<DeclaredType>>() {
+ @Override
+ public Equivalence.Wrapper<DeclaredType> apply(ContributionBinding mapBinding) {
+ return MoreTypes.equivalence()
+ .wrap(getMapKey(mapBinding.bindingElement()).get().getAnnotationType());
+ }
+ }));
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/DependencyRequest.java b/compiler/src/main/java/dagger/internal/codegen/DependencyRequest.java
new file mode 100644
index 000000000..5af9a82c5
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/DependencyRequest.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.Lazy;
+import dagger.MembersInjector;
+import dagger.Provides;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import java.util.List;
+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.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+import static com.google.auto.common.MoreTypes.isTypeOf;
+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 javax.lang.model.type.TypeKind.DECLARED;
+
+/**
+ * Represents a request for a key at an injection point. Parameters to {@link Inject} constructors
+ * or {@link Provides} methods are examples of key requests.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+// TODO(gak): Set bindings and the permutations thereof need to be addressed
+@AutoValue
+abstract class DependencyRequest {
+ static Function<DependencyRequest, BindingKey> BINDING_KEY_FUNCTION =
+ new Function<DependencyRequest, BindingKey>() {
+ @Override public BindingKey apply(DependencyRequest request) {
+ return request.bindingKey();
+ }
+ };
+
+ enum Kind {
+ /** A default request for an instance. E.g.: {@code Blah} */
+ INSTANCE,
+ /** A request for a {@link Provider}. E.g.: {@code Provider<Blah>} */
+ PROVIDER,
+ /** A request for a {@link Lazy}. E.g.: {@code Lazy<Blah>} */
+ LAZY,
+ /** A request for a {@link MembersInjector}. E.g.: {@code MembersInjector<Blah>} */
+ MEMBERS_INJECTOR,
+ /** A request for a {@link Producer}. E.g.: {@code Producer<Blah>} */
+ PRODUCER,
+ /** A request for a {@link Produced}. E.g.: {@code Produced<Blah>} */
+ PRODUCED,
+ /**
+ * A request for a {@link ListenableFuture}. E.g.: {@code ListenableFuture<Blah>}.
+ * These can only be requested by component interfaces.
+ */
+ FUTURE,
+ }
+
+ abstract Kind kind();
+ abstract Key key();
+
+ BindingKey bindingKey() {
+ switch (kind()) {
+ case INSTANCE:
+ case LAZY:
+ case PROVIDER:
+ case PRODUCER:
+ case PRODUCED:
+ case FUTURE:
+ return BindingKey.create(BindingKey.Kind.CONTRIBUTION, key());
+ case MEMBERS_INJECTOR:
+ return BindingKey.create(BindingKey.Kind.MEMBERS_INJECTION, key());
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ abstract Element requestElement();
+
+ /**
+ * Returns the possibly resolved type that contained the requesting element. For members injection
+ * requests, this is the type itself.
+ */
+ abstract DeclaredType enclosingType();
+
+ /** Returns true if this request allows null objects. */
+ abstract boolean isNullable();
+
+ /**
+ * Factory for {@link DependencyRequest}s.
+ *
+ * <p>Any factory method may throw {@link TypeNotPresentException} if a type is not available,
+ * which may mean that the type will be generated in a later round of processing.
+ */
+ static final class Factory {
+ private final Key.Factory keyFactory;
+
+ Factory(Key.Factory keyFactory) {
+ this.keyFactory = keyFactory;
+ }
+
+ ImmutableSet<DependencyRequest> forRequiredResolvedVariables(DeclaredType container,
+ List<? extends VariableElement> variables, List<? extends TypeMirror> resolvedTypes) {
+ checkState(resolvedTypes.size() == variables.size());
+ ImmutableSet.Builder<DependencyRequest> builder = ImmutableSet.builder();
+ for (int i = 0; i < variables.size(); i++) {
+ builder.add(forRequiredResolvedVariable(container, variables.get(i), resolvedTypes.get(i)));
+ }
+ return builder.build();
+ }
+
+ ImmutableSet<DependencyRequest> forRequiredVariables(
+ List<? extends VariableElement> variables) {
+ return FluentIterable.from(variables)
+ .transform(new Function<VariableElement, DependencyRequest>() {
+ @Override public DependencyRequest apply(VariableElement input) {
+ return forRequiredVariable(input);
+ }
+ })
+ .toSet();
+ }
+
+ /**
+ * Creates a DependencyRequest for implictMapBinding, this request's key will be
+ * {@code Map<K, Provider<V>>}, this DependencyRequest is depended by the DependencyRequest
+ * whose key is {@code Map<K, V>}
+ */
+ DependencyRequest forImplicitMapBinding(DependencyRequest delegatingRequest, Key delegateKey) {
+ checkNotNull(delegatingRequest);
+ return new AutoValue_DependencyRequest(Kind.PROVIDER, delegateKey,
+ delegatingRequest.requestElement(),
+ delegatingRequest.enclosingType(),
+ false /* doesn't allow null */);
+ }
+
+ DependencyRequest forRequiredVariable(VariableElement variableElement) {
+ checkNotNull(variableElement);
+ TypeMirror type = variableElement.asType();
+ Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(variableElement);
+ return newDependencyRequest(variableElement, type, qualifier,
+ getEnclosingType(variableElement));
+ }
+
+ DependencyRequest forRequiredResolvedVariable(DeclaredType container,
+ VariableElement variableElement,
+ TypeMirror resolvedType) {
+ checkNotNull(variableElement);
+ checkNotNull(resolvedType);
+ Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(variableElement);
+ return newDependencyRequest(variableElement, resolvedType, qualifier, container);
+ }
+
+ DependencyRequest forComponentProvisionMethod(ExecutableElement provisionMethod,
+ ExecutableType provisionMethodType) {
+ checkNotNull(provisionMethod);
+ checkNotNull(provisionMethodType);
+ checkArgument(provisionMethod.getParameters().isEmpty(),
+ "Component provision methods must be empty: " + provisionMethod);
+ Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(provisionMethod);
+ return newDependencyRequest(provisionMethod, provisionMethodType.getReturnType(), qualifier,
+ getEnclosingType(provisionMethod));
+ }
+
+ DependencyRequest forComponentProductionMethod(ExecutableElement productionMethod,
+ ExecutableType 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);
+ DeclaredType container = getEnclosingType(productionMethod);
+ // Only a component production method can be a request for a ListenableFuture, so we
+ // special-case it here.
+ if (isTypeOf(ListenableFuture.class, type)) {
+ return new AutoValue_DependencyRequest(
+ Kind.FUTURE,
+ keyFactory.forQualifiedType(qualifier,
+ Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments())),
+ productionMethod,
+ container,
+ false /* doesn't allow null */);
+ } else {
+ return newDependencyRequest(productionMethod, type, qualifier, container);
+ }
+ }
+
+ DependencyRequest forComponentMembersInjectionMethod(ExecutableElement membersInjectionMethod,
+ ExecutableType membersInjectionMethodType) {
+ checkNotNull(membersInjectionMethod);
+ checkNotNull(membersInjectionMethodType);
+ Optional<AnnotationMirror> qualifier =
+ InjectionAnnotations.getQualifier(membersInjectionMethod);
+ checkArgument(!qualifier.isPresent());
+ TypeMirror returnType = membersInjectionMethodType.getReturnType();
+ if (returnType.getKind().equals(DECLARED)
+ && MoreTypes.isTypeOf(MembersInjector.class, returnType)) {
+ return new AutoValue_DependencyRequest(Kind.MEMBERS_INJECTOR,
+ keyFactory.forMembersInjectedType(
+ Iterables.getOnlyElement(((DeclaredType) returnType).getTypeArguments())),
+ membersInjectionMethod,
+ getEnclosingType(membersInjectionMethod),
+ false /* doesn't allow null */);
+ } else {
+ return new AutoValue_DependencyRequest(Kind.MEMBERS_INJECTOR,
+ keyFactory.forMembersInjectedType(
+ Iterables.getOnlyElement(membersInjectionMethodType.getParameterTypes())),
+ membersInjectionMethod,
+ getEnclosingType(membersInjectionMethod),
+ false /* doesn't allow null */);
+ }
+ }
+
+ DependencyRequest forMembersInjectedType(DeclaredType type) {
+ return new AutoValue_DependencyRequest(Kind.MEMBERS_INJECTOR,
+ keyFactory.forMembersInjectedType(type),
+ type.asElement(),
+ type,
+ false /* doesn't allow null */);
+ }
+
+ private DependencyRequest newDependencyRequest(Element requestElement,
+ TypeMirror type, Optional<AnnotationMirror> qualifier, DeclaredType container) {
+ KindAndType kindAndType = extractKindAndType(type);
+ if (kindAndType.kind().equals(Kind.MEMBERS_INJECTOR)) {
+ checkArgument(!qualifier.isPresent());
+ }
+ // Only instance types can be non-null -- all other requests are wrapped
+ // inside something (e.g, Provider, Lazy, etc..).
+ // TODO(sameb): should Produced/Producer always require non-nullable?
+ boolean allowsNull = !kindAndType.kind().equals(Kind.INSTANCE)
+ || ConfigurationAnnotations.getNullableType(requestElement).isPresent();
+ return new AutoValue_DependencyRequest(kindAndType.kind(),
+ keyFactory.forQualifiedType(qualifier, kindAndType.type()),
+ requestElement,
+ container,
+ allowsNull);
+ }
+
+ @AutoValue
+ static abstract class KindAndType {
+ abstract Kind kind();
+ abstract TypeMirror type();
+ }
+
+ /**
+ * Extracts the correct requesting type & kind out a request type. For example, if a user
+ * requests {@code Provider<Foo>}, this will return ({@link Kind#PROVIDER}, {@code Foo}).
+ *
+ * @throws TypeNotPresentException if {@code type}'s kind is {@link TypeKind#ERROR}, which may
+ * mean that the type will be generated in a later round of processing
+ */
+ static KindAndType extractKindAndType(TypeMirror type) {
+ if (type.getKind().equals(TypeKind.ERROR)) {
+ throw new TypeNotPresentException(type.toString(), null);
+ }
+
+ // We must check TYPEVAR explicitly before the below checks because calling
+ // isTypeOf(..) on a TYPEVAR throws an exception (because it can't be
+ // represented as a Class).
+ if (type.getKind().equals(TypeKind.TYPEVAR)) {
+ return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.INSTANCE, type);
+ } else if (isTypeOf(Provider.class, type)) {
+ return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.PROVIDER,
+ Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
+ } else if (isTypeOf(Lazy.class, type)) {
+ return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.LAZY,
+ Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
+ } else if (isTypeOf(MembersInjector.class, type)) {
+ return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.MEMBERS_INJECTOR,
+ Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
+ } else if (isTypeOf(Producer.class, type)) {
+ return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.PRODUCER,
+ Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
+ } else if (isTypeOf(Produced.class, type)) {
+ return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.PRODUCED,
+ Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
+ } else {
+ return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.INSTANCE, type);
+ }
+ }
+
+ static DeclaredType getEnclosingType(Element element) {
+ while (!MoreElements.isType(element)) {
+ element = element.getEnclosingElement();
+ }
+ return MoreTypes.asDeclared(element.asType());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/DependencyRequestFormatter.java b/compiler/src/main/java/dagger/internal/codegen/DependencyRequestFormatter.java
new file mode 100644
index 000000000..0e5f1f240
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/DependencyRequestFormatter.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Optional;
+import java.util.List;
+import javax.lang.model.element.AnnotationMirror;
+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.element.VariableElement;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleElementVisitor6;
+import javax.lang.model.util.Types;
+
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.ErrorMessages.INDENT;
+
+/**
+ * Formats a {@link DependencyRequest} into a {@link String} suitable for an error message listing
+ * a chain of dependencies.
+ *
+ * @author Christian Gruber
+ * @since 2.0
+ */
+final class DependencyRequestFormatter extends Formatter<DependencyRequest> {
+ private final Types types;
+
+ DependencyRequestFormatter(Types types) {
+ this.types = types;
+ }
+
+ // TODO(cgruber): Sweep this class for TypeMirror.toString() usage and do some preventive format.
+ // TODO(cgruber): consider returning a small structure containing strings to be indented later.
+ @Override public String format(final DependencyRequest request) {
+ Element requestElement = request.requestElement();
+ Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(requestElement);
+ return requestElement.accept(new SimpleElementVisitor6<String, Optional<AnnotationMirror>>(){
+
+ /* Handle component methods */
+ @Override public String visitExecutable(
+ ExecutableElement method, Optional<AnnotationMirror> qualifier) {
+ StringBuilder builder = new StringBuilder(INDENT);
+ if (method.getParameters().isEmpty()) {
+ // some.package.name.MyComponent.myMethod()
+ // [component method with return type: @other.package.Qualifier some.package.name.Foo]
+ appendEnclosingTypeAndMemberName(method, builder).append("()\n")
+ .append(INDENT).append(INDENT).append("[component method with return type: ");
+ if (qualifier.isPresent()) {
+ // TODO(cgruber) use chenying's annotation mirror stringifier
+ builder.append(qualifier.get()).append(' ');
+ }
+ builder.append(method.getReturnType()).append(']');
+ } else {
+ // some.package.name.MyComponent.myMethod(some.package.name.Foo foo)
+ // [component injection method for type: some.package.name.Foo]
+ VariableElement componentMethodParameter = getOnlyElement(method.getParameters());
+ appendEnclosingTypeAndMemberName(method, builder).append("(");
+ appendParameter(componentMethodParameter, componentMethodParameter.asType(), builder);
+ builder.append(")\n");
+ builder.append(INDENT).append(INDENT).append("[component injection method for type: ")
+ .append(componentMethodParameter.asType())
+ .append(']');
+ }
+ return builder.toString();
+ }
+
+ /* Handle injected fields or method/constructor parameter injection. */
+ @Override public String visitVariable(
+ VariableElement variable, Optional<AnnotationMirror> qualifier) {
+ StringBuilder builder = new StringBuilder(INDENT);
+ TypeMirror resolvedVariableType =
+ MoreTypes.asMemberOf(types, request.enclosingType(), variable);
+ if (variable.getKind().equals(ElementKind.PARAMETER)) {
+ // some.package.name.MyClass.myMethod(some.package.name.Foo arg0, some.package.Bar arg1)
+ // [parameter: @other.package.Qualifier some.package.name.Foo arg0]
+ ExecutableElement methodOrConstructor =
+ MoreElements.asExecutable(variable.getEnclosingElement());
+ ExecutableType resolvedMethodOrConstructor = MoreTypes.asExecutable(
+ types.asMemberOf(request.enclosingType(), methodOrConstructor));
+ appendEnclosingTypeAndMemberName(methodOrConstructor, builder).append('(');
+ List<? extends VariableElement> parameters = methodOrConstructor.getParameters();
+ List<? extends TypeMirror> parameterTypes =
+ resolvedMethodOrConstructor.getParameterTypes();
+ checkState(parameters.size() == parameterTypes.size());
+ for (int i = 0; i < parameters.size(); i++) {
+ appendParameter(parameters.get(i), parameterTypes.get(i), builder);
+ if (i != parameters.size() - 1) {
+ builder.append(", ");
+ }
+ }
+ builder.append(")\n").append(INDENT).append(INDENT).append("[parameter: ");
+ } else {
+ // some.package.name.MyClass.myField
+ // [injected field of type: @other.package.Qualifier some.package.name.Foo myField]
+ appendEnclosingTypeAndMemberName(variable, builder).append("\n")
+ .append(INDENT).append(INDENT).append("[injected field of type: ");
+ }
+ if (qualifier.isPresent()) {
+ // TODO(cgruber) use chenying's annotation mirror stringifier
+ builder.append(qualifier.get()).append(' ');
+ }
+ builder.append(resolvedVariableType)
+ .append(' ')
+ .append(variable.getSimpleName())
+ .append(']');
+ return builder.toString();
+ }
+
+ @Override
+ public String visitType(TypeElement e, Optional<AnnotationMirror> p) {
+ return ""; // types by themselves provide no useful information.
+ }
+
+ @Override protected String defaultAction(Element element, Optional<AnnotationMirror> ignore) {
+ throw new IllegalStateException(
+ "Invalid request " + element.getKind() + " element " + element);
+ }
+ }, qualifier);
+ }
+
+ private StringBuilder appendParameter(VariableElement parameter, TypeMirror type,
+ StringBuilder builder) {
+ return builder.append(type).append(' ').append(parameter.getSimpleName());
+ }
+
+ private StringBuilder appendEnclosingTypeAndMemberName(Element member, StringBuilder builder) {
+ TypeElement type = MoreElements.asType(member.getEnclosingElement());
+ return builder.append(type.getQualifiedName())
+ .append('.')
+ .append(member.getSimpleName());
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/DependencyRequestMapper.java b/compiler/src/main/java/dagger/internal/codegen/DependencyRequestMapper.java
new file mode 100644
index 000000000..1dc48fc8b
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/DependencyRequestMapper.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import dagger.MembersInjector;
+import dagger.producers.Producer;
+import javax.inject.Provider;
+
+import static com.google.common.collect.Iterables.getOnlyElement;
+
+/**
+ * A mapper for associating a {@link DependencyRequest} to a framework class, dependent on
+ * the type of code to be generated (e.g., for {@link Provider} or {@link Producer}).
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+abstract class DependencyRequestMapper {
+ abstract Class<?> getFrameworkClass(DependencyRequest request);
+
+ /**
+ * Returns the framework class to use for a collection of requests of the same {@link BindingKey}.
+ * This allows factories to only take a single argument for multiple requests of the same key.
+ */
+ Class<?> getFrameworkClass(Iterable<DependencyRequest> requests) {
+ ImmutableSet<Class<?>> classes = FluentIterable.from(requests)
+ .transform(new Function<DependencyRequest, Class<?>>() {
+ @Override public Class<?> apply(DependencyRequest request) {
+ return getFrameworkClass(request);
+ }
+ })
+ .toSet();
+ if (classes.size() == 1) {
+ return getOnlyElement(classes);
+ } else if (classes.equals(ImmutableSet.of(Producer.class, Provider.class))) {
+ return Provider.class;
+ } else {
+ throw new IllegalStateException("Bad set of framework classes: " + classes);
+ }
+ }
+
+ private static final class MapperForProvider extends DependencyRequestMapper {
+ @Override public Class<?> getFrameworkClass(DependencyRequest request) {
+ switch (request.kind()) {
+ case INSTANCE:
+ case PROVIDER:
+ case LAZY:
+ return Provider.class;
+ case MEMBERS_INJECTOR:
+ return MembersInjector.class;
+ case PRODUCED:
+ case PRODUCER:
+ throw new IllegalArgumentException();
+ default:
+ throw new AssertionError();
+ }
+ }
+ }
+
+ static final DependencyRequestMapper FOR_PROVIDER = new MapperForProvider();
+
+ private static final class MapperForProducer extends DependencyRequestMapper {
+ @Override public Class<?> getFrameworkClass(DependencyRequest request) {
+ switch (request.kind()) {
+ case INSTANCE:
+ case PRODUCED:
+ case PRODUCER:
+ return Producer.class;
+ case PROVIDER:
+ case LAZY:
+ return Provider.class;
+ case MEMBERS_INJECTOR:
+ return MembersInjector.class;
+ default:
+ throw new AssertionError();
+ }
+ }
+ }
+
+ static final DependencyRequestMapper FOR_PRODUCER = new MapperForProducer();
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/DependencyVariableNamer.java b/compiler/src/main/java/dagger/internal/codegen/DependencyVariableNamer.java
new file mode 100644
index 000000000..1643adbc4
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/DependencyVariableNamer.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.base.Ascii;
+import com.google.common.base.Function;
+import dagger.Lazy;
+import javax.inject.Provider;
+
+/**
+ * Picks a reasonable name for what we think is being provided from the variable name associated
+ * with the {@link DependencyRequest}. I.e. strips out words like "lazy" and "provider" if we
+ * believe that those refer to {@link Lazy} and {@link Provider} rather than the type being
+ * provided.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+//TODO(gak): develop the heuristics to get better names
+final class DependencyVariableNamer implements Function<DependencyRequest, String> {
+ @Override
+ public String apply(DependencyRequest dependency) {
+ String variableName = dependency.requestElement().getSimpleName().toString();
+ switch (dependency.kind()) {
+ case INSTANCE:
+ return variableName;
+ case LAZY:
+ return variableName.startsWith("lazy") && !variableName.equals("lazy")
+ ? Ascii.toLowerCase(variableName.charAt(4)) + variableName.substring(5)
+ : variableName;
+ case PROVIDER:
+ return variableName.endsWith("Provider") && !variableName.equals("Provider")
+ ? variableName.substring(0, variableName.length() - 8)
+ : variableName;
+ case MEMBERS_INJECTOR:
+ return variableName.endsWith("MembersInjector") && !variableName.equals("MembersInjector")
+ ? variableName.substring(0, variableName.length() - 15)
+ : variableName;
+ case PRODUCED:
+ return variableName.startsWith("produced") && !variableName.equals("produced")
+ ? Ascii.toLowerCase(variableName.charAt(8)) + variableName.substring(9)
+ : variableName;
+ case PRODUCER:
+ return variableName.endsWith("Producer") && !variableName.equals("Producer")
+ ? variableName.substring(0, variableName.length() - 8)
+ : variableName;
+ default:
+ throw new AssertionError();
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ErrorMessages.java b/compiler/src/main/java/dagger/internal/codegen/ErrorMessages.java
new file mode 100644
index 000000000..c025eb48a
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ErrorMessages.java
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 dagger.Provides;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.lang.model.element.AnnotationMirror;
+
+/**
+ * The collection of error messages to be reported back to users.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class ErrorMessages {
+ /*
+ * Common constants.
+ */
+ static final String INDENT = " ";
+ static final int DUPLICATE_SIZE_LIMIT = 10;
+
+ /*
+ * JSR-330 errors
+ *
+ * These are errors that are explicitly outlined in the JSR-330 APIs
+ */
+
+ /* constructors */
+ static final String MULTIPLE_INJECT_CONSTRUCTORS =
+ "Types may only contain one @Inject constructor.";
+
+ /* fields */
+ static final String FINAL_INJECT_FIELD = "@Inject fields may not be final";
+
+ /* methods */
+ static final String ABSTRACT_INJECT_METHOD = "Methods with @Inject may not be abstract.";
+ static final String GENERIC_INJECT_METHOD =
+ "Methods with @Inject may not declare type parameters.";
+
+ /* qualifiers */
+ static final String MULTIPLE_QUALIFIERS =
+ "A single injection site may not use more than one @Qualifier.";
+
+ /* scope */
+ static final String MULTIPLE_SCOPES = "A single binding may not declare more than one @Scope.";
+
+ /*
+ * Dagger errors
+ *
+ * These are errors that arise due to restrictions imposed by the dagger implementation.
+ */
+
+ /* constructors */
+ static final String INJECT_ON_PRIVATE_CONSTRUCTOR =
+ "Dagger does not support injection into private constructors";
+ static final String INJECT_CONSTRUCTOR_ON_INNER_CLASS =
+ "@Inject constructors are invalid on inner classes";
+ static final String INJECT_CONSTRUCTOR_ON_ABSTRACT_CLASS =
+ "@Inject is nonsense on the constructor of an abstract class";
+ static final String QUALIFIER_ON_INJECT_CONSTRUCTOR =
+ "@Qualifier annotations are not allowed on @Inject constructors.";
+
+ /* fields */
+ static final String PRIVATE_INJECT_FIELD =
+ "Dagger does not support injection into private fields";
+
+ static final String STATIC_INJECT_FIELD =
+ "Dagger does not support injection into static fields";
+
+ /* methods */
+ static final String PRIVATE_INJECT_METHOD =
+ "Dagger does not support injection into private methods";
+
+ static final String STATIC_INJECT_METHOD =
+ "Dagger does not support injection into static methods";
+
+ /* all */
+ static final String INJECT_INTO_PRIVATE_CLASS =
+ "Dagger does not support injection into private classes";
+
+ /*
+ * Configuration errors
+ *
+ * These are errors that relate specifically to the Dagger configuration API (@Module, @Provides,
+ * etc.)
+ */
+ static final String DUPLICATE_BINDINGS_FOR_KEY_FORMAT =
+ "%s is bound multiple times:";
+
+ static String duplicateMapKeysError(String key) {
+ return "The same map key is bound more than once for " + key;
+ }
+
+ static String inconsistentMapKeyAnnotationsError(String key) {
+ return key + " uses more than one @MapKey annotation type";
+ }
+
+ static final String PROVIDES_METHOD_RETURN_TYPE =
+ "@Provides methods must either return a primitive, an array or a declared type.";
+
+ static final String PRODUCES_METHOD_RETURN_TYPE =
+ "@Produces methods must either return a primitive, an array or a declared type, or a"
+ + " ListenableFuture of one of those types.";
+
+ static final String PRODUCES_METHOD_RAW_FUTURE =
+ "@Produces methods cannot return a raw ListenableFuture.";
+
+ static final String BINDING_METHOD_SET_VALUES_RAW_SET =
+ "@%s methods of type set values cannot return a raw Set";
+
+ static final String PROVIDES_METHOD_SET_VALUES_RETURN_SET =
+ "@Provides methods of type set values must return a Set";
+
+ static final String PRODUCES_METHOD_SET_VALUES_RETURN_SET =
+ "@Produces methods of type set values must return a Set or ListenableFuture of Set";
+
+ static final String BINDING_METHOD_MUST_RETURN_A_VALUE =
+ "@%s methods must return a value (not void).";
+
+ static final String BINDING_METHOD_ABSTRACT = "@%s methods cannot be abstract";
+
+ static final String BINDING_METHOD_PRIVATE = "@%s methods cannot be private";
+
+ static final String BINDING_METHOD_TYPE_PARAMETER =
+ "@%s methods may not have type parameters.";
+
+ static final String BINDING_METHOD_NOT_IN_MODULE =
+ "@%s methods can only be present within a @%s";
+
+ static final String BINDING_METHOD_NOT_MAP_HAS_MAP_KEY =
+ "@%s methods of non map type cannot declare a map key";
+
+ static final String BINDING_METHOD_WITH_NO_MAP_KEY =
+ "@%s methods of type map must declare a map key";
+
+ static final String BINDING_METHOD_WITH_MULTIPLE_MAP_KEY =
+ "@%s methods may not have more than one @MapKey-marked annotation";
+
+ static final String BINDING_METHOD_WITH_SAME_NAME =
+ "Cannot have more than one @%s method with the same name in a single module";
+
+ static final String MODULES_WITH_TYPE_PARAMS_MUST_BE_ABSTRACT =
+ "Modules with type parameters must be abstract";
+
+ static final String REFERENCED_MODULES_MUST_NOT_BE_ABSTRACT =
+ "%s is listed as a module, but is an abstract class or interface";
+
+ static final String REFERENCED_MODULE_NOT_ANNOTATED =
+ "%s is listed as a module, but is not annotated with %s";
+
+ static final String REFERENCED_MODULE_MUST_NOT_HAVE_TYPE_PARAMS =
+ "%s is listed as a module, but has type parameters";
+
+ static final String PROVIDES_METHOD_OVERRIDES_ANOTHER =
+ "@%s methods may not override another method. Overrides: %s";
+
+ static final String METHOD_OVERRIDES_PROVIDES_METHOD =
+ "@%s methods may not be overridden in modules. Overrides: %s";
+
+ static final String PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS =
+ "Cannot use more than one @Qualifier on a @Provides or @Produces method";
+
+ /* mapKey errors*/
+ static final String MAPKEY_WITHOUT_MEMBERS =
+ "Map key annotations must have members";
+
+ static final String UNWRAPPED_MAP_KEY_WITH_TOO_MANY_MEMBERS=
+ "Map key annotations with unwrapped values must have exactly one member";
+
+ static final String UNWRAPPED_MAP_KEY_WITH_ARRAY_MEMBER =
+ "Map key annotations with unwrapped values cannot use arrays";
+
+ /* collection binding errors */
+ static final String MULTIPLE_BINDING_TYPES_FORMAT =
+ "More than one binding present of different types %s";
+
+ static final String MULTIPLE_BINDING_TYPES_FOR_KEY_FORMAT =
+ "%s has incompatible bindings:\n";
+
+ static final String PROVIDER_ENTRY_POINT_MAY_NOT_DEPEND_ON_PRODUCER_FORMAT =
+ "%s is a provision entry-point, which cannot depend on a production.";
+
+ static final String PROVIDER_MAY_NOT_DEPEND_ON_PRODUCER_FORMAT =
+ "%s is a provision, which cannot depend on a production.";
+
+ static final String REQUIRES_AT_INJECT_CONSTRUCTOR_OR_PROVIDER_FORMAT =
+ "%s cannot be provided without an @Inject constructor or from an @Provides-annotated method.";
+
+ static final String REQUIRES_PROVIDER_FORMAT =
+ "%s cannot be provided without an @Provides-annotated method.";
+
+ static final String REQUIRES_AT_INJECT_CONSTRUCTOR_OR_PROVIDER_OR_PRODUCER_FORMAT =
+ "%s cannot be provided without an @Inject constructor or from an @Provides- or "
+ + "@Produces-annotated method.";
+
+ static final String REQUIRES_PROVIDER_OR_PRODUCER_FORMAT =
+ "%s cannot be provided without an @Provides- or @Produces-annotated method.";
+
+ static final String MEMBERS_INJECTION_DOES_NOT_IMPLY_PROVISION =
+ "This type supports members injection but cannot be implicitly provided.";
+
+ static final String MEMBERS_INJECTION_WITH_RAW_TYPE =
+ "%s has type parameters, cannot members inject the raw type. via:\n%s";
+
+ static final String MEMBERS_INJECTION_WITH_UNBOUNDED_TYPE =
+ "Type parameters must be bounded for members injection. %s required by %s, via:\n%s";
+
+ static final String CONTAINS_DEPENDENCY_CYCLE_FORMAT = "%s.%s() contains a dependency cycle:\n%s";
+
+ static final String MALFORMED_MODULE_METHOD_FORMAT =
+ "Cannot generated a graph because method %s on module %s was malformed";
+
+ static final String NULLABLE_TO_NON_NULLABLE =
+ "%s is not nullable, but is being provided by %s";
+
+ static final String CANNOT_RETURN_NULL_FROM_NON_NULLABLE_COMPONENT_METHOD =
+ "Cannot return null from a non-@Nullable component method";
+
+ static final String CANNOT_RETURN_NULL_FROM_NON_NULLABLE_PROVIDES_METHOD =
+ "Cannot return null from a non-@Nullable @Provides method";
+
+ static ComponentBuilderMessages builderMsgsFor(ComponentDescriptor.Kind kind) {
+ switch(kind) {
+ case COMPONENT:
+ return ComponentBuilderMessages.INSTANCE;
+ case SUBCOMPONENT:
+ return SubcomponentBuilderMessages.INSTANCE;
+ default:
+ throw new IllegalStateException(kind.toString());
+ }
+ }
+
+ static class ComponentBuilderMessages {
+ static final ComponentBuilderMessages INSTANCE = new ComponentBuilderMessages();
+
+ protected String process(String s) { return s; }
+
+ /** Errors for component builders. */
+ final String moreThanOne() {
+ return process("@Component has more than one @Component.Builder: %s");
+ }
+
+ final String cxtorOnlyOneAndNoArgs() {
+ return process("@Component.Builder classes must have exactly one constructor,"
+ + " and it must not have any parameters");
+ }
+
+ final String generics() {
+ return process("@Component.Builder types must not have any generic types");
+ }
+
+ final String mustBeInComponent() {
+ return process("@Component.Builder types must be nested within a @Component");
+ }
+
+ final String mustBeClassOrInterface() {
+ return process("@Component.Builder types must be abstract classes or interfaces");
+ }
+
+ final String isPrivate() {
+ return process("@Component.Builder types must not be private");
+ }
+
+ final String mustBeStatic() {
+ return process("@Component.Builder types must be static");
+ }
+
+ final String mustBeAbstract() {
+ return process("@Component.Builder types must be abstract");
+ }
+
+ final String missingBuildMethod() {
+ return process("@Component.Builder types must have exactly one no-args method that "
+ + " returns the @Component type");
+ }
+
+ final String manyMethodsForType() {
+ return process("@Component.Builder types must not have more than one setter method per type,"
+ + " but %s is set by %s");
+ }
+
+ final String extraSetters() {
+ return process(
+ "@Component.Builder has setters for modules or components that aren't required: %s");
+ }
+
+ final String missingSetters() {
+ return process(
+ "@Component.Builder is missing setters for required modules or components: %s");
+ }
+
+ final String twoBuildMethods() {
+ return process("@Component.Builder types must have exactly one zero-arg method, and that"
+ + " method must return the @Component type. Already found: %s");
+ }
+
+ final String inheritedTwoBuildMethods() {
+ return process("@Component.Builder types must have exactly one zero-arg method, and that"
+ + " method must return the @Component type. Found %s and %s");
+ }
+
+ final String buildMustReturnComponentType() {
+ return process(
+ "@Component.Builder methods that have no arguments must return the @Component type");
+ }
+
+ final String inheritedBuildMustReturnComponentType() {
+ return process(
+ "@Component.Builder methods that have no arguments must return the @Component type"
+ + " Inherited method: %s");
+ }
+
+ final String methodsMustTakeOneArg() {
+ return process("@Component.Builder methods must not have more than one argument");
+ }
+
+ final String inheritedMethodsMustTakeOneArg() {
+ return process(
+ "@Component.Builder methods must not have more than one argument. Inherited method: %s");
+ }
+
+ final String methodsMustReturnVoidOrBuilder() {
+ return process("@Component.Builder setter methods must return void, the builder,"
+ + " or a supertype of the builder");
+ }
+
+ final String inheritedMethodsMustReturnVoidOrBuilder() {
+ return process("@Component.Builder setter methods must return void, the builder,"
+ + "or a supertype of the builder. Inherited method: %s");
+ }
+
+ final String methodsMayNotHaveTypeParameters() {
+ return process("@Component.Builder methods must not have type parameters");
+ }
+
+ final String inheritedMethodsMayNotHaveTypeParameters() {
+ return process(
+ "@Component.Builder methods must not have type parameters. Inherited method: %s");
+ }
+ }
+
+ static final class SubcomponentBuilderMessages extends ComponentBuilderMessages {
+ @SuppressWarnings("hiding")
+ static final SubcomponentBuilderMessages INSTANCE = new SubcomponentBuilderMessages();
+
+ @Override protected String process(String s) {
+ return s.replaceAll("component", "subcomponent").replaceAll("Component", "Subcomponent");
+ }
+
+ String builderMethodRequiresNoArgs() {
+ return "Methods returning a @Subcomponent.Builder must have no arguments";
+ }
+
+ String moreThanOneRefToSubcomponent() {
+ return "Only one method can create a given subcomponent. %s is created by: %s";
+ }
+ }
+
+ /**
+ * A regular expression to match a small list of specific packages deemed to
+ * be unhelpful to display in fully qualified types in error messages.
+ *
+ * Note: This should never be applied to messages themselves.
+ */
+ private static final Pattern COMMON_PACKAGE_PATTERN = Pattern.compile(
+ "(?:^|[^.a-z_])" // What we want to match on but not capture.
+ + "((?:" // Start a group with a non-capturing or part
+ + "java[.]lang"
+ + "|java[.]util"
+ + "|javax[.]inject"
+ + "|dagger"
+ + "|com[.]google[.]common[.]base"
+ + "|com[.]google[.]common[.]collect"
+ + ")[.])" // Always end with a literal .
+ + "[A-Z]"); // What we want to match on but not capture.
+
+ /**
+ * A method to strip out common packages and a few rare type prefixes
+ * from types' string representation before being used in error messages.
+ *
+ * This type assumes a String value that is a valid fully qualified
+ * (and possibly parameterized) type, and should NOT be used with
+ * arbitrary text, especially prose error messages.
+ *
+ * TODO(cgruber): Tighten these to take type representations (mirrors
+ * and elements) to avoid accidental mis-use by running errors
+ * through this method.
+ */
+ static String stripCommonTypePrefixes(String type) {
+ // Special case this enum's constants since they will be incredibly common.
+ type = type.replace(Provides.Type.class.getCanonicalName() + ".", "");
+
+ // Do regex magic to remove common packages we care to shorten.
+ Matcher matcher = COMMON_PACKAGE_PATTERN.matcher(type);
+ StringBuilder result = new StringBuilder();
+ int index = 0;
+ while (matcher.find()) {
+ result.append(type.subSequence(index, matcher.start(1)));
+ index = matcher.end(1); // Skip the matched pattern content.
+ }
+ result.append(type.subSequence(index, type.length()));
+ return result.toString();
+ }
+
+ //TODO(cgruber): Extract Formatter and do something less stringy.
+ static String format(AnnotationMirror annotation) {
+ return stripCommonTypePrefixes(annotation.toString());
+ }
+
+ private ErrorMessages() {}
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/FactoryGenerator.java b/compiler/src/main/java/dagger/internal/codegen/FactoryGenerator.java
new file mode 100644
index 000000000..c7eb6326f
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/FactoryGenerator.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreTypes;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import dagger.MembersInjector;
+import dagger.Provides.Type;
+import dagger.internal.Factory;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ClassWriter;
+import dagger.internal.codegen.writer.ConstructorWriter;
+import dagger.internal.codegen.writer.EnumWriter;
+import dagger.internal.codegen.writer.FieldWriter;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.MethodWriter;
+import dagger.internal.codegen.writer.ParameterizedTypeName;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.StringLiteral;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import dagger.internal.codegen.writer.TypeVariableName;
+import dagger.internal.codegen.writer.TypeWriter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Generated;
+import javax.annotation.processing.Filer;
+import javax.inject.Inject;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic;
+
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.Provides.Type.SET;
+import static dagger.internal.codegen.ErrorMessages.CANNOT_RETURN_NULL_FROM_NON_NULLABLE_PROVIDES_METHOD;
+import static dagger.internal.codegen.ProvisionBinding.Kind.PROVISION;
+import static dagger.internal.codegen.SourceFiles.factoryNameForProvisionBinding;
+import static dagger.internal.codegen.SourceFiles.frameworkTypeUsageStatement;
+import static dagger.internal.codegen.SourceFiles.parameterizedFactoryNameForProvisionBinding;
+import static dagger.internal.codegen.writer.Snippet.makeParametersSnippet;
+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;
+
+/**
+ * Generates {@link Factory} implementations from {@link ProvisionBinding} instances for
+ * {@link Inject} constructors.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding> {
+ private final DependencyRequestMapper dependencyRequestMapper;
+ private final Diagnostic.Kind nullableValidationType;
+
+ FactoryGenerator(Filer filer, DependencyRequestMapper dependencyRequestMapper,
+ Diagnostic.Kind nullableValidationType) {
+ super(filer);
+ this.dependencyRequestMapper = dependencyRequestMapper;
+ this.nullableValidationType = nullableValidationType;
+ }
+
+ @Override
+ ClassName nameGeneratedType(ProvisionBinding binding) {
+ return factoryNameForProvisionBinding(binding);
+ }
+
+ @Override
+ Iterable<? extends Element> getOriginatingElements(ProvisionBinding binding) {
+ return ImmutableSet.of(binding.bindingElement());
+ }
+
+ @Override
+ Optional<? extends Element> getElementForErrorReporting(ProvisionBinding binding) {
+ return Optional.of(binding.bindingElement());
+ }
+
+ @Override
+ ImmutableSet<JavaWriter> write(ClassName generatedTypeName, ProvisionBinding binding) {
+ // We don't want to write out resolved bindings -- we want to write out the generic version.
+ checkState(!binding.hasNonDefaultTypeParameters());
+
+ TypeMirror keyType = binding.provisionType().equals(Type.MAP)
+ ? Util.getProvidedValueTypeOfMap(MoreTypes.asDeclared(binding.key().type()))
+ : binding.key().type();
+ TypeName providedTypeName = TypeNames.forTypeMirror(keyType);
+ JavaWriter writer = JavaWriter.inPackage(generatedTypeName.packageName());
+
+ final TypeWriter factoryWriter;
+ final Optional<ConstructorWriter> constructorWriter;
+ List<TypeVariableName> typeParameters = Lists.newArrayList();
+ for (TypeParameterElement typeParameter : binding.bindingTypeElement().getTypeParameters()) {
+ typeParameters.add(TypeVariableName.fromTypeParameterElement(typeParameter));
+ }
+ switch (binding.factoryCreationStrategy()) {
+ case ENUM_INSTANCE:
+ EnumWriter enumWriter = writer.addEnum(generatedTypeName.simpleName());
+ enumWriter.addConstant("INSTANCE");
+ constructorWriter = Optional.absent();
+ factoryWriter = enumWriter;
+ // If we have type parameters, then remove the parameters from our providedTypeName,
+ // since we'll be implementing an erased version of it.
+ if (!typeParameters.isEmpty()) {
+ factoryWriter.annotate(SuppressWarnings.class).setValue("rawtypes");
+ providedTypeName = ((ParameterizedTypeName) providedTypeName).type();
+ }
+ break;
+ case CLASS_CONSTRUCTOR:
+ ClassWriter classWriter = writer.addClass(generatedTypeName.simpleName());
+ classWriter.addTypeParameters(typeParameters);
+ classWriter.addModifiers(FINAL);
+ constructorWriter = Optional.of(classWriter.addConstructor());
+ constructorWriter.get().addModifiers(PUBLIC);
+ factoryWriter = classWriter;
+ if (binding.bindingKind().equals(PROVISION)
+ && !binding.bindingElement().getModifiers().contains(STATIC)) {
+ TypeName enclosingType = TypeNames.forTypeMirror(binding.bindingTypeElement().asType());
+ factoryWriter.addField(enclosingType, "module").addModifiers(PRIVATE, FINAL);
+ constructorWriter.get().addParameter(enclosingType, "module");
+ constructorWriter.get().body()
+ .addSnippet("assert module != null;")
+ .addSnippet("this.module = module;");
+ }
+ break;
+ default:
+ throw new AssertionError();
+ }
+
+ factoryWriter.annotate(Generated.class).setValue(ComponentProcessor.class.getName());
+ factoryWriter.addModifiers(PUBLIC);
+ factoryWriter.addImplementedType(
+ ParameterizedTypeName.create(ClassName.fromClass(Factory.class), providedTypeName));
+
+ MethodWriter getMethodWriter = factoryWriter.addMethod(providedTypeName, "get");
+ getMethodWriter.annotate(Override.class);
+ getMethodWriter.addModifiers(PUBLIC);
+
+ if (binding.memberInjectionRequest().isPresent()) {
+ ParameterizedTypeName membersInjectorType = ParameterizedTypeName.create(
+ MembersInjector.class, providedTypeName);
+ factoryWriter.addField(membersInjectorType, "membersInjector").addModifiers(PRIVATE, FINAL);
+ constructorWriter.get().addParameter(membersInjectorType, "membersInjector");
+ constructorWriter.get().body()
+ .addSnippet("assert membersInjector != null;")
+ .addSnippet("this.membersInjector = membersInjector;");
+ }
+
+ ImmutableMap<BindingKey, FrameworkField> fields =
+ SourceFiles.generateBindingFieldsForDependencies(
+ dependencyRequestMapper, binding.dependencies());
+
+ for (FrameworkField bindingField : fields.values()) {
+ TypeName fieldType = bindingField.frameworkType();
+ FieldWriter field = factoryWriter.addField(fieldType, bindingField.name());
+ field.addModifiers(PRIVATE, FINAL);
+ constructorWriter.get().addParameter(field.type(), field.name());
+ constructorWriter.get().body()
+ .addSnippet("assert %s != null;", field.name())
+ .addSnippet("this.%1$s = %1$s;", field.name());
+ }
+
+ // If constructing a factory for @Inject or @Provides bindings, we use a static create method
+ // so that generated components can avoid having to refer to the generic types
+ // of the factory. (Otherwise they may have visibility problems referring to the types.)
+ switch(binding.bindingKind()) {
+ case INJECTION:
+ case PROVISION:
+ // The return type is usually the same as the implementing type, except in the case
+ // of enums with type variables (where we cast).
+ TypeName returnType = ParameterizedTypeName.create(ClassName.fromClass(Factory.class),
+ TypeNames.forTypeMirror(keyType));
+ MethodWriter createMethodWriter = factoryWriter.addMethod(returnType, "create");
+ createMethodWriter.addTypeParameters(typeParameters);
+ createMethodWriter.addModifiers(Modifier.PUBLIC, Modifier.STATIC);
+ Map<String, TypeName> params = constructorWriter.isPresent()
+ ? constructorWriter.get().parameters() : ImmutableMap.<String, TypeName>of();
+ for (Map.Entry<String, TypeName> param : params.entrySet()) {
+ createMethodWriter.addParameter(param.getValue(), param.getKey());
+ }
+ switch (binding.factoryCreationStrategy()) {
+ case ENUM_INSTANCE:
+ if (typeParameters.isEmpty()) {
+ createMethodWriter.body().addSnippet("return INSTANCE;");
+ } else {
+ // We use an unsafe cast here because the types are different.
+ // It's safe because the type is never referenced anywhere.
+ createMethodWriter.annotate(SuppressWarnings.class).setValue("unchecked");
+ createMethodWriter.body().addSnippet("return (Factory) INSTANCE;");
+ }
+ break;
+ case CLASS_CONSTRUCTOR:
+ createMethodWriter.body().addSnippet("return new %s(%s);",
+ parameterizedFactoryNameForProvisionBinding(binding),
+ Joiner.on(", ").join(params.keySet()));
+ break;
+ default:
+ throw new AssertionError();
+ }
+ break;
+ default: // do nothing.
+ }
+
+ List<Snippet> parameters = Lists.newArrayList();
+ for (DependencyRequest dependency : binding.dependencies()) {
+ parameters.add(frameworkTypeUsageStatement(
+ Snippet.format(fields.get(dependency.bindingKey()).name()), dependency.kind()));
+ }
+ Snippet parametersSnippet = makeParametersSnippet(parameters);
+
+ if (binding.bindingKind().equals(PROVISION)) {
+ Snippet providesMethodInvocation = Snippet.format("%s.%s(%s)",
+ binding.bindingElement().getModifiers().contains(STATIC)
+ ? ClassName.fromTypeElement(binding.bindingTypeElement())
+ : "module",
+ binding.bindingElement().getSimpleName(),
+ parametersSnippet);
+
+ if (binding.provisionType().equals(SET)) {
+ TypeName paramTypeName = TypeNames.forTypeMirror(
+ MoreTypes.asDeclared(keyType).getTypeArguments().get(0));
+ // TODO(cgruber): only be explicit with the parameter if paramType contains wildcards.
+ getMethodWriter.body().addSnippet("return %s.<%s>singleton(%s);",
+ ClassName.fromClass(Collections.class), paramTypeName, providesMethodInvocation);
+ } else if (binding.nullableType().isPresent()
+ || nullableValidationType.equals(Diagnostic.Kind.WARNING)) {
+ if (binding.nullableType().isPresent()) {
+ getMethodWriter.annotate(
+ (ClassName) TypeNames.forTypeMirror(binding.nullableType().get()));
+ }
+ getMethodWriter.body().addSnippet("return %s;", providesMethodInvocation);
+ } else {
+ StringLiteral failMsg =
+ StringLiteral.forValue(CANNOT_RETURN_NULL_FROM_NON_NULLABLE_PROVIDES_METHOD);
+ getMethodWriter.body().addSnippet(Snippet.format(Joiner.on('\n').join(
+ "%s provided = %s;",
+ "if (provided == null) {",
+ " throw new NullPointerException(%s);",
+ "}",
+ "return provided;"),
+ getMethodWriter.returnType(),
+ providesMethodInvocation,
+ failMsg));
+ }
+ } else if (binding.memberInjectionRequest().isPresent()) {
+ getMethodWriter.body().addSnippet("%1$s instance = new %1$s(%2$s);",
+ providedTypeName, parametersSnippet);
+ getMethodWriter.body().addSnippet("membersInjector.injectMembers(instance);");
+ getMethodWriter.body().addSnippet("return instance;");
+ } else {
+ getMethodWriter.body()
+ .addSnippet("return new %s(%s);", providedTypeName, parametersSnippet);
+ }
+
+ // TODO(gak): write a sensible toString
+ return ImmutableSet.of(writer);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/Formatter.java b/compiler/src/main/java/dagger/internal/codegen/Formatter.java
new file mode 100644
index 000000000..880b78705
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/Formatter.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.base.Function;
+
+/**
+ * A formatter which transforms an instance of a particular type into a string
+ * representation.
+ *
+ * @param <T> the type of the object to be transformed.
+ * @author Christian Gruber
+ * @since 2.0
+ */
+abstract class Formatter<T> implements Function<T, String> {
+
+ /**
+ * Performs the transformation of an object into a string representation.
+ */
+ public abstract String format(T object);
+
+ /**
+ * Performs the transformation of an object into a string representation in
+ * conformity with the {@link Function}{@code <T, String>} contract, delegating
+ * to {@link #format(Object)}.
+ *
+ * @deprecated Call {@link #format(T)} instead. This method exists to make
+ * formatters easy to use when functions are required, but shouldn't be called directly.
+ */
+ @SuppressWarnings("javadoc")
+ @Deprecated
+ @Override final public String apply(T object) {
+ return format(object);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/FrameworkField.java b/compiler/src/main/java/dagger/internal/codegen/FrameworkField.java
new file mode 100644
index 000000000..b92cef796
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/FrameworkField.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.CaseFormat;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import dagger.MembersInjector;
+import dagger.internal.codegen.ContributionBinding.BindingType;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ParameterizedTypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import dagger.producers.Producer;
+import javax.inject.Provider;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementKindVisitor6;
+
+/**
+ * A value object that represents a field used by Dagger-generated code.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+@AutoValue
+abstract class FrameworkField {
+ // TODO(gak): reexamine the this class and how consistently we're using it and its creation
+ // methods
+ static FrameworkField createWithTypeFromKey(
+ Class<?> frameworkClass, BindingKey bindingKey, String name) {
+ String suffix = frameworkClass.getSimpleName();
+ ParameterizedTypeName frameworkType = ParameterizedTypeName.create(
+ ClassName.fromClass(frameworkClass),
+ TypeNames.forTypeMirror(bindingKey.key().type()));
+ return new AutoValue_FrameworkField(frameworkClass, frameworkType, bindingKey,
+ name.endsWith(suffix) ? name : name + suffix);
+ }
+
+ private static FrameworkField createForMapBindingContribution(
+ Class<?> frameworkClass, BindingKey bindingKey, String name) {
+ TypeMirror mapValueType =
+ MoreTypes.asDeclared(bindingKey.key().type()).getTypeArguments().get(1);
+ return new AutoValue_FrameworkField(frameworkClass,
+ (ParameterizedTypeName) TypeNames.forTypeMirror(mapValueType),
+ bindingKey,
+ name);
+ }
+
+ static FrameworkField createForSyntheticContributionBinding(
+ BindingKey bindingKey, int contributionNumber, ContributionBinding contributionBinding) {
+ switch (contributionBinding.bindingType()) {
+ case MAP:
+ return createForMapBindingContribution(
+ contributionBinding.frameworkClass(),
+ BindingKey.create(bindingKey.kind(), contributionBinding.key()),
+ KeyVariableNamer.INSTANCE.apply(bindingKey.key())
+ + "Contribution" + contributionNumber);
+ case SET:
+ return createWithTypeFromKey(
+ contributionBinding.frameworkClass(),
+ bindingKey,
+ KeyVariableNamer.INSTANCE.apply(bindingKey.key())
+ + "Contribution" + contributionNumber);
+ case UNIQUE:
+ return createWithTypeFromKey(
+ contributionBinding.frameworkClass(),
+ bindingKey,
+ KeyVariableNamer.INSTANCE.apply(bindingKey.key())
+ + "Contribution" + contributionNumber);
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ static FrameworkField createForResolvedBindings(ResolvedBindings resolvedBindings) {
+ BindingKey bindingKey = resolvedBindings.bindingKey();
+ switch (bindingKey.kind()) {
+ case CONTRIBUTION:
+ ImmutableSet<? extends ContributionBinding> contributionBindings =
+ resolvedBindings.contributionBindings();
+ BindingType bindingsType = ProvisionBinding.bindingTypeFor(contributionBindings);
+ switch (bindingsType) {
+ case SET:
+ case MAP:
+ return createWithTypeFromKey(
+ FrameworkField.frameworkClassForResolvedBindings(resolvedBindings),
+ bindingKey,
+ KeyVariableNamer.INSTANCE.apply(bindingKey.key()));
+ case UNIQUE:
+ ContributionBinding binding = Iterables.getOnlyElement(contributionBindings);
+ return createWithTypeFromKey(
+ FrameworkField.frameworkClassForResolvedBindings(resolvedBindings),
+ bindingKey,
+ BINDING_ELEMENT_NAME.visit(binding.bindingElement()));
+ default:
+ throw new AssertionError();
+ }
+ case MEMBERS_INJECTION:
+ return createWithTypeFromKey(
+ MembersInjector.class,
+ bindingKey,
+ CaseFormat.UPPER_CAMEL.to(
+ CaseFormat.LOWER_CAMEL,
+ Iterables.getOnlyElement(resolvedBindings.bindings())
+ .bindingElement()
+ .getSimpleName()
+ .toString()));
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private static final ElementVisitor<String, Void> BINDING_ELEMENT_NAME =
+ new ElementKindVisitor6<String, Void>() {
+ @Override
+ public String visitExecutableAsConstructor(ExecutableElement e, Void p) {
+ return visit(e.getEnclosingElement());
+ }
+
+ @Override
+ public String visitExecutableAsMethod(ExecutableElement e, Void p) {
+ return e.getSimpleName().toString();
+ }
+
+ @Override
+ public String visitType(TypeElement e, Void p) {
+ return CaseFormat.UPPER_CAMEL.to(
+ CaseFormat.LOWER_CAMEL, e.getSimpleName().toString());
+ }
+ };
+
+ static Class<?> frameworkClassForResolvedBindings(ResolvedBindings resolvedBindings) {
+ switch (resolvedBindings.bindingKey().kind()) {
+ case CONTRIBUTION:
+ for (ContributionBinding binding : resolvedBindings.contributionBindings()) {
+ if (binding instanceof ProductionBinding) {
+ return Producer.class;
+ }
+ }
+ return Provider.class;
+ case MEMBERS_INJECTION:
+ return MembersInjector.class;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ abstract Class<?> frameworkClass();
+ abstract ParameterizedTypeName frameworkType();
+ abstract BindingKey bindingKey();
+ abstract String name();
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/InjectBindingRegistry.java b/compiler/src/main/java/dagger/internal/codegen/InjectBindingRegistry.java
new file mode 100644
index 000000000..b8e302e9a
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/InjectBindingRegistry.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import dagger.Component;
+import dagger.Provides;
+import dagger.internal.codegen.writer.ClassName;
+import java.util.ArrayDeque;
+import java.util.Deque;
+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.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic.Kind;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+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.SourceFiles.membersInjectorNameForType;
+
+/**
+ * Maintains the collection of provision bindings from {@link Inject} constructors and members
+ * injection bindings from {@link Inject} fields and methods known to the annotation processor.
+ * Note that this registry <b>does not</b> handle any explicit bindings (those from {@link Provides}
+ * methods, {@link Component} dependencies, etc.).
+ *
+ * @author Gregory Kick
+ */
+final class InjectBindingRegistry {
+ private final Elements elements;
+ private final Types types;
+ private final Messager messager;
+ private final ProvisionBinding.Factory provisionBindingFactory;
+ private final MembersInjectionBinding.Factory membersInjectionBindingFactory;
+
+ final class BindingsCollection<B extends Binding> {
+ private final Map<Key, B> bindingsByKey = Maps.newLinkedHashMap();
+ private final Deque<B> bindingsRequiringGeneration = new ArrayDeque<>();
+ private final Set<Key> materializedBindingKeys = Sets.newLinkedHashSet();
+
+ void generateBindings(SourceFileGenerator<B> generator) throws SourceFileGenerationException {
+ for (B binding = bindingsRequiringGeneration.poll();
+ binding != null;
+ binding = bindingsRequiringGeneration.poll()) {
+ checkState(!binding.hasNonDefaultTypeParameters());
+ generator.generate(binding);
+ materializedBindingKeys.add(binding.key());
+ }
+ // Because Elements instantiated across processing rounds are not guaranteed to be equals() to
+ // the logically same element, clear the cache after generating
+ bindingsByKey.clear();
+ }
+
+ /** Returns a previously cached binding. */
+ B getBinding(Key key) {
+ return bindingsByKey.get(key);
+ }
+
+ /** Caches the binding and pretends a binding is generated without actually generating it. */
+ B pretendBindingGenerated(B binding, ClassName factoryName) {
+ tryToCacheBinding(binding);
+ if (shouldGenerateBinding(binding, factoryName)) {
+ materializedBindingKeys.add(binding.key());
+ }
+ return binding;
+ }
+
+ /** Caches the binding and generates it if it needs generation. */
+ void tryRegisterBinding(B binding, ClassName factoryName, boolean explicit) {
+ tryToCacheBinding(binding);
+ tryToGenerateBinding(binding, factoryName, explicit);
+ }
+
+ /**
+ * Tries to generate a binding, not generating if it already is generated. For resolved
+ * bindings, this will try to generate the unresolved version of the binding.
+ */
+ void tryToGenerateBinding(B binding, ClassName factoryName, boolean explicit) {
+ if (shouldGenerateBinding(binding, factoryName)) {
+ bindingsRequiringGeneration.offer(binding);
+ if (!explicit) {
+ messager.printMessage(Kind.NOTE, String.format(
+ "Generating a MembersInjector or Factory for %s. "
+ + "Prefer to run the dagger processor over that class instead.",
+ types.erasure(binding.key().type()))); // erasure to strip <T> from msgs.
+ }
+ }
+ }
+
+ /** Returns true if the binding needs to be generated. */
+ private boolean shouldGenerateBinding(B binding, ClassName factoryName) {
+ return !binding.hasNonDefaultTypeParameters()
+ && elements.getTypeElement(factoryName.canonicalName()) == null
+ && !materializedBindingKeys.contains(binding.key())
+ && !bindingsRequiringGeneration.contains(binding);
+
+ }
+
+ /** Caches the binding for future lookups by key. */
+ private void tryToCacheBinding(B binding) {
+ // 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.hasNonDefaultTypeParameters()
+ || binding.bindingTypeElement().getTypeParameters().isEmpty()) {
+ Key key = binding.key();
+ Binding previousValue = bindingsByKey.put(key, binding);
+ checkState(previousValue == null || binding.equals(previousValue),
+ "couldn't register %s. %s was already registered for %s",
+ binding, previousValue, key);
+ }
+ }
+ }
+
+ private final BindingsCollection<ProvisionBinding> provisionBindings = new BindingsCollection<>();
+ private final BindingsCollection<MembersInjectionBinding> membersInjectionBindings =
+ new BindingsCollection<>();
+
+ InjectBindingRegistry(Elements elements,
+ Types types,
+ Messager messager,
+ ProvisionBinding.Factory provisionBindingFactory,
+ MembersInjectionBinding.Factory membersInjectionBindingFactory) {
+ this.elements = elements;
+ this.types = types;
+ this.messager = messager;
+ this.provisionBindingFactory = provisionBindingFactory;
+ this.membersInjectionBindingFactory = membersInjectionBindingFactory;
+ }
+
+ /**
+ * This method ensures that sources for all registered {@link Binding bindings} (either
+ * {@linkplain #registerBinding explicitly} or implicitly via
+ * {@link #getOrFindMembersInjectionBinding} or {@link #getOrFindProvisionBinding}) are generated.
+ */
+ void generateSourcesForRequiredBindings(FactoryGenerator factoryGenerator,
+ MembersInjectorGenerator membersInjectorGenerator) throws SourceFileGenerationException {
+ provisionBindings.generateBindings(factoryGenerator);
+ membersInjectionBindings.generateBindings(membersInjectorGenerator);
+ }
+
+ ProvisionBinding registerBinding(ProvisionBinding binding) {
+ return registerBinding(binding, true);
+ }
+
+ MembersInjectionBinding registerBinding(MembersInjectionBinding binding) {
+ return registerBinding(binding, true);
+ }
+
+ /**
+ * Registers the binding for generation & later lookup. If the binding is resolved, we also
+ * attempt to register an unresolved version of it.
+ */
+ private ProvisionBinding registerBinding(ProvisionBinding binding, boolean explicit) {
+ ClassName factoryName = SourceFiles.factoryNameForProvisionBinding(binding);
+ provisionBindings.tryRegisterBinding(binding, factoryName, explicit);
+ if (binding.hasNonDefaultTypeParameters()) {
+ provisionBindings.tryToGenerateBinding(provisionBindingFactory.unresolve(binding),
+ factoryName, explicit);
+ }
+ return binding;
+ }
+
+ /**
+ * Registers the binding for generation & later lookup. If the binding is resolved, we also
+ * attempt to register an unresolved version of it.
+ */
+ private MembersInjectionBinding registerBinding(
+ MembersInjectionBinding binding, boolean explicit) {
+ ClassName membersInjectorName = membersInjectorNameForType(binding.bindingTypeElement());
+ if (binding.injectionSites().isEmpty()) {
+ // empty members injection bindings are special and don't need source files.
+ // so, we just pretend
+ membersInjectionBindings.pretendBindingGenerated(binding, membersInjectorName);
+ if (binding.hasNonDefaultTypeParameters()) {
+ membersInjectionBindings.pretendBindingGenerated(
+ membersInjectionBindingFactory.unresolve(binding), membersInjectorName);
+ }
+ } else {
+ membersInjectionBindings.tryRegisterBinding(binding, membersInjectorName, explicit);
+ if (binding.hasNonDefaultTypeParameters()) {
+ membersInjectionBindings.tryToGenerateBinding(
+ membersInjectionBindingFactory.unresolve(binding), membersInjectorName, explicit);
+ }
+ }
+ return binding;
+ }
+
+ Optional<ProvisionBinding> getOrFindProvisionBinding(Key key) {
+ checkNotNull(key);
+ if (!key.isValidImplicitProvisionKey(types)) {
+ return Optional.absent();
+ }
+ ProvisionBinding binding = provisionBindings.getBinding(key);
+ if (binding != null) {
+ return Optional.of(binding);
+ }
+
+ // ok, let's see if we can find an @Inject constructor
+ TypeElement element = MoreElements.asType(types.asElement(key.type()));
+ List<ExecutableElement> constructors =
+ ElementFilter.constructorsIn(element.getEnclosedElements());
+ ImmutableSet<ExecutableElement> injectConstructors = FluentIterable.from(constructors)
+ .filter(new Predicate<ExecutableElement>() {
+ @Override public boolean apply(ExecutableElement input) {
+ return isAnnotationPresent(input, Inject.class);
+ }
+ }).toSet();
+ switch (injectConstructors.size()) {
+ case 0:
+ // No constructor found.
+ return Optional.absent();
+ case 1:
+ ProvisionBinding constructorBinding = provisionBindingFactory.forInjectConstructor(
+ Iterables.getOnlyElement(injectConstructors), Optional.of(key.type()));
+ return Optional.of(registerBinding(constructorBinding, false));
+ default:
+ throw new IllegalStateException("Found multiple @Inject constructors: "
+ + injectConstructors);
+ }
+ }
+
+ MembersInjectionBinding getOrFindMembersInjectionBinding(Key key) {
+ checkNotNull(key);
+ // TODO(gak): is checking the kind enough?
+ checkArgument(key.isValidMembersInjectionKey());
+ MembersInjectionBinding binding = membersInjectionBindings.getBinding(key);
+ if (binding != null) {
+ return binding;
+ }
+ return registerBinding(membersInjectionBindingFactory.forInjectedType(
+ MoreTypes.asDeclared(key.type()), Optional.of(key.type())), false);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/InjectConstructorValidator.java b/compiler/src/main/java/dagger/internal/codegen/InjectConstructorValidator.java
new file mode 100644
index 000000000..11cd066fc
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/InjectConstructorValidator.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.lang.model.element.AnnotationMirror;
+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.util.ElementFilter;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static dagger.internal.codegen.ErrorMessages.INJECT_CONSTRUCTOR_ON_ABSTRACT_CLASS;
+import static dagger.internal.codegen.ErrorMessages.INJECT_CONSTRUCTOR_ON_INNER_CLASS;
+import static dagger.internal.codegen.ErrorMessages.INJECT_INTO_PRIVATE_CLASS;
+import static dagger.internal.codegen.ErrorMessages.INJECT_ON_PRIVATE_CONSTRUCTOR;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_INJECT_CONSTRUCTORS;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_QUALIFIERS;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_SCOPES;
+import static dagger.internal.codegen.ErrorMessages.QUALIFIER_ON_INJECT_CONSTRUCTOR;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifiers;
+import static dagger.internal.codegen.InjectionAnnotations.getScopes;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * A {@linkplain ValidationReport validator} for {@link Inject} constructors.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class InjectConstructorValidator {
+ ValidationReport<TypeElement> validate(ExecutableElement constructorElement) {
+ ValidationReport.Builder<TypeElement> builder =
+ ValidationReport.about(MoreElements.asType(constructorElement.getEnclosingElement()));
+ if (constructorElement.getModifiers().contains(PRIVATE)) {
+ builder.addError(INJECT_ON_PRIVATE_CONSTRUCTOR, constructorElement);
+ }
+
+ for (AnnotationMirror qualifier : getQualifiers(constructorElement)) {
+ builder.addError(QUALIFIER_ON_INJECT_CONSTRUCTOR, constructorElement, qualifier);
+ }
+
+ for (VariableElement parameter : constructorElement.getParameters()) {
+ ImmutableSet<? extends AnnotationMirror> qualifiers = getQualifiers(parameter);
+ if (qualifiers.size() > 1) {
+ for (AnnotationMirror qualifier : qualifiers) {
+ builder.addError(MULTIPLE_QUALIFIERS, constructorElement, qualifier);
+ }
+ }
+ }
+
+ TypeElement enclosingElement =
+ MoreElements.asType(constructorElement.getEnclosingElement());
+ Set<Modifier> typeModifiers = enclosingElement.getModifiers();
+
+ if (typeModifiers.contains(PRIVATE)) {
+ builder.addError(INJECT_INTO_PRIVATE_CLASS, constructorElement);
+ }
+
+ if (typeModifiers.contains(ABSTRACT)) {
+ builder.addError(INJECT_CONSTRUCTOR_ON_ABSTRACT_CLASS, constructorElement);
+ }
+
+ if (enclosingElement.getNestingKind().isNested()
+ && !typeModifiers.contains(STATIC)) {
+ builder.addError(INJECT_CONSTRUCTOR_ON_INNER_CLASS, constructorElement);
+ }
+
+ // This is computationally expensive, but probably preferable to a giant index
+ FluentIterable<ExecutableElement> injectConstructors = FluentIterable.from(
+ ElementFilter.constructorsIn(enclosingElement.getEnclosedElements()))
+ .filter(new Predicate<ExecutableElement>() {
+ @Override public boolean apply(ExecutableElement input) {
+ return isAnnotationPresent(input, Inject.class);
+ }
+ });
+
+ if (injectConstructors.size() > 1) {
+ builder.addError(MULTIPLE_INJECT_CONSTRUCTORS, constructorElement);
+ }
+
+ ImmutableSet<? extends AnnotationMirror> scopes = getScopes(enclosingElement);
+ if (scopes.size() > 1) {
+ for (AnnotationMirror scope : scopes) {
+ builder.addError(MULTIPLE_SCOPES, enclosingElement, scope);
+ }
+ }
+
+ return builder.build();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/InjectFieldValidator.java b/compiler/src/main/java/dagger/internal/codegen/InjectFieldValidator.java
new file mode 100644
index 000000000..91143de6e
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/InjectFieldValidator.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.Set;
+import javax.inject.Inject;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.VariableElement;
+import javax.tools.Diagnostic.Kind;
+
+import static dagger.internal.codegen.ErrorMessages.FINAL_INJECT_FIELD;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_QUALIFIERS;
+import static dagger.internal.codegen.ErrorMessages.PRIVATE_INJECT_FIELD;
+import static dagger.internal.codegen.ErrorMessages.STATIC_INJECT_FIELD;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifiers;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * A {@linkplain ValidationReport validator} for {@link Inject} fields.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class InjectFieldValidator {
+ private Kind privateMemberValidationKind;
+ private Kind staticMemberValidationKind;
+
+ public InjectFieldValidator(
+ Kind privateMemberValidationKind, Kind staticMemberValidationKind) {
+ this.privateMemberValidationKind = privateMemberValidationKind;
+ this.staticMemberValidationKind = staticMemberValidationKind;
+ }
+
+ ValidationReport<VariableElement> validate(VariableElement fieldElement) {
+ ValidationReport.Builder<VariableElement> builder = ValidationReport.about(fieldElement);
+ Set<Modifier> modifiers = fieldElement.getModifiers();
+ if (modifiers.contains(FINAL)) {
+ builder.addError(FINAL_INJECT_FIELD, fieldElement);
+ }
+
+ if (modifiers.contains(PRIVATE)) {
+ builder.addItem(PRIVATE_INJECT_FIELD, privateMemberValidationKind, fieldElement);
+ }
+
+ if (modifiers.contains(STATIC)) {
+ builder.addItem(STATIC_INJECT_FIELD, staticMemberValidationKind, fieldElement);
+ }
+
+ ImmutableSet<? extends AnnotationMirror> qualifiers = getQualifiers(fieldElement);
+ if (qualifiers.size() > 1) {
+ for (AnnotationMirror qualifier : qualifiers) {
+ builder.addError(MULTIPLE_QUALIFIERS, fieldElement, qualifier);
+ }
+ }
+
+ return builder.build();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/InjectMethodValidator.java b/compiler/src/main/java/dagger/internal/codegen/InjectMethodValidator.java
new file mode 100644
index 000000000..a716b7d81
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/InjectMethodValidator.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.Set;
+import javax.inject.Inject;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.VariableElement;
+import javax.tools.Diagnostic.Kind;
+
+import static dagger.internal.codegen.ErrorMessages.ABSTRACT_INJECT_METHOD;
+import static dagger.internal.codegen.ErrorMessages.GENERIC_INJECT_METHOD;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_QUALIFIERS;
+import static dagger.internal.codegen.ErrorMessages.PRIVATE_INJECT_METHOD;
+import static dagger.internal.codegen.ErrorMessages.STATIC_INJECT_METHOD;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifiers;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * A {@linkplain ValidationReport validator} for {@link Inject} methods.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class InjectMethodValidator {
+ private Kind privateMemberValidationKind;
+ private Kind staticMemberValidationKind;
+
+ public InjectMethodValidator(
+ Kind privateMemberValidationKind, Kind staticMemberValidationKind) {
+ this.privateMemberValidationKind = privateMemberValidationKind;
+ this.staticMemberValidationKind = staticMemberValidationKind;
+ }
+
+ ValidationReport<ExecutableElement> validate(ExecutableElement methodElement) {
+ ValidationReport.Builder<ExecutableElement> builder = ValidationReport.about(methodElement);
+ Set<Modifier> modifiers = methodElement.getModifiers();
+ if (modifiers.contains(ABSTRACT)) {
+ builder.addError(ABSTRACT_INJECT_METHOD, methodElement);
+ }
+
+ if (modifiers.contains(PRIVATE)) {
+ builder.addItem(PRIVATE_INJECT_METHOD, privateMemberValidationKind, methodElement);
+ }
+
+ if (modifiers.contains(STATIC)) {
+ builder.addItem(STATIC_INJECT_METHOD, staticMemberValidationKind, methodElement);
+ }
+
+ if (!methodElement.getTypeParameters().isEmpty()) {
+ builder.addError(GENERIC_INJECT_METHOD, methodElement);
+ }
+
+ for (VariableElement parameter : methodElement.getParameters()) {
+ ImmutableSet<? extends AnnotationMirror> qualifiers = getQualifiers(parameter);
+ if (qualifiers.size() > 1) {
+ for (AnnotationMirror qualifier : qualifiers) {
+ builder.addError(MULTIPLE_QUALIFIERS, methodElement, qualifier);
+ }
+ }
+ }
+
+ return builder.build();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/InjectProcessingStep.java b/compiler/src/main/java/dagger/internal/codegen/InjectProcessingStep.java
new file mode 100644
index 000000000..61b19c96c
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/InjectProcessingStep.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.BasicAnnotationProcessor;
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+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.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementKindVisitor6;
+
+/**
+ * An annotation processor for generating Dagger implementation code based on the {@link Inject}
+ * annotation.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class InjectProcessingStep implements BasicAnnotationProcessor.ProcessingStep {
+ private final Messager messager;
+ private final InjectConstructorValidator constructorValidator;
+ private final InjectFieldValidator fieldValidator;
+ private final InjectMethodValidator methodValidator;
+ private final ProvisionBinding.Factory provisionBindingFactory;
+ private final MembersInjectionBinding.Factory membersInjectionBindingFactory;
+ private final InjectBindingRegistry injectBindingRegistry;
+
+ InjectProcessingStep(
+ Messager messager,
+ InjectConstructorValidator constructorValidator,
+ InjectFieldValidator fieldValidator,
+ InjectMethodValidator methodValidator,
+ ProvisionBinding.Factory provisionBindingFactory,
+ MembersInjectionBinding.Factory membersInjectionBindingFactory,
+ InjectBindingRegistry factoryRegistrar) {
+ this.messager = messager;
+ this.constructorValidator = constructorValidator;
+ this.fieldValidator = fieldValidator;
+ this.methodValidator = methodValidator;
+ this.provisionBindingFactory = provisionBindingFactory;
+ this.membersInjectionBindingFactory = membersInjectionBindingFactory;
+ this.injectBindingRegistry = factoryRegistrar;
+ }
+
+ @Override
+ public Set<Class<? extends Annotation>> annotations() {
+ return ImmutableSet.<Class<? extends Annotation>>of(Inject.class);
+ }
+
+ @Override
+ public Set<Element> process(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ // TODO(gak): add some error handling for bad source files
+ final ImmutableSet.Builder<ProvisionBinding> provisions = ImmutableSet.builder();
+ // TODO(gak): instead, we should collect reports by type and check later
+ final ImmutableSet.Builder<DeclaredType> membersInjectedTypes = ImmutableSet.builder();
+
+ for (Element injectElement : elementsByAnnotation.get(Inject.class)) {
+ injectElement.accept(
+ new ElementKindVisitor6<Void, Void>() {
+ @Override
+ public Void visitExecutableAsConstructor(ExecutableElement constructorElement, Void v) {
+ ValidationReport<TypeElement> report =
+ constructorValidator.validate(constructorElement);
+
+ report.printMessagesTo(messager);
+
+ if (report.isClean()) {
+ provisions.add(
+ provisionBindingFactory.forInjectConstructor(
+ constructorElement, Optional.<TypeMirror>absent()));
+ DeclaredType type =
+ MoreTypes.asDeclared(constructorElement.getEnclosingElement().asType());
+ if (membersInjectionBindingFactory.hasInjectedMembers(type)) {
+ membersInjectedTypes.add(type);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public Void visitVariableAsField(VariableElement fieldElement, Void p) {
+ ValidationReport<VariableElement> report = fieldValidator.validate(fieldElement);
+
+ report.printMessagesTo(messager);
+
+ if (report.isClean()) {
+ membersInjectedTypes.add(
+ MoreTypes.asDeclared(fieldElement.getEnclosingElement().asType()));
+ }
+
+ return null;
+ }
+
+ @Override
+ public Void visitExecutableAsMethod(ExecutableElement methodElement, Void p) {
+ ValidationReport<ExecutableElement> report = methodValidator.validate(methodElement);
+
+ report.printMessagesTo(messager);
+
+ if (report.isClean()) {
+ membersInjectedTypes.add(
+ MoreTypes.asDeclared(methodElement.getEnclosingElement().asType()));
+ }
+
+ return null;
+ }
+ },
+ null);
+ }
+
+ for (DeclaredType injectedType : membersInjectedTypes.build()) {
+ injectBindingRegistry.registerBinding(membersInjectionBindingFactory.forInjectedType(
+ injectedType, Optional.<TypeMirror>absent()));
+ }
+
+ for (ProvisionBinding binding : provisions.build()) {
+ injectBindingRegistry.registerBinding(binding);
+ }
+ return ImmutableSet.of();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/InjectionAnnotations.java b/compiler/src/main/java/dagger/internal/codegen/InjectionAnnotations.java
new file mode 100644
index 000000000..b3b245dfb
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/InjectionAnnotations.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.AnnotationMirrors;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import javax.inject.Qualifier;
+import javax.inject.Scope;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Utilities relating to annotations defined in the {@code javax.inject} package.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class InjectionAnnotations {
+ static Optional<AnnotationMirror> getScopeAnnotation(Element e) {
+ checkNotNull(e);
+ ImmutableSet<? extends AnnotationMirror> scopeAnnotations = getScopes(e);
+ switch (scopeAnnotations.size()) {
+ case 0:
+ return Optional.absent();
+ case 1:
+ return Optional.<AnnotationMirror>of(scopeAnnotations.iterator().next());
+ default:
+ throw new IllegalArgumentException(
+ e + " was annotated with more than one @Scope annotation");
+ }
+ }
+
+ static Optional<AnnotationMirror> getQualifier(Element e) {
+ checkNotNull(e);
+ ImmutableSet<? extends AnnotationMirror> qualifierAnnotations = getQualifiers(e);
+ switch (qualifierAnnotations.size()) {
+ case 0:
+ return Optional.absent();
+ case 1:
+ return Optional.<AnnotationMirror>of(qualifierAnnotations.iterator().next());
+ default:
+ throw new IllegalArgumentException(
+ e + " was annotated with more than one @Qualifier annotation");
+ }
+ }
+
+ static ImmutableSet<? extends AnnotationMirror> getQualifiers(Element element) {
+ return AnnotationMirrors.getAnnotatedAnnotations(element, Qualifier.class);
+ }
+
+ static ImmutableSet<? extends AnnotationMirror> getScopes(Element element) {
+ return AnnotationMirrors.getAnnotatedAnnotations(element, Scope.class);
+ }
+
+ private InjectionAnnotations() {}
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/Key.java b/compiler/src/main/java/dagger/internal/codegen/Key.java
new file mode 100644
index 000000000..c14cc22c4
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/Key.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.AnnotationMirrors;
+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.google.common.base.MoreObjects;
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.Provides;
+import dagger.producers.Producer;
+import dagger.producers.Produces;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Provider;
+import javax.inject.Qualifier;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.Types;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifier;
+import static dagger.internal.codegen.MapKeys.getMapKey;
+import static dagger.internal.codegen.MapKeys.getUnwrappedMapKeyType;
+import static dagger.internal.codegen.Util.unwrapOptionalEquivalence;
+import static dagger.internal.codegen.Util.wrapOptionalInEquivalence;
+import static javax.lang.model.element.ElementKind.METHOD;
+
+/**
+ * Represents a unique combination of {@linkplain TypeMirror type} and
+ * {@linkplain Qualifier qualifier} to which binding can occur.
+ *
+ * @author Gregory Kick
+ */
+@AutoValue
+abstract class Key {
+ /**
+ * A {@link javax.inject.Qualifier} annotation that provides a unique namespace prefix
+ * for the type of this key.
+ *
+ * Despite documentation in {@link AnnotationMirror}, equals and hashCode aren't implemented
+ * to represent logical equality, so {@link AnnotationMirrors#equivalence()}
+ * provides this facility.
+ */
+ abstract Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedQualifier();
+
+ /**
+ * The type represented by this key.
+ *
+ * As documented in {@link TypeMirror}, equals and hashCode aren't implemented to represent
+ * logical equality, so {@link MoreTypes#equivalence()} wraps this type.
+ */
+ abstract Equivalence.Wrapper<TypeMirror> wrappedType();
+
+ Optional<AnnotationMirror> qualifier() {
+ return unwrapOptionalEquivalence(wrappedQualifier());
+ }
+
+ TypeMirror type() {
+ return wrappedType().get();
+ }
+
+ private static TypeMirror normalize(Types types, TypeMirror type) {
+ TypeKind kind = type.getKind();
+ return kind.isPrimitive() ? types.boxedClass((PrimitiveType) type).asType() : type;
+ }
+
+ Key withType(Types types, TypeMirror newType) {
+ return new AutoValue_Key(wrappedQualifier(),
+ MoreTypes.equivalence().wrap(normalize(types, newType)));
+ }
+
+ boolean isValidMembersInjectionKey() {
+ return !qualifier().isPresent();
+ }
+
+ /**
+ * Returns true if the key is valid as an implicit key (that is, if it's valid for a just-in-time
+ * binding by discovering an {@code @Inject} constructor).
+ */
+ boolean isValidImplicitProvisionKey(final Types types) {
+ // Qualifiers disqualify implicit provisioning.
+ if (qualifier().isPresent()) {
+ return false;
+ }
+
+ return type().accept(new SimpleTypeVisitor6<Boolean, Void>() {
+ @Override protected Boolean defaultAction(TypeMirror e, Void p) {
+ return false; // Only declared types are allowed.
+ }
+
+ @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;
+ }
+
+ // 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;
+ }
+ }
+
+ // 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);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(Key.class)
+ .omitNullValues()
+ .add("qualifier", qualifier().orNull())
+ .add("type", type())
+ .toString();
+ }
+
+ static final class Factory {
+ private final Types types;
+ private final Elements elements;
+
+ Factory(Types types, Elements elements) {
+ this.types = checkNotNull(types);
+ this.elements = checkNotNull(elements);
+ }
+
+ private TypeElement getSetElement() {
+ return elements.getTypeElement(Set.class.getCanonicalName());
+ }
+
+ private TypeElement getMapElement() {
+ return elements.getTypeElement(Map.class.getCanonicalName());
+ }
+
+ private TypeElement getProviderElement() {
+ return elements.getTypeElement(Provider.class.getCanonicalName());
+ }
+
+ private TypeElement getProducerElement() {
+ return elements.getTypeElement(Producer.class.getCanonicalName());
+ }
+
+ private TypeElement getClassElement(Class<?> cls) {
+ return elements.getTypeElement(cls.getCanonicalName());
+ }
+
+ Key forComponentMethod(ExecutableElement componentMethod) {
+ checkNotNull(componentMethod);
+ checkArgument(componentMethod.getKind().equals(METHOD));
+ TypeMirror returnType = normalize(types, componentMethod.getReturnType());
+ return forMethod(componentMethod, returnType);
+ }
+
+ Key forProductionComponentMethod(ExecutableElement componentMethod) {
+ checkNotNull(componentMethod);
+ checkArgument(componentMethod.getKind().equals(METHOD));
+ TypeMirror returnType = normalize(types, componentMethod.getReturnType());
+ TypeMirror keyType = returnType;
+ if (MoreTypes.isTypeOf(ListenableFuture.class, returnType)) {
+ keyType = Iterables.getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments());
+ }
+ return forMethod(componentMethod, keyType);
+ }
+
+ Key forProvidesMethod(ExecutableType executableType, ExecutableElement method) {
+ checkNotNull(method);
+ checkArgument(method.getKind().equals(METHOD));
+ Provides providesAnnotation = method.getAnnotation(Provides.class);
+ checkArgument(providesAnnotation != null);
+ TypeMirror returnType = normalize(types, executableType.getReturnType());
+ TypeMirror keyType =
+ providesOrProducesKeyType(
+ returnType,
+ method,
+ Optional.of(providesAnnotation.type()),
+ Optional.<Produces.Type>absent());
+ return forMethod(method, keyType);
+ }
+
+ // TODO(user): Reconcile this method with forProvidesMethod when Provides.Type and
+ // Produces.Type are no longer different.
+ Key forProducesMethod(ExecutableType executableType, ExecutableElement method) {
+ checkNotNull(method);
+ checkArgument(method.getKind().equals(METHOD));
+ Produces producesAnnotation = method.getAnnotation(Produces.class);
+ checkArgument(producesAnnotation != null);
+ TypeMirror returnType = normalize(types, executableType.getReturnType());
+ TypeMirror unfuturedType = returnType;
+ if (MoreTypes.isTypeOf(ListenableFuture.class, returnType)) {
+ unfuturedType =
+ Iterables.getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments());
+ }
+ TypeMirror keyType =
+ providesOrProducesKeyType(
+ unfuturedType,
+ method,
+ Optional.<Provides.Type>absent(),
+ Optional.of(producesAnnotation.type()));
+ return forMethod(method, keyType);
+ }
+
+ private TypeMirror providesOrProducesKeyType(
+ TypeMirror returnType,
+ ExecutableElement method,
+ Optional<Provides.Type> providesType,
+ Optional<Produces.Type> producesType) {
+ switch (providesType.isPresent()
+ ? providesType.get()
+ : Provides.Type.valueOf(producesType.get().name())) {
+ case UNIQUE:
+ return returnType;
+ case SET:
+ return types.getDeclaredType(getSetElement(), returnType);
+ case MAP:
+ return mapOfFactoryType(
+ method,
+ returnType,
+ providesType.isPresent() ? getProviderElement() : getProducerElement());
+ case SET_VALUES:
+ // TODO(gak): do we want to allow people to use "covariant return" here?
+ checkArgument(MoreTypes.isType(returnType) && MoreTypes.isTypeOf(Set.class, returnType));
+ return returnType;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private TypeMirror mapOfFactoryType(
+ ExecutableElement method, TypeMirror valueType, TypeElement factoryType) {
+ TypeMirror mapKeyType = mapKeyType(method);
+ TypeMirror mapValueFactoryType = types.getDeclaredType(factoryType, valueType);
+ return types.getDeclaredType(getMapElement(), mapKeyType, mapValueFactoryType);
+ }
+
+ private TypeMirror mapKeyType(ExecutableElement method) {
+ AnnotationMirror mapKeyAnnotation = getMapKey(method).get();
+ return MapKeys.unwrapValue(mapKeyAnnotation).isPresent()
+ ? getUnwrappedMapKeyType(mapKeyAnnotation.getAnnotationType(), types)
+ : mapKeyAnnotation.getAnnotationType();
+ }
+
+ private Key forMethod(ExecutableElement method, TypeMirror keyType) {
+ return new AutoValue_Key(
+ wrapOptionalInEquivalence(AnnotationMirrors.equivalence(), getQualifier(method)),
+ MoreTypes.equivalence().wrap(keyType));
+ }
+
+ Key forInjectConstructorWithResolvedType(TypeMirror type) {
+ return new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(type));
+ }
+
+ Key forComponent(TypeMirror type) {
+ return new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(normalize(types, type)));
+ }
+
+ Key forMembersInjectedType(TypeMirror type) {
+ return new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(normalize(types, type)));
+ }
+
+ Key forQualifiedType(Optional<AnnotationMirror> qualifier, TypeMirror type) {
+ return new AutoValue_Key(
+ wrapOptionalInEquivalence(AnnotationMirrors.equivalence(), qualifier),
+ MoreTypes.equivalence().wrap(normalize(types, type)));
+ }
+
+ /**
+ * Optionally extract a {@link Key} for the underlying provision binding(s) if such a
+ * valid key can be inferred from the given key. Specifically, if the key represents a
+ * {@link Map}{@code <K, V>}, a key of {@code Map<K, Provider<V>>} will be returned.
+ */
+ Optional<Key> implicitMapProviderKeyFrom(Key possibleMapKey) {
+ return maybeWrapMapValue(possibleMapKey, Provider.class);
+ }
+
+ /**
+ * Optionally extract a {@link Key} for the underlying production binding(s) if such a
+ * valid key can be inferred from the given key. Specifically, if the key represents a
+ * {@link Map}{@code <K, V>}, a key of {@code Map<K, Producer<V>>} will be returned.
+ */
+ Optional<Key> implicitMapProducerKeyFrom(Key possibleMapKey) {
+ return maybeWrapMapValue(possibleMapKey, Producer.class);
+ }
+
+ /**
+ * Returns a key of {@link Map}{@code <K, WrappingClass<V>>} if the input key represents a
+ * {@code Map<K, V>}.
+ */
+ private Optional<Key> maybeWrapMapValue(Key possibleMapKey, Class<?> wrappingClass) {
+ if (MoreTypes.isTypeOf(Map.class, possibleMapKey.type())) {
+ DeclaredType declaredMapType = MoreTypes.asDeclared(possibleMapKey.type());
+ TypeMirror mapValueType = Util.getValueTypeOfMap(declaredMapType);
+ if (!MoreTypes.isTypeOf(wrappingClass, mapValueType)) {
+ DeclaredType keyType = Util.getKeyTypeOfMap(declaredMapType);
+ TypeElement wrappingElement = getClassElement(wrappingClass);
+ if (wrappingElement == null) {
+ // This target might not be compiled with Producers, so wrappingClass might not have an
+ // associated element.
+ return Optional.absent();
+ }
+ DeclaredType wrappedType = types.getDeclaredType(wrappingElement, mapValueType);
+ TypeMirror mapType = types.getDeclaredType(getMapElement(), keyType, wrappedType);
+ return Optional.<Key>of(new AutoValue_Key(
+ possibleMapKey.wrappedQualifier(),
+ MoreTypes.equivalence().wrap(mapType)));
+ }
+ }
+ return Optional.absent();
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/KeyFormatter.java b/compiler/src/main/java/dagger/internal/codegen/KeyFormatter.java
new file mode 100644
index 000000000..d2e62fcab
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/KeyFormatter.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+/**
+ * Formats a {@link Key} into a {@link String} suitable for use in error messages
+ *
+ * @author Christian Gruber
+ * @since 2.0
+ */
+final class KeyFormatter extends Formatter<Key> {
+
+ @Override public String format(Key request) {
+ StringBuilder builder = new StringBuilder();
+ if (request.qualifier().isPresent()) {
+ builder.append(request.qualifier()); // TODO(cgruber): Use AnnotationMirrorFormatter.
+ builder.append(' ');
+ }
+ builder.append(request.type()); // TODO(cgruber): Use TypeMirrorFormatter.
+ return builder.toString();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/KeyVariableNamer.java b/compiler/src/main/java/dagger/internal/codegen/KeyVariableNamer.java
new file mode 100644
index 000000000..5fe12b102
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/KeyVariableNamer.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.base.Function;
+import java.util.Iterator;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleTypeVisitor6;
+
+import static com.google.common.base.CaseFormat.LOWER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+
+/**
+ * Suggests a variable name for a type based on a {@link Key}. Prefer
+ * {@link DependencyVariableNamer} for cases where a specific {@link DependencyRequest} is present.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+enum KeyVariableNamer implements Function<Key, String> {
+ INSTANCE;
+
+ @Override
+ public String apply(Key key) {
+ StringBuilder builder = new StringBuilder();
+
+ if (key.qualifier().isPresent()) {
+ // TODO(gak): Use a better name for fields with qualifiers with members.
+ builder.append(key.qualifier().get().getAnnotationType().asElement().getSimpleName());
+ }
+
+ key.type().accept(new SimpleTypeVisitor6<Void, StringBuilder>() {
+ @Override
+ public Void visitDeclared(DeclaredType t, StringBuilder builder) {
+ builder.append(t.asElement().getSimpleName());
+ Iterator<? extends TypeMirror> argumentIterator = t.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;
+ }
+ }, builder);
+
+ return UPPER_CAMEL.to(LOWER_CAMEL, builder.toString());
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MapKeyGenerator.java b/compiler/src/main/java/dagger/internal/codegen/MapKeyGenerator.java
new file mode 100644
index 000000000..8d72e5e48
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MapKeyGenerator.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreTypes;
+import com.google.auto.value.AutoAnnotation;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import dagger.MapKey;
+import dagger.internal.codegen.MapKeyGenerator.MapKeyCreatorSpecification;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.MethodWriter;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import dagger.internal.codegen.writer.TypeWriter;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.annotation.processing.Filer;
+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;
+
+import static dagger.internal.codegen.MapKeys.getMapKeyCreatorClassName;
+import static dagger.internal.codegen.writer.Snippet.makeParametersSnippet;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+/**
+ * Generates classes that create annotations required to instantiate {@link MapKey}s.
+ *
+ * @since 2.0
+ */
+final class MapKeyGenerator extends SourceFileGenerator<MapKeyCreatorSpecification> {
+
+ /**
+ * Specification of the {@link MapKey} annotation and the annotation type to generate.
+ */
+ @AutoValue
+ abstract static class MapKeyCreatorSpecification {
+ /**
+ * The {@link MapKey}-annotated annotation.
+ */
+ abstract TypeElement mapKeyElement();
+
+ /**
+ * The annotation type to write create methods for. For wrapped {@link MapKey}s, this is
+ * {@link #mapKeyElement()}. For unwrapped {@code MapKey}s whose single element is an
+ * annotation, this is that annotation element.
+ */
+ abstract TypeElement annotationElement();
+
+ /**
+ * Returns a specification for a wrapped {@link MapKey}-annotated annotation.
+ */
+ static MapKeyCreatorSpecification wrappedMapKey(TypeElement mapKeyElement) {
+ return new AutoValue_MapKeyGenerator_MapKeyCreatorSpecification(mapKeyElement, mapKeyElement);
+ }
+
+ /**
+ * Returns a specification for an unwrapped {@link MapKey}-annotated annotation whose single
+ * element is a nested annotation.
+ */
+ static MapKeyCreatorSpecification unwrappedMapKeyWithAnnotationValue(
+ TypeElement mapKeyElement, TypeElement annotationElement) {
+ return new AutoValue_MapKeyGenerator_MapKeyCreatorSpecification(
+ mapKeyElement, annotationElement);
+ }
+ }
+
+ MapKeyGenerator(Filer filer) {
+ super(filer);
+ }
+
+ @Override
+ ClassName nameGeneratedType(MapKeyCreatorSpecification mapKeyCreatorType) {
+ return getMapKeyCreatorClassName(mapKeyCreatorType.mapKeyElement());
+ }
+
+ @Override
+ Iterable<? extends Element> getOriginatingElements(MapKeyCreatorSpecification mapKeyCreatorType) {
+ return ImmutableSet.of(mapKeyCreatorType.mapKeyElement());
+ }
+
+ @Override
+ Optional<? extends Element> getElementForErrorReporting(
+ MapKeyCreatorSpecification mapKeyCreatorType) {
+ return Optional.of(mapKeyCreatorType.mapKeyElement());
+ }
+
+ @Override
+ ImmutableSet<JavaWriter> write(
+ ClassName generatedTypeName, MapKeyCreatorSpecification mapKeyCreatorType) {
+ JavaWriter writer = JavaWriter.inPackage(generatedTypeName.packageName());
+ TypeWriter mapKeyCreatorWriter = writer.addClass(generatedTypeName.simpleName());
+ mapKeyCreatorWriter.annotate(Generated.class).setValue(ComponentProcessor.class.getName());
+ mapKeyCreatorWriter.addModifiers(PUBLIC, FINAL);
+
+ for (TypeElement annotationElement :
+ nestedAnnotationElements(mapKeyCreatorType.annotationElement())) {
+ writeCreateMethod(mapKeyCreatorWriter, annotationElement);
+ }
+
+ return ImmutableSet.of(writer);
+ }
+
+ private void writeCreateMethod(TypeWriter mapKeyCreatorWriter, TypeElement annotationElement) {
+ MethodWriter createMethod =
+ mapKeyCreatorWriter.addMethod(
+ annotationElement.asType(), "create" + annotationElement.getSimpleName());
+
+ createMethod.annotate(AutoAnnotation.class);
+ createMethod.addModifiers(PUBLIC, STATIC);
+
+ ImmutableList.Builder<Snippet> parameters = ImmutableList.builder();
+ for (ExecutableElement annotationMember : methodsIn(annotationElement.getEnclosedElements())) {
+ String parameterName = annotationMember.getSimpleName().toString();
+ TypeName parameterType = TypeNames.forTypeMirror(annotationMember.getReturnType());
+ createMethod.addParameter(parameterType, parameterName);
+ parameters.add(Snippet.format("%s", parameterName));
+ }
+
+ ClassName autoAnnotationClass = mapKeyCreatorWriter.name().peerNamed(
+ "AutoAnnotation_" + mapKeyCreatorWriter.name().simpleName() + "_" + createMethod.name());
+ createMethod.body().addSnippet(
+ "return new %s(%s);", autoAnnotationClass, makeParametersSnippet(parameters.build()));
+ }
+
+ private static Set<TypeElement> nestedAnnotationElements(TypeElement annotationElement) {
+ return nestedAnnotationElements(annotationElement, new LinkedHashSet<TypeElement>());
+ }
+
+ private static Set<TypeElement> nestedAnnotationElements(
+ TypeElement annotationElement, Set<TypeElement> annotationElements) {
+ if (annotationElements.add(annotationElement)) {
+ for (ExecutableElement method : methodsIn(annotationElement.getEnclosedElements())) {
+ TRAVERSE_NESTED_ANNOTATIONS.visit(method.getReturnType(), 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/compiler/src/main/java/dagger/internal/codegen/MapKeyProcessingStep.java b/compiler/src/main/java/dagger/internal/codegen/MapKeyProcessingStep.java
new file mode 100644
index 000000000..c4a264aa6
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MapKeyProcessingStep.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.BasicAnnotationProcessor;
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+import dagger.MapKey;
+import dagger.internal.codegen.MapKeyGenerator.MapKeyCreatorSpecification;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.util.Types;
+
+import static dagger.internal.codegen.MapKeyGenerator.MapKeyCreatorSpecification.unwrappedMapKeyWithAnnotationValue;
+import static dagger.internal.codegen.MapKeyGenerator.MapKeyCreatorSpecification.wrappedMapKey;
+import static dagger.internal.codegen.MapKeys.getUnwrappedMapKeyType;
+
+/**
+ * The annotation processor responsible for validating the mapKey annotation and auto-generate
+ * implementation of annotations marked with &#064MapKey where necessary.
+ *
+ * @author Chenying Hou
+ * @since 2.0
+ */
+public class MapKeyProcessingStep implements BasicAnnotationProcessor.ProcessingStep {
+ private final Messager messager;
+ private final Types types;
+ private final MapKeyValidator mapKeyValidator;
+ private final MapKeyGenerator mapKeyGenerator;
+
+ MapKeyProcessingStep(
+ Messager messager,
+ Types types,
+ MapKeyValidator mapKeyValidator,
+ MapKeyGenerator mapKeyGenerator) {
+ this.messager = messager;
+ this.types = types;
+ this.mapKeyValidator = mapKeyValidator;
+ this.mapKeyGenerator = mapKeyGenerator;
+ }
+
+ @Override
+ public Set<Class<? extends Annotation>> annotations() {
+ return ImmutableSet.<Class<? extends Annotation>>of(MapKey.class);
+ }
+
+ @Override
+ public Set<Element> process(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ for (Element element : elementsByAnnotation.get(MapKey.class)) {
+ ValidationReport<Element> mapKeyReport = mapKeyValidator.validate(element);
+ mapKeyReport.printMessagesTo(messager);
+
+ if (mapKeyReport.isClean()) {
+ MapKey mapkey = element.getAnnotation(MapKey.class);
+ if (mapkey.unwrapValue()) {
+ DeclaredType keyType =
+ getUnwrappedMapKeyType(MoreTypes.asDeclared(element.asType()), types);
+ if (keyType.asElement().getKind() == ElementKind.ANNOTATION_TYPE) {
+ writeCreatorClass(
+ unwrappedMapKeyWithAnnotationValue(
+ MoreElements.asType(element), MoreTypes.asTypeElement(keyType)));
+ }
+ } else {
+ writeCreatorClass(wrappedMapKey(MoreElements.asType(element)));
+ }
+ }
+ }
+ return ImmutableSet.of();
+ }
+
+ private void writeCreatorClass(MapKeyCreatorSpecification mapKeyCreatorType) {
+ try {
+ mapKeyGenerator.generate(mapKeyCreatorType);
+ } catch (SourceFileGenerationException e) {
+ e.printMessageTo(messager);
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MapKeyValidator.java b/compiler/src/main/java/dagger/internal/codegen/MapKeyValidator.java
new file mode 100644
index 000000000..d6aa2f21c
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MapKeyValidator.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 dagger.MapKey;
+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.type.TypeKind;
+
+import static dagger.internal.codegen.ErrorMessages.MAPKEY_WITHOUT_MEMBERS;
+import static dagger.internal.codegen.ErrorMessages.UNWRAPPED_MAP_KEY_WITH_ARRAY_MEMBER;
+import static dagger.internal.codegen.ErrorMessages.UNWRAPPED_MAP_KEY_WITH_TOO_MANY_MEMBERS;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+/**
+ * A {@link Validator} for {@link MapKey} annotations.
+ *
+ * @author Chenying Hou
+ * @since 2.0
+ */
+// TODO(dpb,gak): Should unwrapped MapKeys be required to have their single member be named "value"?
+final class MapKeyValidator {
+ ValidationReport<Element> validate(Element element) {
+ ValidationReport.Builder<Element> builder = ValidationReport.about(element);
+ List<ExecutableElement> members = methodsIn(((TypeElement) element).getEnclosedElements());
+ if (members.isEmpty()) {
+ builder.addError(MAPKEY_WITHOUT_MEMBERS, element);
+ } else if (element.getAnnotation(MapKey.class).unwrapValue()) {
+ if (members.size() > 1) {
+ builder.addError(UNWRAPPED_MAP_KEY_WITH_TOO_MANY_MEMBERS, element);
+ } else if (members.get(0).getReturnType().getKind() == TypeKind.ARRAY) {
+ builder.addError(UNWRAPPED_MAP_KEY_WITH_ARRAY_MEMBER, element);
+ }
+ }
+ return builder.build();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MapKeys.java b/compiler/src/main/java/dagger/internal/codegen/MapKeys.java
new file mode 100644
index 000000000..4d79a28c8
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MapKeys.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreTypes;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import dagger.MapKey;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+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.element.VariableElement;
+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.SimpleAnnotationValueVisitor6;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.Types;
+
+import static com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations;
+import static com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.google.common.collect.Iterables.transform;
+import static dagger.internal.codegen.writer.Snippet.makeParametersSnippet;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+/**
+ * Methods for extracting {@link MapKey} annotations and key snippets from binding elements.
+ */
+final class MapKeys {
+
+ /**
+ * 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<? extends AnnotationMirror> getMapKey(Element bindingElement) {
+ ImmutableSet<? extends AnnotationMirror> mapKeys = getMapKeys(bindingElement);
+ return mapKeys.isEmpty()
+ ? Optional.<AnnotationMirror>absent()
+ : Optional.of(getOnlyElement(mapKeys));
+ }
+
+ /**
+ * Returns all of the {@link MapKey} annotations that annotate {@code bindingElement}.
+ */
+ static ImmutableSet<? extends AnnotationMirror> getMapKeys(Element bindingElement) {
+ return getAnnotatedAnnotations(bindingElement, MapKey.class);
+ }
+
+ /**
+ * Returns the annotation value if {@code mapKey}'s type is annotated with
+ * {@link MapKey @MapKey(unwrapValue = true)}.
+ *
+ * @throws IllegalArgumentException if {@code mapKey}'s type is not annotated with
+ * {@link MapKey @MapKey} at all.
+ */
+ static Optional<? extends AnnotationValue> unwrapValue(AnnotationMirror mapKey) {
+ MapKey mapKeyAnnotation = mapKey.getAnnotationType().asElement().getAnnotation(MapKey.class);
+ checkArgument(
+ mapKeyAnnotation != null, "%s is not annotated with @MapKey", mapKey.getAnnotationType());
+ return mapKeyAnnotation.unwrapValue()
+ ? Optional.of(getOnlyElement(mapKey.getElementValues().values()))
+ : Optional.<AnnotationValue>absent();
+ }
+
+ /**
+ * Returns the map key type for an unwrapped {@link MapKey} annotation type. If the single member
+ * type is primitive, returns the boxed type.
+ *
+ * @throws IllegalArgumentException if {@code mapKeyAnnotationType} is not an annotation type or
+ * 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 Types types) {
+ checkArgument(
+ MoreTypes.asTypeElement(mapKeyAnnotationType).getKind() == ElementKind.ANNOTATION_TYPE,
+ "%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());
+ }
+
+ /**
+ * Returns the name of the generated class that contains the static {@code create} methods for a
+ * {@link MapKey} annotation type.
+ */
+ public static ClassName getMapKeyCreatorClassName(TypeElement mapKeyType) {
+ ClassName mapKeyTypeName = ClassName.fromTypeElement(mapKeyType);
+ return mapKeyTypeName.topLevelClassName().peerNamed(mapKeyTypeName.classFileName() + "Creator");
+ }
+
+ /**
+ * Returns a snippet for the map key specified by the {@link MapKey} annotation on
+ * {@code bindingElement}.
+ *
+ * @throws IllegalArgumentException if the element is annotated with more than one {@code MapKey}
+ * annotation
+ * @throws IllegalStateException if {@code bindingElement} is not annotated with a {@code MapKey}
+ * annotation
+ */
+ static Snippet getMapKeySnippet(Element bindingElement) {
+ AnnotationMirror mapKey = getMapKey(bindingElement).get();
+ ClassName mapKeyCreator =
+ getMapKeyCreatorClassName(MoreTypes.asTypeElement(mapKey.getAnnotationType()));
+ Optional<? extends AnnotationValue> unwrappedValue = unwrapValue(mapKey);
+ if (unwrappedValue.isPresent()) {
+ return new MapKeySnippetExceptArrays(mapKeyCreator)
+ .visit(unwrappedValue.get(), unwrappedValue.get());
+ } else {
+ return annotationSnippet(mapKey, new MapKeySnippet(mapKeyCreator));
+ }
+ }
+
+ /**
+ * Returns a snippet to create the visited value in code. Expects its parameter to be a class with
+ * static creation methods for all nested annotation types.
+ *
+ * <p>Note that {@link AnnotationValue#toString()} is the source-code representation of the value
+ * <em>when used in an annotation</em>, which is not always the same as the representation needed
+ * when creating the value in a method body.
+ *
+ * <p>For example, inside an annotation, a nested array of {@code int}s is simply
+ * <code>{1, 2, 3}</code>, but in code it would have to be <code> new int[] {1, 2, 3}</code>.
+ */
+ private static class MapKeySnippet
+ extends SimpleAnnotationValueVisitor6<Snippet, AnnotationValue> {
+
+ final ClassName mapKeyCreator;
+
+ MapKeySnippet(ClassName mapKeyCreator) {
+ this.mapKeyCreator = mapKeyCreator;
+ }
+
+ @Override
+ public Snippet visitEnumConstant(VariableElement c, AnnotationValue p) {
+ return Snippet.format(
+ "%s.%s", TypeNames.forTypeMirror(c.getEnclosingElement().asType()), c.getSimpleName());
+ }
+
+ @Override
+ public Snippet visitAnnotation(AnnotationMirror a, AnnotationValue p) {
+ return annotationSnippet(a, this);
+ }
+
+ @Override
+ public Snippet visitType(TypeMirror t, AnnotationValue p) {
+ return Snippet.format("%s.class", TypeNames.forTypeMirror(t));
+ }
+
+ @Override
+ public Snippet visitString(String s, AnnotationValue p) {
+ return Snippet.format("%s", p);
+ }
+
+ @Override
+ public Snippet visitByte(byte b, AnnotationValue p) {
+ return Snippet.format("(byte) %s", b);
+ }
+
+ @Override
+ public Snippet visitChar(char c, AnnotationValue p) {
+ return Snippet.format("%s", p);
+ }
+
+ @Override
+ public Snippet visitDouble(double d, AnnotationValue p) {
+ return Snippet.format("%sD", d);
+ }
+
+ @Override
+ public Snippet visitFloat(float f, AnnotationValue p) {
+ return Snippet.format("%sF", f);
+ }
+
+ @Override
+ public Snippet visitInt(int i, AnnotationValue p) {
+ return Snippet.format("(int) %s", i);
+ }
+
+ @Override
+ public Snippet visitLong(long i, AnnotationValue p) {
+ return Snippet.format("%sL", i);
+ }
+
+ @Override
+ public Snippet visitShort(short s, AnnotationValue p) {
+ return Snippet.format("(short) %s", s);
+ }
+
+ @Override
+ protected Snippet defaultAction(Object o, AnnotationValue p) {
+ return Snippet.format("%s", o);
+ }
+
+ @Override
+ public Snippet visitArray(List<? extends AnnotationValue> values, AnnotationValue p) {
+ ImmutableList.Builder<Snippet> snippets = ImmutableList.builder();
+ for (int i = 0; i < values.size(); i++) {
+ snippets.add(this.visit(values.get(i), p));
+ }
+ return Snippet.format("{%s}", makeParametersSnippet(snippets.build()));
+ }
+ }
+
+ /**
+ * Returns a snippet for the visited value. Expects its parameter to be a class with static
+ * creation methods for all nested annotation types.
+ *
+ * <p>Throws {@link IllegalArgumentException} if the visited value is an array.
+ */
+ private static class MapKeySnippetExceptArrays extends MapKeySnippet {
+
+ MapKeySnippetExceptArrays(ClassName mapKeyCreator) {
+ super(mapKeyCreator);
+ }
+
+ @Override
+ public Snippet visitArray(List<? extends AnnotationValue> values, AnnotationValue p) {
+ throw new IllegalArgumentException("Cannot unwrap arrays");
+ }
+ }
+
+ /**
+ * Returns a snippet that calls a static method on {@code mapKeySnippet.mapKeyCreator} to create
+ * an annotation from {@code mapKeyAnnotation}.
+ */
+ private static Snippet annotationSnippet(
+ AnnotationMirror mapKeyAnnotation, final MapKeySnippet mapKeySnippet) {
+ return Snippet.format(
+ "%s.create%s(%s)",
+ mapKeySnippet.mapKeyCreator,
+ mapKeyAnnotation.getAnnotationType().asElement().getSimpleName(),
+ makeParametersSnippet(
+ transform(
+ getAnnotationValuesWithDefaults(mapKeyAnnotation).entrySet(),
+ new Function<Map.Entry<ExecutableElement, AnnotationValue>, Snippet>() {
+ @Override
+ public Snippet apply(Map.Entry<ExecutableElement, AnnotationValue> entry) {
+ return ARRAY_LITERAL_PREFIX.visit(
+ entry.getKey().getReturnType(),
+ mapKeySnippet.visit(entry.getValue(), entry.getValue()));
+ }
+ })));
+ }
+
+ /**
+ * If the visited type is an array, prefixes the parameter snippet with {@code new T[]}, where
+ * {@code T} is the raw array component type.
+ */
+ private static final SimpleTypeVisitor6<Snippet, Snippet> ARRAY_LITERAL_PREFIX =
+ new SimpleTypeVisitor6<Snippet, Snippet>() {
+
+ @Override
+ public Snippet visitArray(ArrayType t, Snippet p) {
+ return Snippet.format("new %s[] %s", RAW_TYPE_NAME.visit(t.getComponentType()), p);
+ }
+
+ @Override
+ protected Snippet defaultAction(TypeMirror e, Snippet 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.fromTypeElement(MoreTypes.asTypeElement(t));
+ }
+
+ @Override
+ protected TypeName defaultAction(TypeMirror e, Void p) {
+ return TypeNames.forTypeMirror(e);
+ }
+ };
+
+ private MapKeys() {}
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MembersInjectionBinding.java b/compiler/src/main/java/dagger/internal/codegen/MembersInjectionBinding.java
new file mode 100644
index 000000000..87b2ab187
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MembersInjectionBinding.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.SetMultimap;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.inject.Inject;
+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.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.util.ElementKindVisitor6;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+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 javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * Represents the full members injection of a particular type. This does not pay attention to
+ * injected members on supertypes.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@AutoValue
+abstract class MembersInjectionBinding extends Binding {
+ @Override abstract TypeElement bindingElement();
+
+ /** The set of individual sites where {@link Inject} is applied. */
+ abstract ImmutableSortedSet<InjectionSite> injectionSites();
+
+ abstract Optional<DependencyRequest> parentInjectorRequest();
+
+ enum Strategy {
+ NO_OP,
+ INJECT_MEMBERS,
+ }
+
+ Strategy injectionStrategy() {
+ return injectionSites().isEmpty() ? Strategy.NO_OP : Strategy.INJECT_MEMBERS;
+ }
+
+ MembersInjectionBinding withoutParentInjectorRequest() {
+ return new AutoValue_MembersInjectionBinding(
+ key(),
+ dependencies(),
+ implicitDependencies(),
+ bindingPackage(),
+ hasNonDefaultTypeParameters(),
+ bindingElement(),
+ injectionSites(),
+ Optional.<DependencyRequest>absent());
+ }
+
+ @AutoValue
+ abstract static class InjectionSite {
+ enum Kind {
+ FIELD,
+ METHOD,
+ }
+
+ abstract Kind kind();
+
+ abstract Element element();
+
+ abstract ImmutableSet<DependencyRequest> dependencies();
+
+ protected int indexAmongSiblingMembers(InjectionSite injectionSite) {
+ return injectionSite
+ .element()
+ .getEnclosingElement()
+ .getEnclosedElements()
+ .indexOf(injectionSite.element());
+ }
+ }
+
+ static final class Factory {
+ private final Elements elements;
+ private final Types types;
+ private final Key.Factory keyFactory;
+ private final DependencyRequest.Factory dependencyRequestFactory;
+
+ Factory(Elements elements, Types types, Key.Factory keyFactory,
+ DependencyRequest.Factory dependencyRequestFactory) {
+ this.elements = checkNotNull(elements);
+ this.types = checkNotNull(types);
+ this.keyFactory = checkNotNull(keyFactory);
+ this.dependencyRequestFactory = checkNotNull(dependencyRequestFactory);
+ }
+
+ private InjectionSite injectionSiteForInjectMethod(
+ ExecutableElement methodElement, DeclaredType containingType) {
+ checkNotNull(methodElement);
+ checkArgument(methodElement.getKind().equals(ElementKind.METHOD));
+ ExecutableType resolved =
+ MoreTypes.asExecutable(types.asMemberOf(containingType, methodElement));
+ return new AutoValue_MembersInjectionBinding_InjectionSite(
+ InjectionSite.Kind.METHOD,
+ methodElement,
+ dependencyRequestFactory.forRequiredResolvedVariables(
+ containingType, methodElement.getParameters(), resolved.getParameterTypes()));
+ }
+
+ private InjectionSite injectionSiteForInjectField(
+ VariableElement fieldElement, DeclaredType containingType) {
+ checkNotNull(fieldElement);
+ checkArgument(fieldElement.getKind().equals(ElementKind.FIELD));
+ checkArgument(isAnnotationPresent(fieldElement, Inject.class));
+ TypeMirror resolved = types.asMemberOf(containingType, fieldElement);
+ return new AutoValue_MembersInjectionBinding_InjectionSite(
+ InjectionSite.Kind.FIELD,
+ fieldElement,
+ ImmutableSet.of(
+ dependencyRequestFactory.forRequiredResolvedVariable(
+ containingType, fieldElement, resolved)));
+ }
+
+ /** Returns an unresolved version of this binding. */
+ MembersInjectionBinding unresolve(MembersInjectionBinding binding) {
+ checkState(binding.hasNonDefaultTypeParameters());
+ DeclaredType unresolved = MoreTypes.asDeclared(binding.bindingElement().asType());
+ return forInjectedType(unresolved, Optional.<TypeMirror>absent());
+ }
+
+ /** Returns true if the type has some injected members in itself or any of its super classes. */
+ boolean hasInjectedMembers(DeclaredType declaredType) {
+ return !getInjectionSites(declaredType).isEmpty();
+ }
+
+ /**
+ * Returns a MembersInjectionBinding for the given type. If {@code resolvedType} is present,
+ * this will return a resolved binding, with the key & type resolved to the given type (using
+ * {@link Types#asMemberOf(DeclaredType, Element)}).
+ */
+ MembersInjectionBinding forInjectedType(
+ DeclaredType declaredType, Optional<TypeMirror> resolvedType) {
+ // If the class this is injecting has some type arguments, resolve everything.
+ if (!declaredType.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(declaredType)),
+ "erased expected type: %s, erased actual type: %s",
+ types.erasure(resolved),
+ types.erasure(declaredType));
+ declaredType = resolved;
+ }
+ ImmutableSortedSet<InjectionSite> injectionSites = getInjectionSites(declaredType);
+ ImmutableSet<DependencyRequest> dependencies =
+ FluentIterable.from(injectionSites)
+ .transformAndConcat(
+ new Function<InjectionSite, Set<DependencyRequest>>() {
+ @Override
+ public Set<DependencyRequest> apply(InjectionSite input) {
+ return input.dependencies();
+ }
+ })
+ .toSet();
+
+ Optional<DependencyRequest> parentInjectorRequest =
+ MoreTypes.nonObjectSuperclass(types, elements, declaredType)
+ .transform(
+ new Function<DeclaredType, DependencyRequest>() {
+ @Override
+ public DependencyRequest apply(DeclaredType input) {
+ return dependencyRequestFactory.forMembersInjectedType(input);
+ }
+ });
+
+ Key key = keyFactory.forMembersInjectedType(declaredType);
+ TypeElement typeElement = MoreElements.asType(declaredType.asElement());
+ return new AutoValue_MembersInjectionBinding(
+ key,
+ dependencies,
+ dependencies,
+ findBindingPackage(key),
+ hasNonDefaultTypeParameters(typeElement, key.type(), types),
+ typeElement,
+ injectionSites,
+ parentInjectorRequest);
+ }
+
+ private ImmutableSortedSet<InjectionSite> getInjectionSites(DeclaredType declaredType) {
+ Set<InjectionSite> injectionSites = new HashSet<>();
+ final List<TypeElement> ancestors = new ArrayList<>();
+ SetMultimap<String, ExecutableElement> overriddenMethodMap = LinkedHashMultimap.create();
+ for (Optional<DeclaredType> currentType = Optional.of(declaredType);
+ currentType.isPresent();
+ currentType = MoreTypes.nonObjectSuperclass(types, elements, currentType.get())) {
+ final DeclaredType type = currentType.get();
+ ancestors.add(MoreElements.asType(type.asElement()));
+ for (Element enclosedElement : type.asElement().getEnclosedElements()) {
+ Optional<InjectionSite> maybeInjectionSite =
+ injectionSiteVisitor.visit(enclosedElement, type);
+ if (maybeInjectionSite.isPresent()) {
+ InjectionSite injectionSite = maybeInjectionSite.get();
+ if (shouldBeInjected(injectionSite.element(), overriddenMethodMap)) {
+ injectionSites.add(injectionSite);
+ }
+ if (injectionSite.kind() == InjectionSite.Kind.METHOD) {
+ ExecutableElement injectionSiteMethod =
+ MoreElements.asExecutable(injectionSite.element());
+ overriddenMethodMap.put(
+ injectionSiteMethod.getSimpleName().toString(), injectionSiteMethod);
+ }
+ }
+ }
+ }
+ return ImmutableSortedSet.copyOf(
+ new Comparator<InjectionSite>() {
+ @Override
+ public int compare(InjectionSite left, InjectionSite right) {
+ return ComparisonChain.start()
+ // supertypes before subtypes
+ .compare(
+ ancestors.indexOf(right.element().getEnclosingElement()),
+ ancestors.indexOf(left.element().getEnclosingElement()))
+ // fields before methods
+ .compare(left.element().getKind(), right.element().getKind())
+ // then sort by whichever element comes first in the parent
+ // this isn't necessary, but makes the processor nice and predictable
+ .compare(
+ left.indexAmongSiblingMembers(left), right.indexAmongSiblingMembers(right))
+ .result();
+ }
+ },
+ injectionSites);
+ }
+
+ private boolean shouldBeInjected(
+ Element injectionSite, SetMultimap<String, ExecutableElement> overriddenMethodMap) {
+ if (!isAnnotationPresent(injectionSite, Inject.class)
+ || injectionSite.getModifiers().contains(PRIVATE)
+ || injectionSite.getModifiers().contains(STATIC)) {
+ return false;
+ }
+
+ if (injectionSite.getKind().isField()) { // Inject all fields (self and ancestors)
+ return true;
+ }
+
+ // For each method with the same name belonging to any descendant class, return false if any
+ // method has already overridden the injectionSite method. To decrease the number of methods
+ // that are checked, we store the already injected methods in a SetMultimap and only
+ // check the methods with the same name.
+ ExecutableElement injectionSiteMethod = MoreElements.asExecutable(injectionSite);
+ TypeElement injectionSiteType = MoreElements.asType(injectionSite.getEnclosingElement());
+ for (ExecutableElement method :
+ overriddenMethodMap.get(injectionSiteMethod.getSimpleName().toString())) {
+ if (elements.overrides(method, injectionSiteMethod, injectionSiteType)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private final ElementVisitor<Optional<InjectionSite>, DeclaredType> injectionSiteVisitor =
+ new ElementKindVisitor6<Optional<InjectionSite>, DeclaredType>(
+ Optional.<InjectionSite>absent()) {
+ @Override
+ public Optional<InjectionSite> visitExecutableAsMethod(
+ ExecutableElement e, DeclaredType type) {
+ return Optional.of(injectionSiteForInjectMethod(e, type));
+ }
+
+ @Override
+ public Optional<InjectionSite> visitVariableAsField(
+ VariableElement e, DeclaredType type) {
+ return (isAnnotationPresent(e, Inject.class)
+ && !e.getModifiers().contains(PRIVATE)
+ && !e.getModifiers().contains(STATIC))
+ ? Optional.of(injectionSiteForInjectField(e, type))
+ : Optional.<InjectionSite>absent();
+ }
+ };
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MembersInjectorGenerator.java b/compiler/src/main/java/dagger/internal/codegen/MembersInjectorGenerator.java
new file mode 100644
index 000000000..f7fcdee9d
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MembersInjectorGenerator.java
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import dagger.MembersInjector;
+import dagger.internal.codegen.MembersInjectionBinding.InjectionSite;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ClassWriter;
+import dagger.internal.codegen.writer.ConstructorWriter;
+import dagger.internal.codegen.writer.FieldWriter;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.MethodWriter;
+import dagger.internal.codegen.writer.Modifiable;
+import dagger.internal.codegen.writer.ParameterizedTypeName;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import dagger.internal.codegen.writer.TypeVariableName;
+import dagger.internal.codegen.writer.VariableWriter;
+import dagger.internal.codegen.writer.VoidName;
+import dagger.producers.Producer;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.annotation.processing.Filer;
+import javax.inject.Provider;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeVisitor;
+import javax.lang.model.util.SimpleTypeVisitor7;
+
+import static com.google.auto.common.MoreElements.getPackage;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.SourceFiles.frameworkTypeUsageStatement;
+import static dagger.internal.codegen.SourceFiles.membersInjectorNameForType;
+import static dagger.internal.codegen.SourceFiles.parameterizedMembersInjectorNameForMembersInjectionBinding;
+import static dagger.internal.codegen.writer.Snippet.makeParametersSnippet;
+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;
+
+/**
+ * Generates {@link MembersInjector} implementations from {@link MembersInjectionBinding} instances.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class MembersInjectorGenerator extends SourceFileGenerator<MembersInjectionBinding> {
+ private final DependencyRequestMapper dependencyRequestMapper;
+
+ MembersInjectorGenerator(
+ Filer filer,
+ DependencyRequestMapper dependencyRequestMapper) {
+ super(filer);
+ this.dependencyRequestMapper = dependencyRequestMapper;
+ }
+
+ @Override
+ ClassName nameGeneratedType(MembersInjectionBinding binding) {
+ return membersInjectorNameForType(binding.bindingElement());
+ }
+
+ @Override
+ Iterable<? extends Element> getOriginatingElements(
+ MembersInjectionBinding binding) {
+ return FluentIterable.from(binding.injectionSites())
+ .transform(new Function<InjectionSite, Element>() {
+ @Override public Element apply(InjectionSite injectionSite) {
+ return injectionSite.element();
+ }
+ })
+ .toSet();
+ }
+
+ @Override
+ Optional<? extends Element> getElementForErrorReporting(MembersInjectionBinding binding) {
+ return Optional.of(binding.bindingElement());
+ }
+
+ @Override
+ ImmutableSet<JavaWriter> write(ClassName generatedTypeName, MembersInjectionBinding binding) {
+ Set<String> delegateMethods = new HashSet<>();
+
+ // We don't want to write out resolved bindings -- we want to write out the generic version.
+ checkState(!binding.hasNonDefaultTypeParameters());
+
+ TypeName injectedTypeName = TypeNames.forTypeMirror(binding.key().type());
+ JavaWriter writer = JavaWriter.inPackage(generatedTypeName.packageName());
+
+ ClassWriter injectorWriter = writer.addClass(generatedTypeName.simpleName());
+ List<TypeVariableName> typeParameters = Lists.newArrayList();
+ for (TypeParameterElement typeParameter : binding.bindingTypeElement().getTypeParameters()) {
+ typeParameters.add(TypeVariableName.fromTypeParameterElement(typeParameter));
+ }
+ injectorWriter.addTypeParameters(typeParameters);
+ injectorWriter.annotate(Generated.class)
+ .setValue(ComponentProcessor.class.getCanonicalName());
+ injectorWriter.addModifiers(PUBLIC, FINAL);
+ TypeName implementedType =
+ ParameterizedTypeName.create(MembersInjector.class, injectedTypeName);
+ injectorWriter.addImplementedType(implementedType);
+
+ ConstructorWriter constructorWriter = injectorWriter.addConstructor();
+ constructorWriter.addModifiers(PUBLIC);
+ MethodWriter injectMembersWriter = injectorWriter.addMethod(VoidName.VOID, "injectMembers");
+ injectMembersWriter.addModifiers(PUBLIC);
+ injectMembersWriter.annotate(Override.class);
+ injectMembersWriter.addParameter(injectedTypeName, "instance");
+ injectMembersWriter.body().addSnippet(Joiner.on('\n').join(
+ "if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ "}"));
+
+ ImmutableMap<BindingKey, FrameworkField> fields =
+ SourceFiles.generateBindingFieldsForDependencies(
+ dependencyRequestMapper, ImmutableSet.copyOf(binding.dependencies()));
+
+ ImmutableMap.Builder<BindingKey, FieldWriter> dependencyFieldsBuilder =
+ ImmutableMap.builder();
+
+ // We use a static create method so that generated components can avoid having
+ // to refer to the generic types of the factory.
+ // (Otherwise they may have visibility problems referring to the types.)
+ MethodWriter createMethodWriter = injectorWriter.addMethod(implementedType, "create");
+ createMethodWriter.addTypeParameters(typeParameters);
+ createMethodWriter.addModifiers(Modifier.PUBLIC, Modifier.STATIC);
+
+ boolean usesRawFrameworkTypes = false;
+ for (Entry<BindingKey, FrameworkField> fieldEntry : fields.entrySet()) {
+ BindingKey bindingKey = fieldEntry.getKey();
+ FrameworkField bindingField = fieldEntry.getValue();
+
+ // If the dependency type is not visible to this members injector, then use the raw framework
+ // type for the field.
+ boolean useRawFrameworkType =
+ !VISIBLE_TO_MEMBERS_INJECTOR.visit(bindingKey.key().type(), binding);
+
+ FieldWriter field =
+ injectorWriter.addField(
+ useRawFrameworkType
+ ? bindingField.frameworkType().type()
+ : bindingField.frameworkType(),
+ bindingField.name());
+
+ field.addModifiers(PRIVATE, FINAL);
+ VariableWriter constructorParameter =
+ constructorWriter.addParameter(field.type(), field.name());
+ VariableWriter createMethodParameter =
+ createMethodWriter.addParameter(constructorParameter.type(), constructorParameter.name());
+
+ // If we're using the raw type for the field, then suppress the injectMembers method's
+ // unchecked-type warning and the field's and the constructor and create-method's
+ // parameters' raw-type warnings.
+ if (useRawFrameworkType) {
+ usesRawFrameworkTypes = true;
+ suppressRawTypesWarning(field);
+ suppressRawTypesWarning(constructorParameter);
+ suppressRawTypesWarning(createMethodParameter);
+ }
+
+ constructorWriter.body().addSnippet("assert %s != null;", field.name());
+ constructorWriter.body().addSnippet("this.%1$s = %1$s;", field.name());
+ dependencyFieldsBuilder.put(bindingKey, field);
+ }
+
+ createMethodWriter
+ .body()
+ .addSnippet(
+ " return new %s(%s);",
+ parameterizedMembersInjectorNameForMembersInjectionBinding(binding),
+ Joiner.on(", ").join(constructorWriter.parameters().keySet()));
+
+ ImmutableMap<BindingKey, FieldWriter> dependencyFields = dependencyFieldsBuilder.build();
+ for (InjectionSite injectionSite : binding.injectionSites()) {
+ injectMembersWriter
+ .body()
+ .addSnippet(
+ visibleToMembersInjector(binding, injectionSite.element())
+ ? directInjectMemberSnippet(binding, dependencyFields, injectionSite)
+ : delegateInjectMemberSnippet(dependencyFields, injectionSite));
+ if (!injectionSite.element().getModifiers().contains(PUBLIC)
+ && injectionSite.element().getEnclosingElement().equals(binding.bindingElement())
+ && delegateMethods.add(injectionSiteDelegateMethodName(injectionSite.element()))) {
+ writeInjectorMethodForSubclasses(
+ injectorWriter,
+ dependencyFields,
+ typeParameters,
+ injectedTypeName,
+ injectionSite.element(),
+ injectionSite.dependencies());
+ }
+ }
+
+ if (usesRawFrameworkTypes) {
+ injectMembersWriter.annotate(SuppressWarnings.class).setValue("unchecked");
+ }
+
+ return ImmutableSet.of(writer);
+ }
+
+ /**
+ * Returns {@code true} if {@code element} is visible to the members injector for {@code binding}.
+ */
+ // TODO(dpb,gak): Make sure that all cases are covered here. E.g., what if element is public but
+ // enclosed in a package-private element?
+ private static boolean visibleToMembersInjector(
+ MembersInjectionBinding binding, Element element) {
+ return getPackage(element).equals(getPackage(binding.bindingElement()))
+ || element.getModifiers().contains(PUBLIC);
+ }
+
+ /**
+ * Returns a snippet that directly injects the instance's field or method.
+ */
+ private Snippet directInjectMemberSnippet(
+ MembersInjectionBinding binding,
+ ImmutableMap<BindingKey, FieldWriter> dependencyFields,
+ InjectionSite injectionSite) {
+ return Snippet.format(
+ injectionSite.element().getKind().isField() ? "%s.%s = %s;" : "%s.%s(%s);",
+ getInstanceSnippetWithPotentialCast(
+ injectionSite.element().getEnclosingElement(), binding.bindingElement()),
+ injectionSite.element().getSimpleName(),
+ makeParametersSnippet(
+ parameterSnippets(dependencyFields, injectionSite.dependencies(), true)));
+ }
+
+ /**
+ * Returns a snippet that injects the instance's field or method by calling a static method on the
+ * parent members injector class.
+ */
+ private Snippet delegateInjectMemberSnippet(
+ ImmutableMap<BindingKey, FieldWriter> dependencyFields, InjectionSite injectionSite) {
+ return Snippet.format(
+ "%s.%s(%s);",
+ membersInjectorNameForType(
+ MoreElements.asType(injectionSite.element().getEnclosingElement())),
+ injectionSiteDelegateMethodName(injectionSite.element()),
+ makeParametersSnippet(
+ new ImmutableList.Builder<Snippet>()
+ .add(Snippet.format("instance"))
+ .addAll(parameterSnippets(dependencyFields, injectionSite.dependencies(), false))
+ .build()));
+ }
+
+ /**
+ * Returns the parameters for injecting a member.
+ *
+ * @param passValue if {@code true}, each parameter snippet will be the result of converting the
+ * field from the framework type ({@link Provider}, {@link Producer}, etc.) to the real value;
+ * if {@code false}, each parameter snippet will be just the field
+ */
+ private ImmutableList<Snippet> parameterSnippets(
+ ImmutableMap<BindingKey, FieldWriter> dependencyFields,
+ ImmutableSet<DependencyRequest> dependencies,
+ boolean passValue) {
+ ImmutableList.Builder<Snippet> parameters = ImmutableList.builder();
+ for (DependencyRequest dependency : dependencies) {
+ Snippet fieldSnippet =
+ Snippet.format("%s", dependencyFields.get(dependency.bindingKey()).name());
+ parameters.add(
+ passValue ? frameworkTypeUsageStatement(fieldSnippet, dependency.kind()) : fieldSnippet);
+ }
+ return parameters.build();
+ }
+
+ private Snippet getInstanceSnippetWithPotentialCast(
+ Element injectionSiteElement, Element bindingElement) {
+ return (injectionSiteElement.equals(bindingElement))
+ ? Snippet.format("instance")
+ : Snippet.format("((%s)instance)", injectionSiteElement);
+ }
+
+ private String injectionSiteDelegateMethodName(Element injectionSiteElement) {
+ return "inject"
+ + CaseFormat.LOWER_CAMEL.to(
+ CaseFormat.UPPER_CAMEL, injectionSiteElement.getSimpleName().toString());
+ }
+
+ private void writeInjectorMethodForSubclasses(
+ ClassWriter injectorWriter,
+ ImmutableMap<BindingKey, FieldWriter> dependencyFields,
+ List<TypeVariableName> typeParameters,
+ TypeName injectedTypeName,
+ Element injectionElement,
+ ImmutableSet<DependencyRequest> dependencies) {
+ MethodWriter methodWriter =
+ injectorWriter.addMethod(VoidName.VOID, injectionSiteDelegateMethodName(injectionElement));
+ methodWriter.addModifiers(PUBLIC, STATIC);
+ methodWriter.addParameter(injectedTypeName, "instance");
+ methodWriter.addTypeParameters(typeParameters);
+ ImmutableList.Builder<Snippet> providedParameters = ImmutableList.builder();
+ Set<String> parameterNames = new HashSet<>();
+ for (DependencyRequest dependency : dependencies) {
+ FieldWriter field = dependencyFields.get(dependency.bindingKey());
+ VariableWriter parameter =
+ methodWriter.addParameter(
+ field.type(),
+ staticInjectMethodDependencyParameterName(parameterNames, dependency, field));
+ providedParameters.add(
+ frameworkTypeUsageStatement(Snippet.format("%s", parameter.name()), dependency.kind()));
+ }
+ if (injectionElement.getKind().isField()) {
+ methodWriter
+ .body()
+ .addSnippet(
+ "instance.%s = %s;",
+ injectionElement.getSimpleName(),
+ getOnlyElement(providedParameters.build()));
+ } else {
+ methodWriter
+ .body()
+ .addSnippet(
+ "instance.%s(%s);",
+ injectionElement.getSimpleName(),
+ makeParametersSnippet(providedParameters.build()));
+ }
+ }
+
+ /**
+ * Returns the static inject method parameter name for a dependency.
+ *
+ * @param parameterNames the parameter names used so far
+ * @param dependency the dependency
+ * @param field the field used to hold the framework type for the dependency
+ */
+ private String staticInjectMethodDependencyParameterName(
+ Set<String> parameterNames, DependencyRequest dependency, FieldWriter field) {
+ StringBuilder parameterName =
+ new StringBuilder(dependency.requestElement().getSimpleName().toString());
+ switch (dependency.kind()) {
+ case LAZY:
+ case INSTANCE:
+ case FUTURE:
+ String suffix = ((ParameterizedTypeName) field.type()).type().simpleName();
+ if (parameterName.length() <= suffix.length()
+ || !parameterName.substring(parameterName.length() - suffix.length()).equals(suffix)) {
+ parameterName.append(suffix);
+ }
+ break;
+
+ default:
+ break;
+ }
+ int baseLength = parameterName.length();
+ for (int i = 2; !parameterNames.add(parameterName.toString()); i++) {
+ parameterName.replace(baseLength, parameterName.length(), String.valueOf(i));
+ }
+ return parameterName.toString();
+ }
+
+ private void suppressRawTypesWarning(Modifiable modifiable) {
+ modifiable.annotate(SuppressWarnings.class).setValue("rawtypes");
+ }
+
+ private static final TypeVisitor<Boolean, MembersInjectionBinding> VISIBLE_TO_MEMBERS_INJECTOR =
+ new SimpleTypeVisitor7<Boolean, MembersInjectionBinding>(true) {
+ @Override
+ public Boolean visitArray(ArrayType t, MembersInjectionBinding p) {
+ return visit(t.getComponentType(), p);
+ }
+
+ @Override
+ public Boolean visitDeclared(DeclaredType t, MembersInjectionBinding p) {
+ return visibleToMembersInjector(p, t.asElement());
+ }
+ };
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MethodSignature.java b/compiler/src/main/java/dagger/internal/codegen/MethodSignature.java
new file mode 100644
index 000000000..447ed24ef
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MethodSignature.java
@@ -0,0 +1,33 @@
+package dagger.internal.codegen;
+
+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 javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+@AutoValue
+abstract class MethodSignature {
+ abstract String name();
+ abstract ImmutableList<Equivalence.Wrapper<TypeMirror>> parameterTypes();
+ abstract ImmutableList<Equivalence.Wrapper<TypeMirror>> thrownTypes();
+
+ static MethodSignature fromExecutableType(String methodName, ExecutableType methodType) {
+ checkNotNull(methodType);
+ ImmutableList.Builder<Equivalence.Wrapper<TypeMirror>> parameters = ImmutableList.builder();
+ ImmutableList.Builder<Equivalence.Wrapper<TypeMirror>> thrownTypes = ImmutableList.builder();
+ for (TypeMirror parameter : methodType.getParameterTypes()) {
+ parameters.add(MoreTypes.equivalence().wrap(parameter));
+ }
+ for (TypeMirror thrownType : methodType.getThrownTypes()) {
+ thrownTypes.add(MoreTypes.equivalence().wrap(thrownType));
+ }
+ return new AutoValue_MethodSignature(
+ methodName,
+ parameters.build(),
+ thrownTypes.build());
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MethodSignatureFormatter.java b/compiler/src/main/java/dagger/internal/codegen/MethodSignatureFormatter.java
new file mode 100644
index 000000000..078977e16
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MethodSignatureFormatter.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Optional;
+import java.util.Iterator;
+import java.util.List;
+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.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Types;
+
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.ErrorMessages.stripCommonTypePrefixes;
+
+/**
+ * Formats the signature of an {@link ExecutableElement} suitable for use in error messages.
+ *
+ * @author Christian Gruber
+ * @since 2.0
+ */
+final class MethodSignatureFormatter extends Formatter<ExecutableElement> {
+ private final Types types;
+
+ MethodSignatureFormatter(Types types) {
+ this.types = types;
+ }
+
+ @Override public String format(ExecutableElement method) {
+ return format(method, Optional.<DeclaredType>absent());
+ }
+
+ /**
+ * Formats an ExecutableElement as if it were contained within the container, if the container is
+ * present.
+ */
+ public String format(ExecutableElement method, Optional<DeclaredType> container) {
+ StringBuilder builder = new StringBuilder();
+ 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());
+ }
+
+ // TODO(cgruber): AnnotationMirror formatter.
+ List<? extends AnnotationMirror> annotations = method.getAnnotationMirrors();
+ if (!annotations.isEmpty()) {
+ Iterator<? extends AnnotationMirror> annotationIterator = annotations.iterator();
+ for (int i = 0; annotationIterator.hasNext(); i++) {
+ if (i > 0) {
+ builder.append(' ');
+ }
+ builder.append(ErrorMessages.format(annotationIterator.next()));
+ }
+ builder.append(' ');
+ }
+ builder.append(nameOfType(executableType.getReturnType()));
+ builder.append(' ');
+ builder.append(type.getQualifiedName());
+ builder.append('.');
+ builder.append(method.getSimpleName());
+ builder.append('(');
+ checkState(method.getParameters().size() == executableType.getParameterTypes().size());
+ Iterator<? extends VariableElement> parameters = method.getParameters().iterator();
+ Iterator<? extends TypeMirror> parameterTypes = executableType.getParameterTypes().iterator();
+ for (int i = 0; parameters.hasNext(); i++) {
+ if (i > 0) {
+ builder.append(", ");
+ }
+ appendParameter(builder, parameters.next(), parameterTypes.next());
+ }
+ builder.append(')');
+ return builder.toString();
+ }
+
+ private static void appendParameter(StringBuilder builder, VariableElement parameter,
+ TypeMirror type) {
+ Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(parameter);
+ if (qualifier.isPresent()) {
+ builder.append(ErrorMessages.format(qualifier.get())).append(' ');
+ }
+ builder.append(nameOfType(type));
+ }
+
+ private static String nameOfType(TypeMirror type) {
+ if (type.getKind().isPrimitive()) {
+ return MoreTypes.asPrimitiveType(type).toString();
+ } else if (type.getKind() == TypeKind.VOID) {
+ return "void";
+ } else {
+ return stripCommonTypePrefixes(MoreTypes.asDeclared(type).toString());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MissingBindingSuggestions.java b/compiler/src/main/java/dagger/internal/codegen/MissingBindingSuggestions.java
new file mode 100644
index 000000000..dcabab52d
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MissingBindingSuggestions.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+/**
+ * Utility code that looks for bindings matching a key in all subcomponents in a binding graph so
+ * that a user is advised that a binding exists elsewhere when it is not found in the current
+ * subgraph. If a binding matching a key exists in a sub- or sibling component, that is often what
+ * the user actually wants to use.
+ */
+class MissingBindingSuggestions {
+ /**
+ * Searches the entire binding graph from the top-level graph for a binding matching
+ * {@code key}.
+ */
+ static ImmutableList<String> forKey(BindingGraph topLevelGraph, BindingKey key) {
+ ImmutableList.Builder<String> resolutions = new ImmutableList.Builder<>();
+ Deque<BindingGraph> graphsToTry = new ArrayDeque<>();
+
+ graphsToTry.add(topLevelGraph);
+ do {
+ BindingGraph graph = graphsToTry.removeLast();
+ ResolvedBindings bindings = graph.resolvedBindings().get(key);
+ if ((bindings == null) || bindings.bindings().isEmpty()) {
+ graphsToTry.addAll(graph.subgraphs().values());
+ } else {
+ resolutions.add("A binding with matching key exists in component: "
+ + graph.componentDescriptor().componentDefinitionType().getQualifiedName());
+ }
+ } while (!graphsToTry.isEmpty());
+
+ return resolutions.build();
+ }
+
+ private MissingBindingSuggestions() {}
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ModuleDescriptor.java b/compiler/src/main/java/dagger/internal/codegen/ModuleDescriptor.java
new file mode 100644
index 000000000..f5e33b59d
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ModuleDescriptor.java
@@ -0,0 +1,122 @@
+package dagger.internal.codegen;
+
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import dagger.Module;
+import dagger.Provides;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Verify.verify;
+import static dagger.internal.codegen.ConfigurationAnnotations.getModuleIncludes;
+import static dagger.internal.codegen.Util.componentCanMakeNewInstances;
+import static javax.lang.model.type.TypeKind.DECLARED;
+import static javax.lang.model.type.TypeKind.NONE;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+@AutoValue
+abstract class ModuleDescriptor {
+ static final Function<ModuleDescriptor, TypeElement> getModuleElement() {
+ return new Function<ModuleDescriptor, TypeElement>() {
+ @Override public TypeElement apply(ModuleDescriptor input) {
+ return input.moduleElement();
+ }
+ };
+ }
+
+ abstract AnnotationMirror moduleAnnotation();
+
+ abstract TypeElement moduleElement();
+
+ abstract ImmutableSet<ModuleDescriptor> includedModules();
+
+ abstract ImmutableSet<? extends ContributionBinding> bindings();
+
+ enum DefaultCreationStrategy {
+ PASSED,
+ CONSTRUCTED,
+ }
+
+ abstract DefaultCreationStrategy defaultCreationStrategy();
+
+ static final class Factory {
+ private final Elements elements;
+ private final ProvisionBinding.Factory provisionBindingFactory;
+ private final ProductionBinding.Factory productionBindingFactory;
+
+ Factory(
+ Elements elements,
+ ProvisionBinding.Factory provisionBindingFactory,
+ ProductionBinding.Factory productionBindingFactory) {
+ this.elements = elements;
+ this.provisionBindingFactory = provisionBindingFactory;
+ this.productionBindingFactory = productionBindingFactory;
+ }
+
+ ModuleDescriptor create(TypeElement moduleElement) {
+ AnnotationMirror moduleAnnotation = getModuleAnnotation(moduleElement).get();
+
+ ImmutableSet.Builder<ContributionBinding> bindings = ImmutableSet.builder();
+ for (ExecutableElement moduleMethod : methodsIn(elements.getAllMembers(moduleElement))) {
+ if (isAnnotationPresent(moduleMethod, Provides.class)) {
+ bindings.add(
+ provisionBindingFactory.forProvidesMethod(moduleMethod, moduleElement.asType()));
+ }
+ if (isAnnotationPresent(moduleMethod, Produces.class)) {
+ bindings.add(
+ productionBindingFactory.forProducesMethod(moduleMethod, moduleElement.asType()));
+ }
+ }
+
+ DefaultCreationStrategy defaultCreationStrategy =
+ (componentCanMakeNewInstances(moduleElement)
+ && moduleElement.getTypeParameters().isEmpty())
+ ? ModuleDescriptor.DefaultCreationStrategy.CONSTRUCTED
+ : ModuleDescriptor.DefaultCreationStrategy.PASSED;
+
+ return new AutoValue_ModuleDescriptor(
+ moduleAnnotation,
+ moduleElement,
+ ImmutableSet.copyOf(
+ collectIncludedModules(new LinkedHashSet<ModuleDescriptor>(), moduleElement)),
+ bindings.build(),
+ defaultCreationStrategy);
+ }
+
+ private static Optional<AnnotationMirror> getModuleAnnotation(TypeElement moduleElement) {
+ return getAnnotationMirror(moduleElement, Module.class)
+ .or(getAnnotationMirror(moduleElement, ProducerModule.class));
+ }
+
+ private Set<ModuleDescriptor> collectIncludedModules(
+ Set<ModuleDescriptor> 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);
+ }
+ }
+ Optional<AnnotationMirror> moduleAnnotation = getModuleAnnotation(moduleElement);
+ if (moduleAnnotation.isPresent()) {
+ for (TypeMirror moduleIncludesType : getModuleIncludes(moduleAnnotation.get())) {
+ includedModules.add(create(MoreTypes.asTypeElement(moduleIncludesType)));
+ }
+ }
+ return includedModules;
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ModuleProcessingStep.java b/compiler/src/main/java/dagger/internal/codegen/ModuleProcessingStep.java
new file mode 100644
index 000000000..1afda7d90
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ModuleProcessingStep.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.BasicAnnotationProcessor;
+import com.google.auto.common.MoreElements;
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import dagger.Module;
+import dagger.Provides;
+import java.lang.annotation.Annotation;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static javax.lang.model.element.ElementKind.METHOD;
+
+/**
+ * An annotation processor for generating Dagger implementation code based on the {@link Module}
+ * (and {@link Provides}) annotation.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class ModuleProcessingStep implements BasicAnnotationProcessor.ProcessingStep {
+ private final Messager messager;
+ private final ModuleValidator moduleValidator;
+ private final ProvidesMethodValidator providesMethodValidator;
+ private final ProvisionBinding.Factory provisionBindingFactory;
+ private final FactoryGenerator factoryGenerator;
+ private final Set<Element> processedModuleElements = Sets.newLinkedHashSet();
+
+ ModuleProcessingStep(
+ Messager messager,
+ ModuleValidator moduleValidator,
+ ProvidesMethodValidator providesMethodValidator,
+ ProvisionBinding.Factory provisionBindingFactory,
+ FactoryGenerator factoryGenerator) {
+ this.messager = messager;
+ this.moduleValidator = moduleValidator;
+ this.providesMethodValidator = providesMethodValidator;
+ this.provisionBindingFactory = provisionBindingFactory;
+ this.factoryGenerator = factoryGenerator;
+ }
+
+ @Override
+ public Set<Class<? extends Annotation>> annotations() {
+ return ImmutableSet.of(Module.class, Provides.class);
+ }
+
+ @Override
+ public Set<Element> process(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ // first, check and collect all provides methods
+ ImmutableSet.Builder<ExecutableElement> validProvidesMethodsBuilder = ImmutableSet.builder();
+ for (Element providesElement : elementsByAnnotation.get(Provides.class)) {
+ if (providesElement.getKind().equals(METHOD)) {
+ ExecutableElement providesMethodElement = (ExecutableElement) providesElement;
+ ValidationReport<ExecutableElement> methodReport =
+ providesMethodValidator.validate(providesMethodElement);
+ methodReport.printMessagesTo(messager);
+ if (methodReport.isClean()) {
+ validProvidesMethodsBuilder.add(providesMethodElement);
+ }
+ }
+ }
+ ImmutableSet<ExecutableElement> validProvidesMethods = validProvidesMethodsBuilder.build();
+
+ // process each module
+ for (Element moduleElement :
+ Sets.difference(elementsByAnnotation.get(Module.class), processedModuleElements)) {
+ ValidationReport<TypeElement> report =
+ moduleValidator.validate(MoreElements.asType(moduleElement));
+ report.printMessagesTo(messager);
+
+ if (report.isClean()) {
+ ImmutableSet.Builder<ExecutableElement> moduleProvidesMethodsBuilder =
+ ImmutableSet.builder();
+ List<ExecutableElement> moduleMethods =
+ ElementFilter.methodsIn(moduleElement.getEnclosedElements());
+ for (ExecutableElement methodElement : moduleMethods) {
+ if (isAnnotationPresent(methodElement, Provides.class)) {
+ moduleProvidesMethodsBuilder.add(methodElement);
+ }
+ }
+ ImmutableSet<ExecutableElement> moduleProvidesMethods =
+ moduleProvidesMethodsBuilder.build();
+
+ if (Sets.difference(moduleProvidesMethods, validProvidesMethods).isEmpty()) {
+ // all of the provides methods in this module are valid!
+ // time to generate some factories!
+ ImmutableSet<ProvisionBinding> bindings = FluentIterable.from(moduleProvidesMethods)
+ .transform(new Function<ExecutableElement, ProvisionBinding>() {
+ @Override
+ public ProvisionBinding apply(ExecutableElement providesMethod) {
+ return provisionBindingFactory.forProvidesMethod(providesMethod,
+ providesMethod.getEnclosingElement().asType());
+ }
+ })
+ .toSet();
+
+ try {
+ for (ProvisionBinding binding : bindings) {
+ factoryGenerator.generate(binding);
+ }
+ } catch (SourceFileGenerationException e) {
+ e.printMessageTo(messager);
+ }
+ }
+ }
+ processedModuleElements.add(moduleElement);
+ }
+ return ImmutableSet.of();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ModuleValidator.java b/compiler/src/main/java/dagger/internal/codegen/ModuleValidator.java
new file mode 100644
index 000000000..8b0c9a217
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ModuleValidator.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.auto.common.Visibility;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Sets;
+import dagger.Module;
+import dagger.producers.ProducerModule;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import javax.lang.model.element.AnnotationMirror;
+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.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.Types;
+
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+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.collect.Iterables.any;
+import static dagger.internal.codegen.ConfigurationAnnotations.getModuleIncludes;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_SAME_NAME;
+import static dagger.internal.codegen.ErrorMessages.METHOD_OVERRIDES_PROVIDES_METHOD;
+import static dagger.internal.codegen.ErrorMessages.MODULES_WITH_TYPE_PARAMS_MUST_BE_ABSTRACT;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_METHOD_OVERRIDES_ANOTHER;
+import static dagger.internal.codegen.ErrorMessages.REFERENCED_MODULES_MUST_NOT_BE_ABSTRACT;
+import static dagger.internal.codegen.ErrorMessages.REFERENCED_MODULE_MUST_NOT_HAVE_TYPE_PARAMS;
+import static dagger.internal.codegen.ErrorMessages.REFERENCED_MODULE_NOT_ANNOTATED;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+
+/**
+ * A {@linkplain ValidationReport validator} for {@link Module}s or {@link ProducerModule}s.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class ModuleValidator {
+ private final Types types;
+ private final Elements elements;
+ private final Class<? extends Annotation> moduleClass;
+ private final ImmutableList<Class<? extends Annotation>> includedModuleClasses;
+ private final Class<? extends Annotation> methodClass;
+ private final MethodSignatureFormatter methodSignatureFormatter;
+
+ ModuleValidator(
+ Types types,
+ Elements elements,
+ MethodSignatureFormatter methodSignatureFormatter,
+ Class<? extends Annotation> moduleClass,
+ ImmutableList<Class<? extends Annotation>> includedModuleClasses,
+ Class<? extends Annotation> methodClass) {
+ this.types = types;
+ this.elements = elements;
+ this.moduleClass = moduleClass;
+ this.includedModuleClasses = includedModuleClasses;
+ this.methodClass = methodClass;
+ this.methodSignatureFormatter = methodSignatureFormatter;
+ }
+
+ ValidationReport<TypeElement> validate(final TypeElement subject) {
+ final ValidationReport.Builder<TypeElement> builder = ValidationReport.about(subject);
+
+ List<ExecutableElement> moduleMethods = ElementFilter.methodsIn(subject.getEnclosedElements());
+ ListMultimap<String, ExecutableElement> allMethodsByName = ArrayListMultimap.create();
+ ListMultimap<String, ExecutableElement> bindingMethodsByName = ArrayListMultimap.create();
+ for (ExecutableElement moduleMethod : moduleMethods) {
+ if (isAnnotationPresent(moduleMethod, methodClass)) {
+ bindingMethodsByName.put(moduleMethod.getSimpleName().toString(), moduleMethod);
+ }
+ allMethodsByName.put(moduleMethod.getSimpleName().toString(), moduleMethod);
+ }
+
+ validateModuleVisibility(subject, builder);
+ validateMethodsWithSameName(builder, bindingMethodsByName);
+ if (subject.getKind() != ElementKind.INTERFACE) {
+ validateProvidesOverrides(subject, builder, allMethodsByName, bindingMethodsByName);
+ }
+ validateModifiers(subject, builder);
+ validateReferencedModules(subject, builder);
+
+ // TODO(gak): port the dagger 1 module validation?
+ return builder.build();
+ }
+
+ private void validateModifiers(
+ TypeElement subject, ValidationReport.Builder<TypeElement> 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)) {
+ builder.addError(MODULES_WITH_TYPE_PARAMS_MUST_BE_ABSTRACT, subject);
+ }
+ }
+
+ private void validateMethodsWithSameName(
+ ValidationReport.Builder<TypeElement> builder,
+ ListMultimap<String, ExecutableElement> bindingMethodsByName) {
+ for (Entry<String, Collection<ExecutableElement>> entry :
+ bindingMethodsByName.asMap().entrySet()) {
+ if (entry.getValue().size() > 1) {
+ for (ExecutableElement offendingMethod : entry.getValue()) {
+ builder.addError(
+ String.format(BINDING_METHOD_WITH_SAME_NAME, methodClass.getSimpleName()),
+ offendingMethod);
+ }
+ }
+ }
+ }
+
+ private void validateReferencedModules(
+ TypeElement subject, ValidationReport.Builder<TypeElement> builder) {
+ // Validate that all the modules we include are valid for inclusion.
+ AnnotationMirror mirror = getAnnotationMirror(subject, moduleClass).get();
+ ImmutableList<TypeMirror> includedTypes = getModuleIncludes(mirror);
+ validateReferencedModules(subject, builder, includedTypes);
+ }
+
+ /**
+ * Used by {@link ModuleValidator} & {@link ComponentValidator} to validate referenced modules.
+ */
+ void validateReferencedModules(
+ final TypeElement subject,
+ final ValidationReport.Builder<TypeElement> builder,
+ ImmutableList<TypeMirror> includedTypes) {
+ for (TypeMirror includedType : includedTypes) {
+ includedType.accept(
+ new SimpleTypeVisitor6<Void, Void>() {
+ @Override
+ protected Void defaultAction(TypeMirror mirror, Void p) {
+ builder.addError(mirror + " is not a valid module type.", subject);
+ return null;
+ }
+
+ @Override
+ public Void visitDeclared(DeclaredType t, Void p) {
+ final TypeElement element = MoreElements.asType(t.asElement());
+ if (!t.getTypeArguments().isEmpty()) {
+ builder.addError(
+ String.format(
+ REFERENCED_MODULE_MUST_NOT_HAVE_TYPE_PARAMS, element.getQualifiedName()),
+ subject);
+ }
+ boolean isIncludedModule =
+ any(
+ includedModuleClasses,
+ new Predicate<Class<? extends Annotation>>() {
+ @Override
+ public boolean apply(Class<? extends Annotation> otherClass) {
+ return MoreElements.isAnnotationPresent(element, otherClass);
+ }
+ });
+ if (!isIncludedModule) {
+ builder.addError(
+ String.format(
+ REFERENCED_MODULE_NOT_ANNOTATED,
+ element.getQualifiedName(),
+ (includedModuleClasses.size() > 1 ? "one of " : "")
+ + Joiner.on(", ")
+ .join(
+ FluentIterable.from(includedModuleClasses)
+ .transform(
+ new Function<Class<? extends Annotation>, String>() {
+ @Override
+ public String apply(
+ Class<? extends Annotation> otherClass) {
+ return "@" + otherClass.getSimpleName();
+ }
+ }))),
+ subject);
+ }
+ if (element.getModifiers().contains(ABSTRACT)) {
+ builder.addError(
+ String.format(
+ REFERENCED_MODULES_MUST_NOT_BE_ABSTRACT, element.getQualifiedName()),
+ subject);
+ }
+ return null;
+ }
+ },
+ null);
+ }
+ }
+
+ private void validateProvidesOverrides(
+ TypeElement subject,
+ ValidationReport.Builder<TypeElement> builder,
+ ListMultimap<String, ExecutableElement> allMethodsByName,
+ ListMultimap<String, ExecutableElement> bindingMethodsByName) {
+ // For every @Provides method, confirm it overrides nothing *and* nothing overrides it.
+ // Consider the following hierarchy:
+ // class Parent {
+ // @Provides Foo a() {}
+ // @Provides Foo b() {}
+ // Foo c() {}
+ // }
+ // class Child extends Parent {
+ // @Provides Foo a() {}
+ // Foo b() {}
+ // @Provides Foo c() {}
+ // }
+ // In each of those cases, we want to fail. "a" is clear, "b" because Child is overriding
+ // a method marked @Provides in Parent, and "c" because Child is defining an @Provides
+ // method that overrides Parent.
+ TypeElement currentClass = subject;
+ TypeMirror objectType = elements.getTypeElement(Object.class.getCanonicalName()).asType();
+ // We keep track of methods that failed so we don't spam with multiple failures.
+ Set<ExecutableElement> failedMethods = Sets.newHashSet();
+ while (!types.isSameType(currentClass.getSuperclass(), objectType)) {
+ currentClass = MoreElements.asType(types.asElement(currentClass.getSuperclass()));
+ List<ExecutableElement> superclassMethods =
+ ElementFilter.methodsIn(currentClass.getEnclosedElements());
+ for (ExecutableElement superclassMethod : superclassMethods) {
+ String name = superclassMethod.getSimpleName().toString();
+ // For each method in the superclass, confirm our @Provides methods don't override it
+ for (ExecutableElement providesMethod : bindingMethodsByName.get(name)) {
+ if (!failedMethods.contains(providesMethod)
+ && elements.overrides(providesMethod, superclassMethod, subject)) {
+ failedMethods.add(providesMethod);
+ builder.addError(
+ String.format(
+ PROVIDES_METHOD_OVERRIDES_ANOTHER,
+ methodClass.getSimpleName(),
+ methodSignatureFormatter.format(superclassMethod)),
+ providesMethod);
+ }
+ }
+ // For each @Provides method in superclass, confirm our methods don't override it.
+ if (isAnnotationPresent(superclassMethod, methodClass)) {
+ for (ExecutableElement method : allMethodsByName.get(name)) {
+ if (!failedMethods.contains(method)
+ && elements.overrides(method, superclassMethod, subject)) {
+ failedMethods.add(method);
+ builder.addError(
+ String.format(
+ METHOD_OVERRIDES_PROVIDES_METHOD,
+ methodClass.getSimpleName(),
+ methodSignatureFormatter.format(superclassMethod)),
+ method);
+ }
+ }
+ }
+ allMethodsByName.put(superclassMethod.getSimpleName().toString(), superclassMethod);
+ }
+ }
+ }
+
+ private void validateModuleVisibility(final TypeElement moduleElement,
+ final ValidationReport.Builder<?> reportBuilder) {
+ Visibility moduleVisibility = Visibility.ofElement(moduleElement);
+ if (moduleVisibility.equals(PRIVATE)) {
+ reportBuilder.addError("Modules cannot be private.", moduleElement);
+ } else if (effectiveVisibilityOfElement(moduleElement).equals(PRIVATE)) {
+ 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 (moduleVisibility.equals(PUBLIC)) {
+ ImmutableSet<Element> nonPublicModules = FluentIterable.from(getModuleIncludes(
+ getAnnotationMirror(moduleElement, moduleClass).get()))
+ .transform(new Function<TypeMirror, Element>() {
+ @Override public Element apply(TypeMirror input) {
+ return types.asElement(input);
+ }
+ })
+ .filter(new Predicate<Element>() {
+ @Override public boolean apply(Element input) {
+ return effectiveVisibilityOfElement(input).compareTo(PUBLIC) < 0;
+ }
+ })
+ .toSet();
+ if (!nonPublicModules.isEmpty()) {
+ reportBuilder.addError(
+ String.format(
+ "This module is public, but it includes non-public "
+ + "(or effectively non-public) modules. "
+ + "Either reduce the visibility of this module or make %s public.",
+ formatListForErrorMessage(nonPublicModules.asList())),
+ moduleElement);
+ }
+ }
+ break;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private static String formatListForErrorMessage(List<?> things) {
+ switch (things.size()) {
+ case 0:
+ return "";
+ case 1:
+ return things.get(0).toString();
+ default:
+ StringBuilder output = new StringBuilder();
+ Joiner.on(", ").appendTo(output, things.subList(0, things.size() - 1));
+ output.append(" and ").append(things.get(things.size() - 1));
+ return output.toString();
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProducerFactoryGenerator.java b/compiler/src/main/java/dagger/internal/codegen/ProducerFactoryGenerator.java
new file mode 100644
index 000000000..9ae154886
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProducerFactoryGenerator.java
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreTypes;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+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.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.Provides.Type;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ClassWriter;
+import dagger.internal.codegen.writer.ConstructorWriter;
+import dagger.internal.codegen.writer.FieldWriter;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.MethodWriter;
+import dagger.internal.codegen.writer.ParameterizedTypeName;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import dagger.producers.Produces;
+import dagger.producers.internal.AbstractProducer;
+import dagger.producers.internal.Producers;
+import dagger.producers.monitoring.ProducerToken;
+import dagger.producers.monitoring.ProductionComponentMonitor;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+import javax.annotation.Nullable;
+import javax.annotation.processing.Filer;
+import javax.lang.model.element.Element;
+import javax.lang.model.type.TypeMirror;
+
+import static dagger.internal.codegen.SourceFiles.factoryNameForProductionBinding;
+import static dagger.internal.codegen.SourceFiles.frameworkTypeUsageStatement;
+import static dagger.internal.codegen.writer.Snippet.makeParametersSnippet;
+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;
+
+/**
+ * Generates {@link Producer} implementations from {@link ProductionBinding} instances.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+final class ProducerFactoryGenerator extends SourceFileGenerator<ProductionBinding> {
+ private final DependencyRequestMapper dependencyRequestMapper;
+
+ ProducerFactoryGenerator(Filer filer, DependencyRequestMapper dependencyRequestMapper) {
+ super(filer);
+ this.dependencyRequestMapper = dependencyRequestMapper;
+ }
+
+ @Override
+ ClassName nameGeneratedType(ProductionBinding binding) {
+ return factoryNameForProductionBinding(binding);
+ }
+
+ @Override
+ Iterable<? extends Element> getOriginatingElements(ProductionBinding binding) {
+ return ImmutableSet.of(binding.bindingElement());
+ }
+
+ @Override
+ Optional<? extends Element> getElementForErrorReporting(ProductionBinding binding) {
+ return Optional.of(binding.bindingElement());
+ }
+
+ @Override
+ ImmutableSet<JavaWriter> write(ClassName generatedTypeName, ProductionBinding binding) {
+ TypeMirror keyType = binding.productionType().equals(Type.MAP)
+ ? Util.getProvidedValueTypeOfMap(MoreTypes.asDeclared(binding.key().type()))
+ : binding.key().type();
+ TypeName providedTypeName = TypeNames.forTypeMirror(keyType);
+ TypeName futureTypeName = ParameterizedTypeName.create(
+ ClassName.fromClass(ListenableFuture.class), providedTypeName);
+ JavaWriter writer = JavaWriter.inPackage(generatedTypeName.packageName());
+
+ ClassWriter factoryWriter = writer.addClass(generatedTypeName.simpleName());
+ ConstructorWriter constructorWriter = factoryWriter.addConstructor();
+ constructorWriter.addModifiers(PUBLIC);
+
+ constructorWriter
+ .addParameter(ProductionComponentMonitor.class, "componentMonitor")
+ .annotate(Nullable.class);
+ constructorWriter
+ .body()
+ .addSnippet(
+ "super(%s.producerMonitorFor(componentMonitor, %s.create(%s.class)));",
+ ClassName.fromClass(Producers.class),
+ ClassName.fromClass(ProducerToken.class),
+ factoryWriter.name());
+
+ if (!binding.bindingElement().getModifiers().contains(STATIC)) {
+ factoryWriter.addField(binding.bindingTypeElement(), "module")
+ .addModifiers(PRIVATE, FINAL);
+ constructorWriter.addParameter(binding.bindingTypeElement(), "module");
+ constructorWriter.body()
+ .addSnippet("assert module != null;")
+ .addSnippet("this.module = module;");
+ }
+
+ factoryWriter.addField(Executor.class, "executor")
+ .addModifiers(PRIVATE, FINAL);
+ constructorWriter.addParameter(Executor.class, "executor");
+ constructorWriter.body()
+ .addSnippet("assert executor != null;")
+ .addSnippet("this.executor = executor;");
+
+ factoryWriter.annotate(Generated.class).setValue(ComponentProcessor.class.getName());
+ factoryWriter.addModifiers(PUBLIC);
+ factoryWriter.addModifiers(FINAL);
+ factoryWriter.setSuperclass(
+ ParameterizedTypeName.create(AbstractProducer.class, providedTypeName));
+
+ MethodWriter getMethodWriter = factoryWriter.addMethod(futureTypeName, "compute");
+ getMethodWriter.annotate(Override.class);
+ getMethodWriter.addModifiers(PROTECTED);
+
+ final ImmutableMap<BindingKey, FrameworkField> fields =
+ SourceFiles.generateBindingFieldsForDependencies(
+ dependencyRequestMapper, binding.dependencies());
+
+ for (FrameworkField bindingField : fields.values()) {
+ TypeName fieldType = bindingField.frameworkType();
+ FieldWriter field = factoryWriter.addField(fieldType, bindingField.name());
+ field.addModifiers(PRIVATE, FINAL);
+ constructorWriter.addParameter(field.type(), field.name());
+ constructorWriter.body()
+ .addSnippet("assert %s != null;", field.name())
+ .addSnippet("this.%1$s = %1$s;", field.name());
+ }
+
+ boolean returnsFuture = binding.bindingKind().equals(ProductionBinding.Kind.FUTURE_PRODUCTION);
+ ImmutableList<DependencyRequest> asyncDependencies = FluentIterable
+ .from(binding.dependencies())
+ .filter(new Predicate<DependencyRequest>() {
+ @Override public boolean apply(DependencyRequest dependency) {
+ return isAsyncDependency(dependency);
+ }
+ })
+ .toList();
+
+ for (DependencyRequest dependency : asyncDependencies) {
+ ParameterizedTypeName futureType = ParameterizedTypeName.create(
+ ClassName.fromClass(ListenableFuture.class),
+ asyncDependencyType(dependency));
+ String name = fields.get(dependency.bindingKey()).name();
+ Snippet futureAccess = Snippet.format("%s.get()", name);
+ getMethodWriter.body().addSnippet("%s %sFuture = %s;",
+ futureType,
+ name,
+ dependency.kind().equals(DependencyRequest.Kind.PRODUCED)
+ ? Snippet.format("%s.createFutureProduced(%s)",
+ ClassName.fromClass(Producers.class), futureAccess)
+ : futureAccess);
+ }
+
+ if (asyncDependencies.isEmpty()) {
+ ImmutableList.Builder<Snippet> parameterSnippets = ImmutableList.builder();
+ for (DependencyRequest dependency : binding.dependencies()) {
+ parameterSnippets.add(frameworkTypeUsageStatement(
+ Snippet.format(fields.get(dependency.bindingKey()).name()), dependency.kind()));
+ }
+ final boolean wrapWithFuture = false; // since submitToExecutor will create the future
+ Snippet invocationSnippet =
+ getInvocationSnippet(wrapWithFuture, binding, parameterSnippets.build());
+ TypeName callableReturnType = returnsFuture ? futureTypeName : providedTypeName;
+ Snippet throwsClause = getThrowsClause(binding.thrownTypes());
+ Snippet callableSnippet =
+ Snippet.format(
+ Joiner.on('\n')
+ .join(
+ "new %1$s<%2$s>() {",
+ " @Override public %2$s call() %3$s{",
+ " %4$s",
+ " }",
+ "}"),
+ ClassName.fromClass(Callable.class),
+ callableReturnType,
+ throwsClause,
+ invocationSnippet);
+ getMethodWriter
+ .body()
+ .addSnippet(
+ "%s future = %s.submitToExecutor(%s, executor);",
+ ParameterizedTypeName.create(
+ ClassName.fromClass(ListenableFuture.class), callableReturnType),
+ ClassName.fromClass(Producers.class),
+ callableSnippet);
+ getMethodWriter
+ .body()
+ .addSnippet(
+ "return %s;",
+ returnsFuture
+ ? Snippet.format("%s.dereference(future)", ClassName.fromClass(Futures.class))
+ : "future");
+ } else {
+ final Snippet futureSnippet;
+ final Snippet transformSnippet;
+ if (asyncDependencies.size() == 1) {
+ DependencyRequest asyncDependency = Iterables.getOnlyElement(asyncDependencies);
+ futureSnippet = Snippet.format("%s",
+ fields.get(asyncDependency.bindingKey()).name() + "Future");
+ String argName = asyncDependency.requestElement().getSimpleName().toString();
+ ImmutableList.Builder<Snippet> parameterSnippets = ImmutableList.builder();
+ for (DependencyRequest dependency : binding.dependencies()) {
+ // We really want to compare instances here, because asyncDependency is an element in the
+ // set binding.dependencies().
+ if (dependency == asyncDependency) {
+ parameterSnippets.add(Snippet.format("%s", argName));
+ } else {
+ parameterSnippets.add(frameworkTypeUsageStatement(
+ Snippet.format(fields.get(dependency.bindingKey()).name()),
+ dependency.kind()));
+ }
+ }
+ boolean wrapWithFuture = !returnsFuture; // only wrap if we don't already have a future
+ Snippet invocationSnippet =
+ getInvocationSnippet(wrapWithFuture, binding, parameterSnippets.build());
+ Snippet throwsClause = getThrowsClause(binding.thrownTypes());
+ transformSnippet =
+ Snippet.format(
+ Joiner.on('\n')
+ .join(
+ "new %1$s<%2$s, %3$s>() {",
+ " @Override public %4$s apply(%2$s %5$s) %6$s{",
+ " %7$s",
+ " }",
+ "}"),
+ ClassName.fromClass(AsyncFunction.class),
+ asyncDependencyType(asyncDependency),
+ providedTypeName,
+ futureTypeName,
+ argName,
+ throwsClause,
+ invocationSnippet);
+ } else {
+ futureSnippet = Snippet.format("%s.<%s>allAsList(%s)",
+ ClassName.fromClass(Futures.class),
+ ClassName.fromClass(Object.class),
+ Joiner.on(",").join(FluentIterable
+ .from(asyncDependencies)
+ .transform(DependencyRequest.BINDING_KEY_FUNCTION)
+ .transform(new Function<BindingKey, String>() {
+ @Override public String apply(BindingKey dependencyBindingKey) {
+ return fields.get(dependencyBindingKey).name() + "Future";
+ }
+ })));
+ ImmutableList<Snippet> parameterSnippets = getParameterSnippets(binding, fields, "args");
+ boolean wrapWithFuture = !returnsFuture; // only wrap if we don't already have a future
+ Snippet invocationSnippet =
+ getInvocationSnippet(wrapWithFuture, binding, parameterSnippets);
+ ParameterizedTypeName listOfObject =
+ ParameterizedTypeName.create(
+ ClassName.fromClass(List.class), ClassName.fromClass(Object.class));
+ Snippet throwsClause = getThrowsClause(binding.thrownTypes());
+ transformSnippet =
+ Snippet.format(
+ Joiner.on('\n')
+ .join(
+ "new %1$s<%2$s, %3$s>() {",
+ " @SuppressWarnings(\"unchecked\") // safe by specification",
+ " @Override public %4$s apply(%2$s args) %5$s{",
+ " %6$s",
+ " }",
+ "}"),
+ ClassName.fromClass(AsyncFunction.class),
+ listOfObject,
+ providedTypeName,
+ futureTypeName,
+ throwsClause,
+ invocationSnippet);
+ }
+ getMethodWriter.body().addSnippet("return %s.%s(%s, %s, executor);",
+ ClassName.fromClass(Futures.class),
+ "transform",
+ futureSnippet,
+ transformSnippet);
+ }
+
+ // TODO(gak): write a sensible toString
+ return ImmutableSet.of(writer);
+ }
+
+ private boolean isAsyncDependency(DependencyRequest dependency) {
+ switch (dependency.kind()) {
+ case INSTANCE:
+ case PRODUCED:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private TypeName asyncDependencyType(DependencyRequest dependency) {
+ TypeName keyName = TypeNames.forTypeMirror(dependency.key().type());
+ switch (dependency.kind()) {
+ case INSTANCE:
+ return keyName;
+ case PRODUCED:
+ return ParameterizedTypeName.create(ClassName.fromClass(Produced.class), keyName);
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private ImmutableList<Snippet> getParameterSnippets(ProductionBinding binding,
+ ImmutableMap<BindingKey, FrameworkField> fields,
+ String listArgName) {
+ int argIndex = 0;
+ ImmutableList.Builder<Snippet> snippets = ImmutableList.builder();
+ for (DependencyRequest dependency : binding.dependencies()) {
+ if (isAsyncDependency(dependency)) {
+ snippets.add(Snippet.format(
+ "(%s) %s.get(%s)",
+ asyncDependencyType(dependency),
+ listArgName,
+ argIndex));
+ argIndex++;
+ } else {
+ snippets.add(frameworkTypeUsageStatement(
+ Snippet.format(fields.get(dependency.bindingKey()).name()), dependency.kind()));
+ }
+ }
+ return snippets.build();
+ }
+
+ /**
+ * Creates a snippet for the invocation of the producer method from the module, which should be
+ * used entirely within a method body.
+ *
+ * @param wrapWithFuture If true, wraps the result of the call to the producer method
+ * in an immediate future.
+ * @param binding The binding to generate the invocation snippet for.
+ * @param parameterSnippets The snippets for all the parameters to the producer method.
+ */
+ private Snippet getInvocationSnippet(
+ boolean wrapWithFuture, ProductionBinding binding, ImmutableList<Snippet> parameterSnippets) {
+ Snippet moduleSnippet = Snippet.format("%s.%s(%s)",
+ binding.bindingElement().getModifiers().contains(STATIC)
+ ? ClassName.fromTypeElement(binding.bindingTypeElement())
+ : "module",
+ binding.bindingElement().getSimpleName(),
+ makeParametersSnippet(parameterSnippets));
+
+ // NOTE(beder): We don't worry about catching exeptions from the monitor methods themselves
+ // because we'll wrap all monitoring in non-throwing monitors before we pass them to the
+ // factories.
+ ImmutableList.Builder<Snippet> snippets = ImmutableList.builder();
+ snippets.add(Snippet.format("if (monitor != null) { monitor.methodStarting(); }"));
+
+ final Snippet valueSnippet;
+ if (binding.productionType().equals(Produces.Type.SET)) {
+ if (binding.bindingKind().equals(ProductionBinding.Kind.FUTURE_PRODUCTION)) {
+ valueSnippet =
+ Snippet.format(
+ "%s.createFutureSingletonSet(%s)",
+ ClassName.fromClass(Producers.class),
+ moduleSnippet);
+ } else {
+ valueSnippet =
+ Snippet.format("%s.of(%s)", ClassName.fromClass(ImmutableSet.class), moduleSnippet);
+ }
+ } else {
+ valueSnippet = moduleSnippet;
+ }
+ Snippet returnSnippet =
+ wrapWithFuture
+ ? Snippet.format(
+ "%s.<%s>immediateFuture(%s)",
+ ClassName.fromClass(Futures.class),
+ TypeNames.forTypeMirror(binding.key().type()),
+ valueSnippet)
+ : valueSnippet;
+ return Snippet.format(
+ Joiner.on('\n')
+ .join(
+ "if (monitor != null) { monitor.methodStarting(); }",
+ "try {",
+ " return %s;",
+ "} finally {",
+ " if (monitor != null) { monitor.methodFinished(); }",
+ "}"),
+ returnSnippet);
+ }
+
+ /**
+ * Creates a Snippet for the throws clause.
+ *
+ * @param thrownTypes the list of thrown types.
+ */
+ private Snippet getThrowsClause(List<? extends TypeMirror> thrownTypes) {
+ if (thrownTypes.isEmpty()) {
+ return Snippet.format("");
+ }
+ return Snippet.format("throws %s ",
+ Snippet.makeParametersSnippet(FluentIterable
+ .from(thrownTypes)
+ .transform(new Function<TypeMirror, Snippet>() {
+ @Override public Snippet apply(TypeMirror thrownType) {
+ return Snippet.format("%s", TypeNames.forTypeMirror(thrownType));
+ }
+ })
+ .toList()));
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProducerModuleProcessingStep.java b/compiler/src/main/java/dagger/internal/codegen/ProducerModuleProcessingStep.java
new file mode 100644
index 000000000..cc167e599
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProducerModuleProcessingStep.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.BasicAnnotationProcessor.ProcessingStep;
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.SuperficialValidation;
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.lang.annotation.Annotation;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static javax.lang.model.element.ElementKind.METHOD;
+
+/**
+ * An annotation processor for generating Dagger implementation code based on the
+ * {@link ProducerModule} (and {@link Produces}) annotation.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+final class ProducerModuleProcessingStep implements ProcessingStep {
+ private final Messager messager;
+ private final ModuleValidator moduleValidator;
+ private final ProducesMethodValidator producesMethodValidator;
+ private final ProductionBinding.Factory productionBindingFactory;
+ private final ProducerFactoryGenerator factoryGenerator;
+ private final Set<Element> processedModuleElements = Sets.newLinkedHashSet();
+
+ ProducerModuleProcessingStep(
+ Messager messager,
+ ModuleValidator moduleValidator,
+ ProducesMethodValidator producesMethodValidator,
+ ProductionBinding.Factory productionBindingFactory,
+ ProducerFactoryGenerator factoryGenerator) {
+ this.messager = messager;
+ this.moduleValidator = moduleValidator;
+ this.producesMethodValidator = producesMethodValidator;
+ this.productionBindingFactory = productionBindingFactory;
+ this.factoryGenerator = factoryGenerator;
+ }
+
+ @Override
+ public Set<Class<? extends Annotation>> annotations() {
+ return ImmutableSet.of(Produces.class, ProducerModule.class);
+ }
+
+ @Override
+ public Set<Element> process(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ // first, check and collect all produces methods
+ ImmutableSet.Builder<ExecutableElement> validProducesMethodsBuilder = ImmutableSet.builder();
+ for (Element producesElement : elementsByAnnotation.get(Produces.class)) {
+ if (producesElement.getKind().equals(METHOD)) {
+ ExecutableElement producesMethodElement = (ExecutableElement) producesElement;
+ ValidationReport<ExecutableElement> methodReport =
+ producesMethodValidator.validate(producesMethodElement);
+ methodReport.printMessagesTo(messager);
+ if (methodReport.isClean()) {
+ validProducesMethodsBuilder.add(producesMethodElement);
+ }
+ }
+ }
+ ImmutableSet<ExecutableElement> validProducesMethods = validProducesMethodsBuilder.build();
+
+ // process each module
+ for (Element moduleElement :
+ Sets.difference(elementsByAnnotation.get(ProducerModule.class),
+ processedModuleElements)) {
+ if (SuperficialValidation.validateElement(moduleElement)) {
+ ValidationReport<TypeElement> report =
+ moduleValidator.validate(MoreElements.asType(moduleElement));
+ report.printMessagesTo(messager);
+
+ if (report.isClean()) {
+ ImmutableSet.Builder<ExecutableElement> moduleProducesMethodsBuilder =
+ ImmutableSet.builder();
+ List<ExecutableElement> moduleMethods =
+ ElementFilter.methodsIn(moduleElement.getEnclosedElements());
+ for (ExecutableElement methodElement : moduleMethods) {
+ if (isAnnotationPresent(methodElement, Produces.class)) {
+ moduleProducesMethodsBuilder.add(methodElement);
+ }
+ }
+ ImmutableSet<ExecutableElement> moduleProducesMethods =
+ moduleProducesMethodsBuilder.build();
+
+ if (Sets.difference(moduleProducesMethods, validProducesMethods).isEmpty()) {
+ // all of the produces methods in this module are valid!
+ // time to generate some factories!
+ ImmutableSet<ProductionBinding> bindings = FluentIterable.from(moduleProducesMethods)
+ .transform(new Function<ExecutableElement, ProductionBinding>() {
+ @Override
+ public ProductionBinding apply(ExecutableElement producesMethod) {
+ return productionBindingFactory.forProducesMethod(producesMethod,
+ producesMethod.getEnclosingElement().asType());
+ }
+ })
+ .toSet();
+
+ try {
+ for (ProductionBinding binding : bindings) {
+ factoryGenerator.generate(binding);
+ }
+ } catch (SourceFileGenerationException e) {
+ e.printMessageTo(messager);
+ }
+ }
+ }
+
+ processedModuleElements.add(moduleElement);
+ }
+ }
+ return ImmutableSet.of();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProducesMethodValidator.java b/compiler/src/main/java/dagger/internal/codegen/ProducesMethodValidator.java
new file mode 100644
index 000000000..b0b4df1cc
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProducesMethodValidator.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.util.Set;
+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.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_ABSTRACT;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_MUST_RETURN_A_VALUE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_NOT_IN_MODULE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_NOT_MAP_HAS_MAP_KEY;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_PRIVATE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_SET_VALUES_RAW_SET;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_TYPE_PARAMETER;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_MULTIPLE_MAP_KEY;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_NO_MAP_KEY;
+import static dagger.internal.codegen.ErrorMessages.PRODUCES_METHOD_RAW_FUTURE;
+import static dagger.internal.codegen.ErrorMessages.PRODUCES_METHOD_RETURN_TYPE;
+import static dagger.internal.codegen.ErrorMessages.PRODUCES_METHOD_SET_VALUES_RETURN_SET;
+import static dagger.internal.codegen.MapKeys.getMapKeys;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.type.TypeKind.ARRAY;
+import static javax.lang.model.type.TypeKind.DECLARED;
+import static javax.lang.model.type.TypeKind.VOID;
+
+/**
+ * A {@linkplain ValidationReport validator} for {@link Produces} methods.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+// TODO(user): Consider unifying this with the ProvidesMethodValidator after Provides.Type and
+// Produces.Type are reconciled.
+final class ProducesMethodValidator {
+ private final Elements elements;
+
+ ProducesMethodValidator(Elements elements) {
+ this.elements = checkNotNull(elements);
+ }
+
+ private TypeElement getSetElement() {
+ return elements.getTypeElement(Set.class.getCanonicalName());
+ }
+
+ ValidationReport<ExecutableElement> validate(ExecutableElement producesMethodElement) {
+ ValidationReport.Builder<ExecutableElement> builder =
+ ValidationReport.about(producesMethodElement);
+
+ Produces producesAnnotation = producesMethodElement.getAnnotation(Produces.class);
+ checkArgument(producesAnnotation != null);
+
+ Element enclosingElement = producesMethodElement.getEnclosingElement();
+ if (!isAnnotationPresent(enclosingElement, ProducerModule.class)) {
+ builder.addError(
+ formatModuleErrorMessage(BINDING_METHOD_NOT_IN_MODULE), producesMethodElement);
+ }
+
+ if (!producesMethodElement.getTypeParameters().isEmpty()) {
+ builder.addError(formatErrorMessage(BINDING_METHOD_TYPE_PARAMETER), producesMethodElement);
+ }
+
+ Set<Modifier> modifiers = producesMethodElement.getModifiers();
+ if (modifiers.contains(PRIVATE)) {
+ builder.addError(formatErrorMessage(BINDING_METHOD_PRIVATE), producesMethodElement);
+ }
+ if (modifiers.contains(ABSTRACT)) {
+ builder.addError(formatErrorMessage(BINDING_METHOD_ABSTRACT), producesMethodElement);
+ }
+
+ TypeMirror returnType = producesMethodElement.getReturnType();
+ TypeKind returnTypeKind = returnType.getKind();
+ if (returnTypeKind.equals(VOID)) {
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_MUST_RETURN_A_VALUE), producesMethodElement);
+ }
+
+ // check mapkey is right
+ if (!producesAnnotation.type().equals(Produces.Type.MAP)
+ && !getMapKeys(producesMethodElement).isEmpty()) {
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_NOT_MAP_HAS_MAP_KEY), producesMethodElement);
+ }
+
+ ProvidesMethodValidator.validateMethodQualifiers(builder, producesMethodElement);
+
+ switch (producesAnnotation.type()) {
+ case UNIQUE: // fall through
+ case SET:
+ validateSingleReturnType(builder, returnType);
+ break;
+ case MAP:
+ validateSingleReturnType(builder, returnType);
+ ImmutableSet<? extends AnnotationMirror> mapKeys = getMapKeys(producesMethodElement);
+ switch (mapKeys.size()) {
+ case 0:
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_WITH_NO_MAP_KEY), producesMethodElement);
+ break;
+ case 1:
+ break;
+ default:
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_WITH_MULTIPLE_MAP_KEY), producesMethodElement);
+ break;
+ }
+ break;
+ case SET_VALUES:
+ if (returnTypeKind.equals(DECLARED)
+ && MoreTypes.isTypeOf(ListenableFuture.class, returnType)) {
+ DeclaredType declaredReturnType = MoreTypes.asDeclared(returnType);
+ if (!declaredReturnType.getTypeArguments().isEmpty()) {
+ validateSetType(builder, Iterables.getOnlyElement(
+ declaredReturnType.getTypeArguments()));
+ }
+ } else {
+ validateSetType(builder, returnType);
+ }
+ break;
+ default:
+ throw new AssertionError();
+ }
+
+ return builder.build();
+ }
+
+ private String formatErrorMessage(String msg) {
+ return String.format(msg, Produces.class.getSimpleName());
+ }
+
+ private String formatModuleErrorMessage(String msg) {
+ return String.format(msg, Produces.class.getSimpleName(), ProducerModule.class.getSimpleName());
+ }
+
+ private void validateKeyType(ValidationReport.Builder<? extends Element> reportBuilder,
+ TypeMirror type) {
+ TypeKind kind = type.getKind();
+ if (!(kind.isPrimitive() || kind.equals(DECLARED) || kind.equals(ARRAY))) {
+ reportBuilder.addError(PRODUCES_METHOD_RETURN_TYPE, reportBuilder.getSubject());
+ }
+ }
+
+ private void validateSingleReturnType(ValidationReport.Builder<? extends Element> reportBuilder,
+ TypeMirror type) {
+ if (type.getKind().equals(DECLARED) && MoreTypes.isTypeOf(ListenableFuture.class, type)) {
+ DeclaredType declaredType = MoreTypes.asDeclared(type);
+ if (declaredType.getTypeArguments().isEmpty()) {
+ reportBuilder.addError(PRODUCES_METHOD_RAW_FUTURE, reportBuilder.getSubject());
+ } else {
+ validateKeyType(reportBuilder, Iterables.getOnlyElement(declaredType.getTypeArguments()));
+ }
+ } else {
+ validateKeyType(reportBuilder, type);
+ }
+ }
+
+ private void validateSetType(ValidationReport.Builder<? extends Element> reportBuilder,
+ TypeMirror type) {
+ if (!type.getKind().equals(DECLARED)) {
+ reportBuilder.addError(PRODUCES_METHOD_SET_VALUES_RETURN_SET, reportBuilder.getSubject());
+ return;
+ }
+
+ // TODO(gak): should we allow "covariant return" for set values?
+ DeclaredType declaredType = MoreTypes.asDeclared(type);
+ if (!declaredType.asElement().equals(getSetElement())) {
+ reportBuilder.addError(PRODUCES_METHOD_SET_VALUES_RETURN_SET, reportBuilder.getSubject());
+ } else if (declaredType.getTypeArguments().isEmpty()) {
+ reportBuilder.addError(
+ formatErrorMessage(BINDING_METHOD_SET_VALUES_RAW_SET), reportBuilder.getSubject());
+ } else {
+ validateSingleReturnType(reportBuilder,
+ Iterables.getOnlyElement(declaredType.getTypeArguments()));
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProductionBinding.java b/compiler/src/main/java/dagger/internal/codegen/ProductionBinding.java
new file mode 100644
index 000000000..38d45e6a2
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProductionBinding.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Producer;
+import dagger.producers.Produces;
+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;
+import javax.lang.model.util.Types;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static javax.lang.model.element.ElementKind.METHOD;
+
+/**
+ * A value object representing the mechanism by which a {@link Key} can be produced. New instances
+ * should be created using an instance of the {@link Factory}.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+@AutoValue
+abstract class ProductionBinding extends ContributionBinding {
+ @Override
+ ImmutableSet<DependencyRequest> implicitDependencies() {
+ return dependencies();
+ }
+
+ enum Kind {
+ /** Represents a binding configured by {@link Produces} that doesn't return a future. */
+ IMMEDIATE,
+ /** Represents a binding configured by {@link Produces} that returns a future. */
+ FUTURE_PRODUCTION,
+ /**
+ * Represents a binding that is not explicitly tied to code, but generated implicitly by the
+ * framework.
+ */
+ SYNTHETIC_PRODUCTION,
+ /**
+ * Represents a binding from a production method on a component dependency that returns a
+ * future. Methods that return immediate values are considered provision bindings.
+ */
+ COMPONENT_PRODUCTION,
+ }
+
+ /**
+ * The type of binding (whether the {@link Produces} method returns a future). For the particular
+ * type of production, use {@link #productionType}.
+ */
+ abstract Kind bindingKind();
+
+ /** Returns provision type that was used to bind the key. */
+ abstract Produces.Type productionType();
+
+ /** Returns the list of types in the throws clause of the method. */
+ abstract ImmutableList<? extends TypeMirror> thrownTypes();
+
+ @Override
+ BindingType bindingType() {
+ switch (productionType()) {
+ case SET:
+ case SET_VALUES:
+ return BindingType.SET;
+ case MAP:
+ return BindingType.MAP;
+ case UNIQUE:
+ return BindingType.UNIQUE;
+ default:
+ throw new IllegalStateException("Unknown production type: " + productionType());
+ }
+ }
+
+ @Override
+ boolean isSyntheticBinding() {
+ return bindingKind().equals(Kind.SYNTHETIC_PRODUCTION);
+ }
+
+ @Override
+ Class<?> frameworkClass() {
+ return Producer.class;
+ }
+
+ static final class Factory {
+ private final Types types;
+ private final Key.Factory keyFactory;
+ private final DependencyRequest.Factory dependencyRequestFactory;
+
+ Factory(Types types,
+ Key.Factory keyFactory,
+ DependencyRequest.Factory
+ dependencyRequestFactory) {
+ this.types = types;
+ this.keyFactory = keyFactory;
+ this.dependencyRequestFactory = dependencyRequestFactory;
+ }
+
+ ProductionBinding forProducesMethod(
+ ExecutableElement producesMethod, TypeMirror contributedBy) {
+ checkNotNull(producesMethod);
+ checkArgument(producesMethod.getKind().equals(METHOD));
+ checkArgument(contributedBy.getKind().equals(TypeKind.DECLARED));
+ Produces producesAnnotation = producesMethod.getAnnotation(Produces.class);
+ checkArgument(producesAnnotation != null);
+ DeclaredType declaredContainer = MoreTypes.asDeclared(contributedBy);
+ ExecutableType resolvedMethod =
+ MoreTypes.asExecutable(types.asMemberOf(declaredContainer, producesMethod));
+ Key key = keyFactory.forProducesMethod(resolvedMethod, producesMethod);
+ ImmutableSet<DependencyRequest> dependencies =
+ dependencyRequestFactory.forRequiredResolvedVariables(
+ declaredContainer,
+ producesMethod.getParameters(),
+ resolvedMethod.getParameterTypes());
+ Kind kind = MoreTypes.isTypeOf(ListenableFuture.class, producesMethod.getReturnType())
+ ? Kind.FUTURE_PRODUCTION
+ : Kind.IMMEDIATE;
+ return new AutoValue_ProductionBinding(
+ key,
+ producesMethod,
+ dependencies,
+ findBindingPackage(key),
+ false,
+ ConfigurationAnnotations.getNullableType(producesMethod),
+ Optional.of(MoreTypes.asTypeElement(declaredContainer)),
+ kind,
+ producesAnnotation.type(),
+ ImmutableList.copyOf(producesMethod.getThrownTypes()));
+ }
+
+ ProductionBinding forImplicitMapBinding(DependencyRequest explicitRequest,
+ DependencyRequest implicitRequest) {
+ checkNotNull(explicitRequest);
+ checkNotNull(implicitRequest);
+ ImmutableSet<DependencyRequest> dependencies = ImmutableSet.of(implicitRequest);
+ return new AutoValue_ProductionBinding(
+ explicitRequest.key(),
+ implicitRequest.requestElement(),
+ dependencies,
+ findBindingPackage(explicitRequest.key()),
+ false,
+ Optional.<DeclaredType>absent(),
+ Optional.<TypeElement>absent(),
+ Kind.SYNTHETIC_PRODUCTION,
+ Produces.Type.MAP,
+ ImmutableList.<TypeMirror>of());
+ }
+
+ ProductionBinding forComponentMethod(ExecutableElement componentMethod) {
+ checkNotNull(componentMethod);
+ checkArgument(componentMethod.getKind().equals(METHOD));
+ checkArgument(componentMethod.getParameters().isEmpty());
+ checkArgument(MoreTypes.isTypeOf(ListenableFuture.class, componentMethod.getReturnType()));
+ return new AutoValue_ProductionBinding(
+ keyFactory.forProductionComponentMethod(componentMethod),
+ componentMethod,
+ ImmutableSet.<DependencyRequest>of(),
+ Optional.<String>absent(),
+ false,
+ Optional.<DeclaredType>absent(),
+ Optional.<TypeElement>absent(),
+ Kind.COMPONENT_PRODUCTION,
+ Produces.Type.UNIQUE,
+ ImmutableList.copyOf(componentMethod.getThrownTypes()));
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProductionBindingFormatter.java b/compiler/src/main/java/dagger/internal/codegen/ProductionBindingFormatter.java
new file mode 100644
index 000000000..e7e7e778a
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProductionBindingFormatter.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.base.Optional;
+
+import static com.google.auto.common.MoreElements.asExecutable;
+import static com.google.auto.common.MoreTypes.asDeclared;
+
+/**
+ * Formats a {@link ProductionBinding} into a {@link String} suitable for use in error messages.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+final class ProductionBindingFormatter extends Formatter<ProductionBinding> {
+ private final MethodSignatureFormatter methodSignatureFormatter;
+
+ ProductionBindingFormatter(MethodSignatureFormatter methodSignatureFormatter) {
+ this.methodSignatureFormatter = methodSignatureFormatter;
+ }
+
+ @Override public String format(ProductionBinding binding) {
+ switch (binding.bindingKind()) {
+ case IMMEDIATE:
+ case FUTURE_PRODUCTION:
+ return methodSignatureFormatter.format(asExecutable(binding.bindingElement()),
+ Optional.of(asDeclared(binding.contributedBy().get().asType())));
+ case COMPONENT_PRODUCTION:
+ return methodSignatureFormatter.format(asExecutable(binding.bindingElement()));
+ default:
+ throw new UnsupportedOperationException(
+ "Not yet supporting " + binding.bindingKind() + " binding types.");
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProductionComponentProcessingStep.java b/compiler/src/main/java/dagger/internal/codegen/ProductionComponentProcessingStep.java
new file mode 100644
index 000000000..56f8ccb17
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProductionComponentProcessingStep.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.BasicAnnotationProcessor.ProcessingStep;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+import dagger.producers.ProductionComponent;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * A {@link ProcessingStep} that is responsible for dealing with the {@link ProductionComponent}
+ * annotation as part of the {@link ComponentProcessor}.
+ *
+ * @author Jesse Beder
+ */
+final class ProductionComponentProcessingStep extends AbstractComponentProcessingStep {
+ private final ComponentElementValidator componentElementValidator;
+
+ ProductionComponentProcessingStep(
+ Messager messager,
+ final ProductionComponentValidator componentValidator,
+ ComponentHierarchyValidator componentHierarchyValidator,
+ BindingGraphValidator bindingGraphValidator,
+ ComponentDescriptor.Factory componentDescriptorFactory,
+ BindingGraph.Factory bindingGraphFactory,
+ ComponentGenerator componentGenerator) {
+ super(
+ ProductionComponent.class,
+ messager,
+ componentHierarchyValidator,
+ bindingGraphValidator,
+ componentDescriptorFactory,
+ bindingGraphFactory,
+ componentGenerator);
+ this.componentElementValidator =
+ new ComponentElementValidator() {
+ @Override
+ boolean validateComponent(TypeElement componentTypeElement, Messager messager) {
+ ValidationReport<TypeElement> validationReport =
+ componentValidator.validate(componentTypeElement);
+ validationReport.printMessagesTo(messager);
+ return validationReport.isClean();
+ }
+ };
+ }
+
+ @Override
+ public Set<Class<? extends Annotation>> annotations() {
+ return ImmutableSet.<Class<? extends Annotation>>of(ProductionComponent.class);
+ }
+
+ @Override
+ protected ComponentElementValidator componentElementValidator(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ return componentElementValidator;
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProductionComponentValidator.java b/compiler/src/main/java/dagger/internal/codegen/ProductionComponentValidator.java
new file mode 100644
index 000000000..2e2291d34
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProductionComponentValidator.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.common.collect.ImmutableList;
+import dagger.Module;
+import dagger.producers.ProducerModule;
+import dagger.producers.ProductionComponent;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleTypeVisitor6;
+
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.ConfigurationAnnotations.getComponentModules;
+import static javax.lang.model.element.ElementKind.CLASS;
+import static javax.lang.model.element.ElementKind.INTERFACE;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+
+/**
+ * Performs superficial validation of the contract of the {@link ProductionComponent} annotation.
+ *
+ * @author Jesse Beder
+ */
+final class ProductionComponentValidator {
+ ValidationReport<TypeElement> validate(final TypeElement subject) {
+ final ValidationReport.Builder<TypeElement> builder = ValidationReport.about(subject);
+
+ if (!subject.getKind().equals(INTERFACE)
+ && !(subject.getKind().equals(CLASS) && subject.getModifiers().contains(ABSTRACT))) {
+ builder.addError(
+ "@ProductionComponent may only be applied to an interface or abstract class", subject);
+ }
+
+ AnnotationMirror componentMirror =
+ getAnnotationMirror(subject, ProductionComponent.class).get();
+ ImmutableList<TypeMirror> moduleTypes = getComponentModules(componentMirror);
+
+ // TODO(gak): make unused modules an error
+ for (TypeMirror moduleType : moduleTypes) {
+ moduleType.accept(
+ new SimpleTypeVisitor6<Void, Void>() {
+ @Override
+ protected Void defaultAction(TypeMirror mirror, Void p) {
+ builder.addError(mirror + " is not a valid module type.", subject);
+ return null;
+ }
+
+ @Override
+ public Void visitDeclared(DeclaredType t, Void p) {
+ checkState(t.getTypeArguments().isEmpty());
+ TypeElement moduleElement = MoreElements.asType(t.asElement());
+ if (!getAnnotationMirror(moduleElement, Module.class).isPresent()
+ && !getAnnotationMirror(moduleElement, ProducerModule.class).isPresent()) {
+ builder.addError(
+ moduleElement.getQualifiedName()
+ + " is listed as a module, but is not annotated with @Module or"
+ + " @ProducerModule",
+ subject);
+ }
+ return null;
+ }
+ },
+ null);
+ }
+
+ return builder.build();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProvidesMethodValidator.java b/compiler/src/main/java/dagger/internal/codegen/ProvidesMethodValidator.java
new file mode 100644
index 000000000..e9c8b1629
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProvidesMethodValidator.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.google.common.collect.Iterables;
+import dagger.Module;
+import dagger.Provides;
+import java.util.Set;
+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.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_ABSTRACT;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_MUST_RETURN_A_VALUE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_NOT_IN_MODULE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_NOT_MAP_HAS_MAP_KEY;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_PRIVATE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_SET_VALUES_RAW_SET;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_TYPE_PARAMETER;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_MULTIPLE_MAP_KEY;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_NO_MAP_KEY;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_METHOD_RETURN_TYPE;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_METHOD_SET_VALUES_RETURN_SET;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifiers;
+import static dagger.internal.codegen.MapKeys.getMapKeys;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.type.TypeKind.ARRAY;
+import static javax.lang.model.type.TypeKind.DECLARED;
+import static javax.lang.model.type.TypeKind.VOID;
+
+/**
+ * A {@linkplain ValidationReport validator} for {@link Provides} methods.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class ProvidesMethodValidator {
+ private final Elements elements;
+
+ ProvidesMethodValidator(Elements elements) {
+ this.elements = checkNotNull(elements);
+ }
+
+ private TypeElement getSetElement() {
+ return elements.getTypeElement(Set.class.getCanonicalName());
+ }
+
+ ValidationReport<ExecutableElement> validate(ExecutableElement providesMethodElement) {
+ ValidationReport.Builder<ExecutableElement> builder =
+ ValidationReport.about(providesMethodElement);
+
+ Provides providesAnnotation = providesMethodElement.getAnnotation(Provides.class);
+ checkArgument(providesAnnotation != null);
+
+ Element enclosingElement = providesMethodElement.getEnclosingElement();
+ if (!isAnnotationPresent(enclosingElement, Module.class)) {
+ builder.addError(
+ formatModuleErrorMessage(BINDING_METHOD_NOT_IN_MODULE), providesMethodElement);
+ }
+
+ if (!providesMethodElement.getTypeParameters().isEmpty()) {
+ builder.addError(formatErrorMessage(BINDING_METHOD_TYPE_PARAMETER), providesMethodElement);
+ }
+
+ Set<Modifier> modifiers = providesMethodElement.getModifiers();
+ if (modifiers.contains(PRIVATE)) {
+ builder.addError(formatErrorMessage(BINDING_METHOD_PRIVATE), providesMethodElement);
+ }
+ if (modifiers.contains(ABSTRACT)) {
+ builder.addError(formatErrorMessage(BINDING_METHOD_ABSTRACT), providesMethodElement);
+ }
+
+ TypeMirror returnType = providesMethodElement.getReturnType();
+ TypeKind returnTypeKind = returnType.getKind();
+ if (returnTypeKind.equals(VOID)) {
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_MUST_RETURN_A_VALUE), providesMethodElement);
+ }
+
+ // check mapkey is right
+ if (!providesAnnotation.type().equals(Provides.Type.MAP)
+ && !getMapKeys(providesMethodElement).isEmpty()) {
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_NOT_MAP_HAS_MAP_KEY), providesMethodElement);
+ }
+
+ validateMethodQualifiers(builder, providesMethodElement);
+
+ switch (providesAnnotation.type()) {
+ case UNIQUE: // fall through
+ case SET:
+ validateKeyType(builder, returnType);
+ break;
+ case MAP:
+ validateKeyType(builder, returnType);
+ ImmutableSet<? extends AnnotationMirror> mapKeys = getMapKeys(providesMethodElement);
+ switch (mapKeys.size()) {
+ case 0:
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_WITH_NO_MAP_KEY), providesMethodElement);
+ break;
+ case 1:
+ break;
+ default:
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_WITH_MULTIPLE_MAP_KEY), providesMethodElement);
+ break;
+ }
+ break;
+ case SET_VALUES:
+ if (!returnTypeKind.equals(DECLARED)) {
+ builder.addError(PROVIDES_METHOD_SET_VALUES_RETURN_SET, providesMethodElement);
+ } else {
+ DeclaredType declaredReturnType = (DeclaredType) returnType;
+ // TODO(gak): should we allow "covariant return" for set values?
+ if (!declaredReturnType.asElement().equals(getSetElement())) {
+ builder.addError(PROVIDES_METHOD_SET_VALUES_RETURN_SET, providesMethodElement);
+ } else if (declaredReturnType.getTypeArguments().isEmpty()) {
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_SET_VALUES_RAW_SET), providesMethodElement);
+ } else {
+ validateKeyType(builder,
+ Iterables.getOnlyElement(declaredReturnType.getTypeArguments()));
+ }
+ }
+ break;
+ default:
+ throw new AssertionError();
+ }
+
+ return builder.build();
+ }
+
+ /** Validates that a Provides or Produces method doesn't have multiple qualifiers. */
+ static void validateMethodQualifiers(ValidationReport.Builder<ExecutableElement> builder,
+ ExecutableElement methodElement) {
+ ImmutableSet<? extends AnnotationMirror> qualifiers = getQualifiers(methodElement);
+ if (qualifiers.size() > 1) {
+ for (AnnotationMirror qualifier : qualifiers) {
+ builder.addError(PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS, methodElement, qualifier);
+ }
+ }
+ }
+
+ private String formatErrorMessage(String msg) {
+ return String.format(msg, Provides.class.getSimpleName());
+ }
+
+ private String formatModuleErrorMessage(String msg) {
+ return String.format(msg, Provides.class.getSimpleName(), Module.class.getSimpleName());
+ }
+
+ private void validateKeyType(ValidationReport.Builder<? extends Element> reportBuilder,
+ TypeMirror type) {
+ TypeKind kind = type.getKind();
+ if (!(kind.isPrimitive() || kind.equals(DECLARED) || kind.equals(ARRAY))) {
+ reportBuilder.addError(PROVIDES_METHOD_RETURN_TYPE, reportBuilder.getSubject());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProvisionBinding.java b/compiler/src/main/java/dagger/internal/codegen/ProvisionBinding.java
new file mode 100644
index 000000000..8a3c203c8
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProvisionBinding.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import dagger.Provides;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.inject.Provider;
+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;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+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.InjectionAnnotations.getQualifier;
+import static dagger.internal.codegen.ProvisionBinding.Kind.INJECTION;
+import static dagger.internal.codegen.ProvisionBinding.Kind.PROVISION;
+import static javax.lang.model.element.ElementKind.CONSTRUCTOR;
+import static javax.lang.model.element.ElementKind.FIELD;
+import static javax.lang.model.element.ElementKind.METHOD;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * A value object representing the mechanism by which a {@link Key} can be provided. New instances
+ * should be created using an instance of the {@link Factory}.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@AutoValue
+abstract class ProvisionBinding extends ContributionBinding {
+ @Override
+ Set<DependencyRequest> implicitDependencies() {
+ // Optimization: If we don't need the memberInjectionRequest, don't create more objects.
+ if (!memberInjectionRequest().isPresent()) {
+ return dependencies();
+ } else {
+ // Optimization: Avoid creating an ImmutableSet+Builder just to union two things together.
+ return Sets.union(memberInjectionRequest().asSet(), dependencies());
+ }
+ }
+
+ enum Kind {
+ /** Represents an {@link Inject} binding. */
+ INJECTION,
+ /** Represents a binding configured by {@link Provides}. */
+ PROVISION,
+ /**
+ * Represents a binding that is not explicitly tied to code, but generated implicitly by the
+ * framework.
+ */
+ SYNTHETIC_PROVISON,
+ /** Represents the implicit binding to the component. */
+ COMPONENT,
+ /** Represents a binding from a provision method on a component dependency. */
+ COMPONENT_PROVISION,
+ }
+
+ /**
+ * The type of binding ({@link Inject} or {@link Provides}). For the particular type of provision,
+ * use {@link #provisionType}.
+ */
+ abstract Kind bindingKind();
+
+ /** Returns provision type that was used to bind the key. */
+ abstract Provides.Type provisionType();
+
+ /**
+ * The scope of the provider.
+ */
+ abstract Scope scope();
+
+ /** If this provision requires members injection, this will be the corresponding request. */
+ abstract Optional<DependencyRequest> memberInjectionRequest();
+
+ @Override
+ BindingType bindingType() {
+ switch (provisionType()) {
+ case SET:
+ case SET_VALUES:
+ return BindingType.SET;
+ case MAP:
+ return BindingType.MAP;
+ case UNIQUE:
+ return BindingType.UNIQUE;
+ default:
+ throw new IllegalStateException("Unknown provision type: " + provisionType());
+ }
+ }
+
+ @Override
+ boolean isSyntheticBinding() {
+ return bindingKind().equals(Kind.SYNTHETIC_PROVISON);
+ }
+
+ @Override
+ Class<?> frameworkClass() {
+ return Provider.class;
+ }
+
+ enum FactoryCreationStrategy {
+ ENUM_INSTANCE,
+ CLASS_CONSTRUCTOR,
+ }
+
+ FactoryCreationStrategy factoryCreationStrategy() {
+ if (bindingKind().equals(INJECTION) && implicitDependencies().isEmpty()) {
+ return FactoryCreationStrategy.ENUM_INSTANCE;
+ }
+ if (bindingKind().equals(PROVISION)
+ && implicitDependencies().isEmpty()
+ && bindingElement().getModifiers().contains(STATIC)) {
+ return FactoryCreationStrategy.ENUM_INSTANCE;
+ }
+ return FactoryCreationStrategy.CLASS_CONSTRUCTOR;
+ }
+
+ static final class Factory {
+ private final Elements elements;
+ private final Types types;
+ private final Key.Factory keyFactory;
+ private final DependencyRequest.Factory dependencyRequestFactory;
+
+ Factory(Elements elements, Types types, Key.Factory keyFactory,
+ DependencyRequest.Factory dependencyRequestFactory) {
+ this.elements = elements;
+ this.types = types;
+ this.keyFactory = keyFactory;
+ this.dependencyRequestFactory = dependencyRequestFactory;
+ }
+
+ /** Returns an unresolved version of this binding. */
+ ProvisionBinding unresolve(ProvisionBinding binding) {
+ checkState(binding.hasNonDefaultTypeParameters());
+ return forInjectConstructor((ExecutableElement) binding.bindingElement(),
+ Optional.<TypeMirror>absent());
+ }
+
+ /**
+ * Returns a ProvisionBinding for the given element. If {@code resolvedType} is present, this
+ * will return a resolved binding, with the key & type resolved to the given type (using
+ * {@link Types#asMemberOf(DeclaredType, Element)}).
+ */
+ ProvisionBinding forInjectConstructor(ExecutableElement constructorElement,
+ Optional<TypeMirror> resolvedType) {
+ checkNotNull(constructorElement);
+ checkArgument(constructorElement.getKind().equals(CONSTRUCTOR));
+ checkArgument(isAnnotationPresent(constructorElement, Inject.class));
+ checkArgument(!getQualifier(constructorElement).isPresent());
+
+ ExecutableType cxtorType = MoreTypes.asExecutable(constructorElement.asType());
+ DeclaredType enclosingCxtorType =
+ MoreTypes.asDeclared(constructorElement.getEnclosingElement().asType());
+ // If the class this is constructing has some type arguments, resolve everything.
+ if (!enclosingCxtorType.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(enclosingCxtorType)),
+ "erased expected type: %s, erased actual type: %s",
+ types.erasure(resolved), types.erasure(enclosingCxtorType));
+ cxtorType = MoreTypes.asExecutable(types.asMemberOf(resolved, constructorElement));
+ enclosingCxtorType = resolved;
+ }
+
+ Key key = keyFactory.forInjectConstructorWithResolvedType(enclosingCxtorType);
+ checkArgument(!key.qualifier().isPresent());
+ ImmutableSet<DependencyRequest> dependencies =
+ dependencyRequestFactory.forRequiredResolvedVariables(enclosingCxtorType,
+ constructorElement.getParameters(),
+ cxtorType.getParameterTypes());
+ Optional<DependencyRequest> membersInjectionRequest =
+ membersInjectionRequest(enclosingCxtorType);
+ Scope scope = Scope.scopeOf(constructorElement.getEnclosingElement());
+
+ TypeElement bindingTypeElement =
+ MoreElements.asType(constructorElement.getEnclosingElement());
+
+ return new AutoValue_ProvisionBinding(
+ key,
+ constructorElement,
+ dependencies,
+ findBindingPackage(key),
+ hasNonDefaultTypeParameters(bindingTypeElement, key.type(), types),
+ Optional.<DeclaredType>absent(),
+ Optional.<TypeElement>absent(),
+ Kind.INJECTION,
+ Provides.Type.UNIQUE,
+ scope,
+ membersInjectionRequest);
+ }
+
+ private static final ImmutableSet<ElementKind> MEMBER_KINDS =
+ Sets.immutableEnumSet(METHOD, FIELD);
+
+ private Optional<DependencyRequest> membersInjectionRequest(DeclaredType type) {
+ TypeElement typeElement = MoreElements.asType(type.asElement());
+ if (!types.isSameType(elements.getTypeElement(Object.class.getCanonicalName()).asType(),
+ typeElement.getSuperclass())) {
+ return Optional.of(dependencyRequestFactory.forMembersInjectedType(type));
+ }
+ for (Element enclosedElement : typeElement.getEnclosedElements()) {
+ if (MEMBER_KINDS.contains(enclosedElement.getKind())
+ && (isAnnotationPresent(enclosedElement, Inject.class))) {
+ return Optional.of(dependencyRequestFactory.forMembersInjectedType(type));
+ }
+ }
+ return Optional.absent();
+ }
+
+ ProvisionBinding forProvidesMethod(ExecutableElement providesMethod, TypeMirror contributedBy) {
+ checkNotNull(providesMethod);
+ checkArgument(providesMethod.getKind().equals(METHOD));
+ checkArgument(contributedBy.getKind().equals(TypeKind.DECLARED));
+ Provides providesAnnotation = providesMethod.getAnnotation(Provides.class);
+ checkArgument(providesAnnotation != null);
+ DeclaredType declaredContainer = MoreTypes.asDeclared(contributedBy);
+ ExecutableType resolvedMethod =
+ MoreTypes.asExecutable(types.asMemberOf(declaredContainer, providesMethod));
+ Key key = keyFactory.forProvidesMethod(resolvedMethod, providesMethod);
+ ImmutableSet<DependencyRequest> dependencies =
+ dependencyRequestFactory.forRequiredResolvedVariables(
+ declaredContainer,
+ providesMethod.getParameters(),
+ resolvedMethod.getParameterTypes());
+ Scope scope = Scope.scopeOf(providesMethod);
+ return new AutoValue_ProvisionBinding(
+ key,
+ providesMethod,
+ dependencies,
+ findBindingPackage(key),
+ false /* no non-default parameter types */,
+ ConfigurationAnnotations.getNullableType(providesMethod),
+ Optional.of(MoreTypes.asTypeElement(declaredContainer)),
+ Kind.PROVISION,
+ providesAnnotation.type(),
+ scope,
+ Optional.<DependencyRequest>absent());
+ }
+
+ ProvisionBinding forImplicitMapBinding(DependencyRequest explicitRequest,
+ DependencyRequest implicitRequest) {
+ checkNotNull(explicitRequest);
+ checkNotNull(implicitRequest);
+ ImmutableSet<DependencyRequest> dependencies = ImmutableSet.of(implicitRequest);
+ Scope scope = Scope.scopeOf(implicitRequest.requestElement());
+ return new AutoValue_ProvisionBinding(
+ explicitRequest.key(),
+ implicitRequest.requestElement(),
+ dependencies,
+ findBindingPackage(explicitRequest.key()),
+ false /* no non-default parameter types */,
+ Optional.<DeclaredType>absent(),
+ Optional.<TypeElement>absent(),
+ Kind.SYNTHETIC_PROVISON,
+ Provides.Type.MAP,
+ scope,
+ Optional.<DependencyRequest>absent());
+ }
+
+ ProvisionBinding forComponent(TypeElement componentDefinitionType) {
+ checkNotNull(componentDefinitionType);
+ return new AutoValue_ProvisionBinding(
+ keyFactory.forComponent(componentDefinitionType.asType()),
+ componentDefinitionType,
+ ImmutableSet.<DependencyRequest>of(),
+ Optional.<String>absent(),
+ false /* no non-default parameter types */,
+ Optional.<DeclaredType>absent(),
+ Optional.<TypeElement>absent(),
+ Kind.COMPONENT,
+ Provides.Type.UNIQUE,
+ Scope.unscoped(),
+ Optional.<DependencyRequest>absent());
+ }
+
+ ProvisionBinding forComponentMethod(ExecutableElement componentMethod) {
+ checkNotNull(componentMethod);
+ checkArgument(componentMethod.getKind().equals(METHOD));
+ checkArgument(componentMethod.getParameters().isEmpty());
+ Scope scope = Scope.scopeOf(componentMethod);
+ return new AutoValue_ProvisionBinding(
+ keyFactory.forComponentMethod(componentMethod),
+ componentMethod,
+ ImmutableSet.<DependencyRequest>of(),
+ Optional.<String>absent(),
+ false /* no non-default parameter types */,
+ ConfigurationAnnotations.getNullableType(componentMethod),
+ Optional.<TypeElement>absent(),
+ Kind.COMPONENT_PROVISION,
+ Provides.Type.UNIQUE,
+ scope,
+ Optional.<DependencyRequest>absent());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProvisionBindingFormatter.java b/compiler/src/main/java/dagger/internal/codegen/ProvisionBindingFormatter.java
new file mode 100644
index 000000000..92d031042
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProvisionBindingFormatter.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.base.Optional;
+
+import static com.google.auto.common.MoreElements.asExecutable;
+import static com.google.auto.common.MoreTypes.asDeclared;
+
+/**
+ * Formats a {@link ProvisionBinding} into a {@link String} suitable for use in error messages.
+ *
+ * @author Christian Gruber
+ * @since 2.0
+ */
+final class ProvisionBindingFormatter extends Formatter<ProvisionBinding> {
+ private final MethodSignatureFormatter methodSignatureFormatter;
+
+ ProvisionBindingFormatter(MethodSignatureFormatter methodSignatureFormatter) {
+ this.methodSignatureFormatter = methodSignatureFormatter;
+ }
+
+ @Override public String format(ProvisionBinding binding) {
+ switch (binding.bindingKind()) {
+ case PROVISION:
+ return methodSignatureFormatter.format(asExecutable(binding.bindingElement()),
+ Optional.of(asDeclared(binding.contributedBy().get().asType())));
+ case COMPONENT_PROVISION:
+ return methodSignatureFormatter.format(asExecutable(binding.bindingElement()));
+ default:
+ throw new UnsupportedOperationException(
+ "Not yet supporting " + binding.bindingKind() + " binding types.");
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ResolvedBindings.java b/compiler/src/main/java/dagger/internal/codegen/ResolvedBindings.java
new file mode 100644
index 000000000..7ef4deb92
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ResolvedBindings.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.value.AutoValue;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Multimap;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.ContributionBinding.bindingTypeFor;
+
+/**
+ * The collection of bindings that have been resolved for a binding key.
+ *
+ * @author Gregory Kick
+ */
+@AutoValue
+abstract class ResolvedBindings {
+ abstract BindingKey bindingKey();
+ abstract ComponentDescriptor owningComponent();
+ abstract ImmutableSet<? extends Binding> ownedBindings();
+ abstract ImmutableSetMultimap<ComponentDescriptor, ? extends Binding> inheritedBindings();
+
+ static ResolvedBindings create(
+ BindingKey bindingKey,
+ ComponentDescriptor owningComponent,
+ Set<? extends Binding> ownedBindings,
+ Multimap<ComponentDescriptor, ? extends Binding> inheritedBindings) {
+ return new AutoValue_ResolvedBindings(
+ bindingKey,
+ owningComponent,
+ ImmutableSet.copyOf(ownedBindings),
+ ImmutableSetMultimap.copyOf(inheritedBindings));
+ }
+
+ static ResolvedBindings create(
+ BindingKey bindingKey,
+ ComponentDescriptor owningComponent,
+ Binding... ownedBindings) {
+ return new AutoValue_ResolvedBindings(
+ bindingKey,
+ owningComponent,
+ ImmutableSet.copyOf(ownedBindings),
+ ImmutableSetMultimap.<ComponentDescriptor, Binding>of());
+ }
+
+ ImmutableSet<? extends Binding> bindings() {
+ return new ImmutableSet.Builder<Binding>()
+ .addAll(ownedBindings())
+ .addAll(inheritedBindings().values())
+ .build();
+ }
+
+ @SuppressWarnings("unchecked") // checked by validator
+ ImmutableSet<? extends ContributionBinding> ownedContributionBindings() {
+ checkState(bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION));
+ return (ImmutableSet<? extends ContributionBinding>) ownedBindings();
+ }
+
+ @SuppressWarnings("unchecked") // checked by validator
+ ImmutableSet<? extends ContributionBinding> contributionBindings() {
+ checkState(bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION));
+ return new ImmutableSet.Builder<ContributionBinding>()
+ .addAll((Iterable<? extends ContributionBinding>) ownedBindings())
+ .addAll((Iterable<? extends ContributionBinding>) inheritedBindings().values())
+ .build();
+ }
+
+ @SuppressWarnings("unchecked") // checked by validator
+ ImmutableSet<? extends MembersInjectionBinding> membersInjectionBindings() {
+ checkState(bindingKey().kind().equals(BindingKey.Kind.MEMBERS_INJECTION));
+ return new ImmutableSet.Builder<MembersInjectionBinding>()
+ .addAll((Iterable<? extends MembersInjectionBinding>) ownedBindings())
+ .addAll((Iterable<? extends MembersInjectionBinding>) inheritedBindings().values())
+ .build();
+ }
+
+ /**
+ * Returns a {@code ResolvedBindings} with the same {@link #bindingKey()} and {@link #bindings()}
+ * as this one, but no {@link #ownedBindings()}.
+ */
+ ResolvedBindings asInheritedIn(ComponentDescriptor owningComponent) {
+ return ResolvedBindings.create(
+ bindingKey(),
+ owningComponent,
+ ImmutableSet.<Binding>of(),
+ new ImmutableSetMultimap.Builder<ComponentDescriptor, Binding>()
+ .putAll(inheritedBindings())
+ .putAll(owningComponent, ownedBindings())
+ .build());
+ }
+
+ /**
+ * {@code true} if this is a multibindings contribution.
+ */
+ boolean isMultibindings() {
+ return bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION)
+ && !contributionBindings().isEmpty()
+ && bindingTypeFor(contributionBindings()).isMultibinding();
+ }
+
+ /**
+ * {@code true} if this is a unique contribution binding.
+ */
+ boolean isUniqueContribution() {
+ return bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION)
+ && !contributionBindings().isEmpty()
+ && !bindingTypeFor(contributionBindings()).isMultibinding();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/Scope.java b/compiler/src/main/java/dagger/internal/codegen/Scope.java
new file mode 100644
index 000000000..bcb009d1e
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/Scope.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.AnnotationMirrors;
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import javax.annotation.Nullable;
+import javax.inject.Singleton;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+import static com.google.auto.common.MoreTypes.isTypeOf;
+import static dagger.internal.codegen.ErrorMessages.stripCommonTypePrefixes;
+import static dagger.internal.codegen.InjectionAnnotations.getScopeAnnotation;
+
+/**
+ * A representation of the scope (or lack of it) associated with a component, providing method
+ * or injection location.
+ */
+final class Scope {
+
+ /**
+ * An internal representation for an unscoped binding.
+ */
+ private static final Scope UNSCOPED = new Scope();
+
+ /**
+ * The underlying {@link AnnotationMirror} that represents the scope annotation.
+ */
+ @Nullable
+ private final AnnotationMirror annotationMirror;
+
+ private Scope(@Nullable AnnotationMirror annotationMirror) {
+ this.annotationMirror = annotationMirror;
+ }
+
+ private Scope() {
+ this(null);
+ }
+
+ /**
+ * Returns representation for an unscoped binding.
+ */
+ static Scope unscoped() {
+ return UNSCOPED;
+ }
+
+ /**
+ * If the source code element has an associated scoped annotation then returns a representation
+ * of that scope, otherwise returns a representation for an unscoped binding.
+ */
+ static Scope scopeOf(Element element) {
+ Optional<AnnotationMirror> scopeAnnotation = getScopeAnnotation(element);
+ return scopeAnnotation.isPresent() ? new Scope(scopeAnnotation.get()) : UNSCOPED;
+ }
+
+ /**
+ * Returns true if the scope is present, i.e. it's not unscoped binding.
+ */
+ public boolean isPresent() {
+ return annotationMirror != null;
+ }
+
+ /**
+ * Returns true if the scope represents the {@link Singleton @Singleton} annotation.
+ */
+ public boolean isSingleton() {
+ return annotationMirror != null
+ && isTypeOf(Singleton.class, annotationMirror.getAnnotationType());
+ }
+
+ /**
+ * Returns the readable source representation (name with @ prefix) of the annotation type.
+ *
+ * <p>It's readable source because it has had common package prefixes removed, e.g.
+ * {@code @javax.inject.Singleton} is returned as {@code @Singleton}.
+ *
+ * <p>Make sure that the scope is actually {@link #isPresent() present} before calling as it will
+ * throw an {@link IllegalStateException} otherwise. This does not return any annotation values
+ * as according to {@link javax.inject.Scope} scope annotations are not supposed to use them.
+ */
+ public String getReadableSource() {
+ return stripCommonTypePrefixes("@" + getQualifiedName());
+ }
+
+ /**
+ * Returns the fully qualified name of the annotation type.
+ *
+ * <p>Make sure that the scope is actually {@link #isPresent() present} before calling as it will
+ * throw an {@link IllegalStateException} otherwise. This does not return any annotation values
+ * as according to {@link javax.inject.Scope} scope annotations are not supposed to use them.
+ */
+ public String getQualifiedName() {
+ Preconditions.checkState(annotationMirror != null,
+ "Cannot create a stripped source representation of no annotation");
+ TypeElement typeElement = MoreTypes.asTypeElement(annotationMirror.getAnnotationType());
+ return typeElement.getQualifiedName().toString();
+ }
+
+ /**
+ * Scopes are equal if the underlying {@link AnnotationMirror} are equivalent according to
+ * {@link AnnotationMirrors#equivalence()}.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ } else if (obj instanceof Scope) {
+ Scope that = (Scope) obj;
+ return AnnotationMirrors.equivalence()
+ .equivalent(this.annotationMirror, that.annotationMirror);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return AnnotationMirrors.equivalence().hash(annotationMirror);
+ }
+
+ /**
+ * Returns a debug representation of the scope.
+ */
+ @Override
+ public String toString() {
+ return annotationMirror == null ? "UNSCOPED" : annotationMirror.toString();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/SourceFileGenerationException.java b/compiler/src/main/java/dagger/internal/codegen/SourceFileGenerationException.java
new file mode 100644
index 000000000..c2620981a
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/SourceFileGenerationException.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import dagger.internal.codegen.writer.ClassName;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.Element;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+/**
+ * An exception thrown to indicate that a source file could not be generated.
+ *
+ * <p>This exception <b>should not</b> be used to report detectable, logical errors as it may mask
+ * other errors that might have been caught upon further processing. Use a {@link ValidationReport}
+ * for that.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class SourceFileGenerationException extends Exception {
+ private final ImmutableSet<ClassName> generatedClassNames;
+ private final Optional<? extends Element> associatedElement;
+
+ SourceFileGenerationException(Iterable<ClassName> generatedClassNames, Throwable cause,
+ Optional<? extends Element> associatedElement) {
+ super(createMessage(generatedClassNames, cause.getMessage()), cause);
+ this.generatedClassNames = ImmutableSet.copyOf(generatedClassNames);
+ this.associatedElement = checkNotNull(associatedElement);
+ }
+
+ SourceFileGenerationException(Iterable<ClassName> generatedClassNames, Throwable cause) {
+ this(generatedClassNames, cause, Optional.<Element>absent());
+ }
+
+ SourceFileGenerationException(Iterable<ClassName> generatedClassNames, Throwable cause,
+ Element associatedElement) {
+ this(generatedClassNames, cause, Optional.of(associatedElement));
+ }
+
+ public ImmutableSet<ClassName> generatedClassNames() {
+ return generatedClassNames;
+ }
+
+ public Optional<? extends Element> associatedElement() {
+ return associatedElement;
+ }
+
+ private static String createMessage(Iterable<ClassName> generatedClassNames, String message) {
+ return String.format("Could not generate %s: %s.",
+ Iterables.isEmpty(generatedClassNames)
+ ? "unknown files"
+ : Iterables.toString(generatedClassNames),
+ message);
+ }
+
+ void printMessageTo(Messager messager) {
+ if (associatedElement.isPresent()) {
+ messager.printMessage(ERROR, getMessage(), associatedElement.get());
+ } else {
+ messager.printMessage(ERROR, getMessage());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/SourceFileGenerator.java b/compiler/src/main/java/dagger/internal/codegen/SourceFileGenerator.java
new file mode 100644
index 000000000..4b6efc0ea
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/SourceFileGenerator.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.TypeWriter;
+import java.io.IOException;
+import javax.annotation.processing.Filer;
+import javax.lang.model.element.Element;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A template class that provides a framework for properly handling IO while generating source files
+ * from an annotation processor. Particularly, it makes a best effort to ensure that files that
+ * fail to write successfully are deleted.
+ *
+ * @param <T> The input type from which source is to be generated.
+ * @author Gregory Kick
+ * @since 2.0
+ */
+abstract class SourceFileGenerator<T> {
+ private final Filer filer;
+
+ SourceFileGenerator(Filer filer) {
+ this.filer = checkNotNull(filer);
+ }
+
+ final void generate(T input) throws SourceFileGenerationException {
+ ClassName generatedTypeName = nameGeneratedType(input);
+ ImmutableSet<Element> originatingElements =
+ ImmutableSet.<Element>copyOf(getOriginatingElements(input));
+ try {
+ ImmutableSet<JavaWriter> writers = write(generatedTypeName, input);
+ for (JavaWriter javaWriter : writers) {
+ try {
+ javaWriter.file(filer, originatingElements);
+ } catch (IOException e) {
+ throw new SourceFileGenerationException(getNamesForWriters(javaWriter.getTypeWriters()),
+ e, getElementForErrorReporting(input));
+ }
+ }
+ } catch (Exception e) {
+ // if the code above threw a SFGE, use that
+ Throwables.propagateIfPossible(e, SourceFileGenerationException.class);
+ // otherwise, throw a new one
+ throw new SourceFileGenerationException(ImmutableList.<ClassName>of(), e,
+ getElementForErrorReporting(input));
+ }
+ }
+
+ private static Iterable<ClassName> getNamesForWriters(Iterable<TypeWriter> typeWriters) {
+ return Iterables.transform(typeWriters, new Function<TypeWriter, ClassName>() {
+ @Override public ClassName apply(TypeWriter input) {
+ return input.name();
+ }
+ });
+ }
+
+ /**
+ * Implementations should return the {@link ClassName} for the top-level type to be generated.
+ */
+ abstract ClassName nameGeneratedType(T input);
+
+ /**
+ * Implementations should return {@link Element} instances from which the source is to be
+ * generated.
+ */
+ abstract Iterable<? extends Element> getOriginatingElements(T input);
+
+ /**
+ * Returns an optional element to be used for reporting errors. This returns a single element
+ * rather than a collection to reduce output noise.
+ */
+ abstract Optional<? extends Element> getElementForErrorReporting(T input);
+
+ /**
+ */
+ abstract ImmutableSet<JavaWriter> write(ClassName generatedTypeName, T input);
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/SourceFiles.java b/compiler/src/main/java/dagger/internal/codegen/SourceFiles.java
new file mode 100644
index 000000000..890d3553b
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/SourceFiles.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT 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.base.CaseFormat;
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Ordering;
+import dagger.internal.DoubleCheckLazy;
+import dagger.internal.codegen.ContributionBinding.BindingType;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ParameterizedTypeName;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Types;
+
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+
+/**
+ * Utilities for generating files.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+class SourceFiles {
+ /**
+ * Sorts {@link DependencyRequest} instances in an order likely to reflect their logical
+ * importance.
+ */
+ static final Ordering<DependencyRequest> DEPENDENCY_ORDERING = new Ordering<DependencyRequest>() {
+ @Override
+ public int compare(DependencyRequest left, DependencyRequest right) {
+ return ComparisonChain.start()
+ // put fields before parameters
+ .compare(left.requestElement().getKind(), right.requestElement().getKind())
+ // order by dependency kind
+ .compare(left.kind(), right.kind())
+ // then sort by name
+ .compare(left.requestElement().getSimpleName().toString(),
+ right.requestElement().getSimpleName().toString()).result();
+ }
+ };
+
+ /**
+ * A variant of {@link #indexDependenciesByKey} that maps from unresolved keys
+ * to requests. This is used when generating component's initialize()
+ * methods (and in members injectors) in order to instantiate dependent
+ * providers. Consider a generic type of {@code Foo<T>} with a constructor
+ * of {@code Foo(T t, T t1, A a, A a1)}. That will be collapsed to a factory
+ * taking a {@code Provider<T> tProvider, Provider<A> aProvider}. However,
+ * if it was referenced as {@code Foo<A>}, we need to make sure we still
+ * pass two providers. Naively (if we just referenced by resolved BindingKey),
+ * we would have passed a single {@code aProvider}.
+ */
+ // TODO(user): Refactor these indexing methods so that the binding itself knows what sort of
+ // binding keys and framework classes that it needs.
+ static ImmutableSetMultimap<BindingKey, DependencyRequest> indexDependenciesByUnresolvedKey(
+ Types types, Iterable<? extends DependencyRequest> dependencies) {
+ ImmutableSetMultimap.Builder<BindingKey, DependencyRequest> dependenciesByKeyBuilder =
+ new ImmutableSetMultimap.Builder<BindingKey, DependencyRequest>()
+ .orderValuesBy(DEPENDENCY_ORDERING);
+ for (DependencyRequest dependency : dependencies) {
+ BindingKey resolved = dependency.bindingKey();
+ // To get the proper unresolved type, we have to extract the proper type from the
+ // request type again (because we're looking at the actual element's type).
+ TypeMirror unresolvedType =
+ DependencyRequest.Factory.extractKindAndType(dependency.requestElement().asType()).type();
+ BindingKey unresolved =
+ BindingKey.create(resolved.kind(), resolved.key().withType(types, unresolvedType));
+ dependenciesByKeyBuilder.put(unresolved, dependency);
+ }
+ return dependenciesByKeyBuilder.build();
+ }
+
+ /**
+ * Allows dependency requests to be grouped by the key they're requesting.
+ * This is used by factory generation in order to minimize the number of parameters
+ * required in the case where a given key is requested more than once. This expects
+ * unresolved dependency requests, otherwise we may generate factories based on
+ * a particular usage of a class as opposed to the generic types of the class.
+ */
+ static ImmutableSetMultimap<BindingKey, DependencyRequest> indexDependenciesByKey(
+ Iterable<? extends DependencyRequest> dependencies) {
+ ImmutableSetMultimap.Builder<BindingKey, DependencyRequest> dependenciesByKeyBuilder =
+ new ImmutableSetMultimap.Builder<BindingKey, DependencyRequest>()
+ .orderValuesBy(DEPENDENCY_ORDERING);
+ for (DependencyRequest dependency : dependencies) {
+ dependenciesByKeyBuilder.put(dependency.bindingKey(), dependency);
+ }
+ return dependenciesByKeyBuilder.build();
+ }
+
+ /**
+ * This method generates names and keys for the framework classes necessary for all of the
+ * bindings. It is responsible for the following:
+ * <ul>
+ * <li>Choosing a name that associates the binding with all of the dependency requests for this
+ * type.
+ * <li>Choosing a name that is <i>probably</i> associated with the type being bound.
+ * <li>Ensuring that no two bindings end up with the same name.
+ * </ul>
+ *
+ * @return Returns the mapping from {@link BindingKey} to field, sorted by the name of the field.
+ */
+ static ImmutableMap<BindingKey, FrameworkField> generateBindingFieldsForDependencies(
+ DependencyRequestMapper dependencyRequestMapper,
+ Iterable<? extends DependencyRequest> dependencies) {
+ ImmutableSetMultimap<BindingKey, DependencyRequest> dependenciesByKey =
+ indexDependenciesByKey(dependencies);
+ Map<BindingKey, Collection<DependencyRequest>> dependenciesByKeyMap =
+ dependenciesByKey.asMap();
+ ImmutableMap.Builder<BindingKey, FrameworkField> bindingFields = ImmutableMap.builder();
+ for (Entry<BindingKey, Collection<DependencyRequest>> entry
+ : dependenciesByKeyMap.entrySet()) {
+ BindingKey bindingKey = entry.getKey();
+ Collection<DependencyRequest> requests = entry.getValue();
+ Class<?> frameworkClass =
+ dependencyRequestMapper.getFrameworkClass(requests.iterator().next());
+ // collect together all of the names that we would want to call the provider
+ ImmutableSet<String> dependencyNames =
+ FluentIterable.from(requests).transform(new DependencyVariableNamer()).toSet();
+
+ if (dependencyNames.size() == 1) {
+ // if there's only one name, great! use it!
+ String name = Iterables.getOnlyElement(dependencyNames);
+ bindingFields.put(bindingKey,
+ FrameworkField.createWithTypeFromKey(frameworkClass, bindingKey, name));
+ } else {
+ // in the event that a field is being used for a bunch of deps with different names,
+ // add all the names together with "And"s in the middle. E.g.: stringAndS
+ Iterator<String> namesIterator = dependencyNames.iterator();
+ String first = namesIterator.next();
+ StringBuilder compositeNameBuilder = new StringBuilder(first);
+ while (namesIterator.hasNext()) {
+ compositeNameBuilder.append("And").append(
+ CaseFormat.LOWER_CAMEL.to(UPPER_CAMEL, namesIterator.next()));
+ }
+ bindingFields.put(bindingKey, FrameworkField.createWithTypeFromKey(
+ frameworkClass, bindingKey, compositeNameBuilder.toString()));
+ }
+ }
+ return bindingFields.build();
+ }
+
+ static Snippet frameworkTypeUsageStatement(Snippet frameworkTypeMemberSelect,
+ DependencyRequest.Kind dependencyKind) {
+ switch (dependencyKind) {
+ case LAZY:
+ return Snippet.format("%s.create(%s)", ClassName.fromClass(DoubleCheckLazy.class),
+ frameworkTypeMemberSelect);
+ case INSTANCE:
+ case FUTURE:
+ return Snippet.format("%s.get()", frameworkTypeMemberSelect);
+ case PROVIDER:
+ case PRODUCER:
+ case MEMBERS_INJECTOR:
+ return Snippet.format("%s", frameworkTypeMemberSelect);
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ static ClassName factoryNameForProvisionBinding(ProvisionBinding binding) {
+ TypeElement enclosingTypeElement = binding.bindingTypeElement();
+ ClassName enclosingClassName = ClassName.fromTypeElement(enclosingTypeElement);
+ switch (binding.bindingKind()) {
+ case INJECTION:
+ case PROVISION:
+ return enclosingClassName.topLevelClassName().peerNamed(
+ enclosingClassName.classFileName() + "_" + factoryPrefix(binding) + "Factory");
+ case SYNTHETIC_PROVISON:
+ throw new IllegalArgumentException();
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Returns the factory name parameterized with the ProvisionBinding's parameters (if necessary).
+ */
+ static TypeName parameterizedFactoryNameForProvisionBinding(
+ ProvisionBinding binding) {
+ ClassName factoryName = factoryNameForProvisionBinding(binding);
+ List<TypeName> parameters = ImmutableList.of();
+ if (binding.bindingType().equals(BindingType.UNIQUE)) {
+ switch(binding.bindingKind()) {
+ case INJECTION:
+ TypeName bindingName = TypeNames.forTypeMirror(binding.key().type());
+ // If the binding is parameterized, parameterize the factory.
+ if (bindingName instanceof ParameterizedTypeName) {
+ parameters = ((ParameterizedTypeName) bindingName).parameters();
+ }
+ break;
+ case PROVISION:
+ // For provision bindings, we parameterize creation on the types of
+ // the module, not the types of the binding.
+ // Consider: Module<A, B, C> { @Provides List<B> provideB(B b) { .. }}
+ // The binding is just parameterized on <B>, but we need all of <A, B, C>.
+ if (!binding.bindingTypeElement().getTypeParameters().isEmpty()) {
+ parameters = ((ParameterizedTypeName) TypeNames.forTypeMirror(
+ binding.bindingTypeElement().asType())).parameters();
+ }
+ break;
+ default: // fall through.
+ }
+ }
+ return parameters.isEmpty() ? factoryName
+ : ParameterizedTypeName.create(factoryName, parameters);
+ }
+
+ static ClassName factoryNameForProductionBinding(ProductionBinding binding) {
+ TypeElement enclosingTypeElement = binding.bindingTypeElement();
+ ClassName enclosingClassName = ClassName.fromTypeElement(enclosingTypeElement);
+ switch (binding.bindingKind()) {
+ case IMMEDIATE:
+ case FUTURE_PRODUCTION:
+ return enclosingClassName.topLevelClassName().peerNamed(
+ enclosingClassName.classFileName() + "_" + factoryPrefix(binding) + "Factory");
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Returns the members injector's name parameterized with the binding's parameters (if necessary).
+ */
+ static TypeName parameterizedMembersInjectorNameForMembersInjectionBinding(
+ MembersInjectionBinding binding) {
+ ClassName factoryName = membersInjectorNameForType(binding.bindingElement());
+ TypeName bindingName = TypeNames.forTypeMirror(binding.key().type());
+ // If the binding is parameterized, parameterize the MembersInjector.
+ if (bindingName instanceof ParameterizedTypeName) {
+ return ParameterizedTypeName.create(factoryName,
+ ((ParameterizedTypeName) bindingName).parameters());
+ }
+ return factoryName;
+ }
+
+ static ClassName membersInjectorNameForType(TypeElement typeElement) {
+ ClassName injectedClassName = ClassName.fromTypeElement(typeElement);
+ return injectedClassName
+ .topLevelClassName()
+ .peerNamed(injectedClassName.classFileName() + "_MembersInjector");
+ }
+
+ private static String factoryPrefix(ProvisionBinding binding) {
+ switch (binding.bindingKind()) {
+ case INJECTION:
+ return "";
+ case PROVISION:
+ return CaseFormat.LOWER_CAMEL.to(UPPER_CAMEL,
+ ((ExecutableElement) binding.bindingElement()).getSimpleName().toString());
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private static String factoryPrefix(ProductionBinding binding) {
+ switch (binding.bindingKind()) {
+ case IMMEDIATE:
+ case FUTURE_PRODUCTION:
+ return CaseFormat.LOWER_CAMEL.to(UPPER_CAMEL,
+ ((ExecutableElement) binding.bindingElement()).getSimpleName().toString());
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private SourceFiles() {}
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/SubcomponentWriter.java b/compiler/src/main/java/dagger/internal/codegen/SubcomponentWriter.java
new file mode 100644
index 000000000..8cb31b92d
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/SubcomponentWriter.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreTypes;
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import dagger.internal.codegen.ComponentDescriptor.BuilderSpec;
+import dagger.internal.codegen.ComponentGenerator.MemberSelect;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ClassWriter;
+import dagger.internal.codegen.writer.FieldWriter;
+import dagger.internal.codegen.writer.MethodWriter;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import java.util.List;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+
+import static com.google.common.base.CaseFormat.LOWER_CAMEL;
+import static com.google.common.base.Verify.verify;
+import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.UNINITIALIZED;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+/**
+ * Creates the nested implementation class for a subcomponent.
+ */
+class SubcomponentWriter extends AbstractComponentWriter {
+
+ private AbstractComponentWriter parent;
+ private ExecutableElement subcomponentFactoryMethod;
+
+ public SubcomponentWriter(
+ AbstractComponentWriter parent,
+ ExecutableElement subcomponentFactoryMethod,
+ BindingGraph subgraph) {
+ super(
+ parent.types,
+ parent.elements,
+ parent.keyFactory,
+ parent.nullableValidationType,
+ parent.name.nestedClassNamed(subcomponentSimpleName(subgraph)),
+ subgraph);
+ this.parent = parent;
+ this.subcomponentFactoryMethod = subcomponentFactoryMethod;
+ }
+
+ private static String subcomponentSimpleName(BindingGraph subgraph) {
+ return subgraph.componentDescriptor().componentDefinitionType().getSimpleName() + "Impl";
+ }
+
+ @Override
+ protected InitializationState getInitializationState(BindingKey bindingKey) {
+ InitializationState initializationState = super.getInitializationState(bindingKey);
+ return initializationState.equals(UNINITIALIZED)
+ ? parent.getInitializationState(bindingKey)
+ : initializationState;
+ }
+
+ @Override
+ protected Optional<Snippet> getOrCreateComponentContributionFieldSnippet(
+ TypeElement contributionType) {
+ return super.getOrCreateComponentContributionFieldSnippet(contributionType)
+ .or(parent.getOrCreateComponentContributionFieldSnippet(contributionType));
+ }
+
+ @Override
+ protected MemberSelect getMemberSelect(BindingKey key) {
+ MemberSelect memberSelect = super.getMemberSelect(key);
+ return memberSelect == null ? parent.getMemberSelect(key) : memberSelect;
+ }
+
+ @Override
+ protected Optional<MemberSelect> getMultibindingContributionSnippet(ContributionBinding binding) {
+ return super.getMultibindingContributionSnippet(binding)
+ .or(parent.getMultibindingContributionSnippet(binding));
+ }
+
+ private ExecutableType resolvedSubcomponentFactoryMethod() {
+ return MoreTypes.asExecutable(
+ types.asMemberOf(
+ MoreTypes.asDeclared(parent.componentDefinitionType().asType()),
+ subcomponentFactoryMethod));
+ }
+
+ @Override
+ protected ClassWriter createComponentClass() {
+ ClassWriter componentWriter = parent.componentWriter.addNestedClass(name.simpleName());
+ componentWriter.addModifiers(PRIVATE, FINAL);
+ componentWriter.setSupertype(
+ MoreTypes.asTypeElement(
+ graph.componentDescriptor().builderSpec().isPresent()
+ ? graph
+ .componentDescriptor()
+ .builderSpec()
+ .get()
+ .componentType()
+ : resolvedSubcomponentFactoryMethod().getReturnType()));
+ return componentWriter;
+ }
+
+ @Override
+ protected void addBuilder() {
+ // Only write subcomponent builders if there is a spec.
+ if (graph.componentDescriptor().builderSpec().isPresent()) {
+ super.addBuilder();
+ }
+ }
+
+ @Override
+ protected ClassWriter createBuilder() {
+ // Only write subcomponent builders if there is a spec.
+ verify(graph.componentDescriptor().builderSpec().isPresent());
+ return parent.componentWriter.addNestedClass(
+ componentDefinitionTypeName().simpleName() + "Builder");
+ }
+
+ @Override
+ protected void addFactoryMethods() {
+ MethodWriter componentMethod;
+ if (graph.componentDescriptor().builderSpec().isPresent()) {
+ BuilderSpec spec = graph.componentDescriptor().builderSpec().get();
+ componentMethod =
+ parent.componentWriter.addMethod(
+ spec.builderDefinitionType().asType(),
+ subcomponentFactoryMethod.getSimpleName().toString());
+ componentMethod.body().addSnippet("return new %s();", builderName.get());
+ } else {
+ ExecutableType resolvedMethod = resolvedSubcomponentFactoryMethod();
+ componentMethod =
+ parent.componentWriter.addMethod(
+ resolvedMethod.getReturnType(), subcomponentFactoryMethod.getSimpleName().toString());
+ writeSubcomponentWithoutBuilder(componentMethod, resolvedMethod);
+ }
+ componentMethod.addModifiers(PUBLIC);
+ componentMethod.annotate(Override.class);
+ }
+
+ private void writeSubcomponentWithoutBuilder(
+ MethodWriter componentMethod, ExecutableType resolvedMethod) {
+ ImmutableList.Builder<Snippet> subcomponentConstructorParameters = ImmutableList.builder();
+ List<? extends VariableElement> params = subcomponentFactoryMethod.getParameters();
+ List<? extends TypeMirror> paramTypes = resolvedMethod.getParameterTypes();
+ for (int i = 0; i < params.size(); i++) {
+ VariableElement moduleVariable = params.get(i);
+ TypeElement moduleTypeElement = MoreTypes.asTypeElement(paramTypes.get(i));
+ TypeName moduleType = TypeNames.forTypeMirror(paramTypes.get(i));
+ componentMethod.addParameter(moduleType, moduleVariable.getSimpleName().toString());
+ if (!componentContributionFields.containsKey(moduleTypeElement)) {
+ String preferredModuleName =
+ CaseFormat.UPPER_CAMEL.to(LOWER_CAMEL, moduleTypeElement.getSimpleName().toString());
+ FieldWriter contributionField =
+ componentWriter.addField(moduleTypeElement, preferredModuleName);
+ contributionField.addModifiers(PRIVATE, FINAL);
+ String actualModuleName = contributionField.name();
+ constructorWriter.addParameter(moduleType, actualModuleName);
+ constructorWriter.body()
+ .addSnippet("if (%s == null) {", actualModuleName)
+ .addSnippet(" throw new NullPointerException();")
+ .addSnippet("}");
+ constructorWriter.body().addSnippet("this.%1$s = %1$s;", actualModuleName);
+ MemberSelect moduleSelect =
+ MemberSelect.instanceSelect(name, Snippet.format(actualModuleName));
+ componentContributionFields.put(moduleTypeElement, moduleSelect);
+ subcomponentConstructorParameters.add(Snippet.format("%s", moduleVariable.getSimpleName()));
+ }
+ }
+
+ ImmutableSet<TypeElement> uninitializedModules =
+ FluentIterable.from(graph.componentDescriptor().transitiveModules())
+ .transform(ModuleDescriptor.getModuleElement())
+ .filter(Predicates.not(Predicates.in(componentContributionFields.keySet())))
+ .toSet();
+
+ for (TypeElement moduleType : uninitializedModules) {
+ String preferredModuleName =
+ CaseFormat.UPPER_CAMEL.to(LOWER_CAMEL, moduleType.getSimpleName().toString());
+ FieldWriter contributionField = componentWriter.addField(moduleType, preferredModuleName);
+ contributionField.addModifiers(PRIVATE, FINAL);
+ String actualModuleName = contributionField.name();
+ constructorWriter.body().addSnippet("this.%s = new %s();",
+ actualModuleName, ClassName.fromTypeElement(moduleType));
+ MemberSelect moduleSelect =
+ MemberSelect.instanceSelect(name, Snippet.format(actualModuleName));
+ componentContributionFields.put(moduleType, moduleSelect);
+ }
+
+ componentMethod.body().addSnippet("return new %s(%s);",
+ name, Snippet.makeParametersSnippet(subcomponentConstructorParameters.build()));
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/Util.java b/compiler/src/main/java/dagger/internal/codegen/Util.java
new file mode 100644
index 000000000..faa0459c4
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/Util.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2013 Google, Inc.
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreTypes;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Equivalence.Wrapper;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Provider;
+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.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+
+import static com.google.auto.common.MoreElements.getLocalAndInheritedMethods;
+import static com.google.auto.common.MoreTypes.asDeclared;
+import static com.google.common.base.Preconditions.checkState;
+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;
+
+/**
+ * Utilities for handling types in annotation processors
+ */
+final class Util {
+ /**
+ * Returns the {@code V} type for a {@link Map} type like Map<K, Provider<V>>} if the map
+ * includes such a construction
+ */
+ public static DeclaredType getProvidedValueTypeOfMap(DeclaredType mapType) {
+ checkState(MoreTypes.isTypeOf(Map.class, mapType), "%s is not a Map.", mapType);
+ return asDeclared(asDeclared(mapType.getTypeArguments().get(1)).getTypeArguments().get(0));
+ }
+
+ // TODO(cgruber): Consider an object that holds and exposes the various parts of a Map type.
+ /**
+ * returns the value type for a {@link Map} type like Map<K, V>}.
+ */
+ public static DeclaredType getValueTypeOfMap(DeclaredType mapType) {
+ checkState(MoreTypes.isTypeOf(Map.class, mapType), "%s is not a Map.", mapType);
+ List<? extends TypeMirror> mapArgs = mapType.getTypeArguments();
+ return asDeclared(mapArgs.get(1));
+ }
+
+ /**
+ * Returns the key type for a {@link Map} type like Map<K, Provider<V>>}
+ */
+ public static DeclaredType getKeyTypeOfMap(DeclaredType mapType) {
+ checkState(MoreTypes.isTypeOf(Map.class, mapType), "%s is not a Map.", mapType);
+ List<? extends TypeMirror> mapArgs = mapType.getTypeArguments();
+ return MoreTypes.asDeclared(mapArgs.get(0));
+ }
+
+ /**
+ * Returns true if {@code type} is a {@link Map} whose value type is not a {@link Provider}.
+ */
+ public static boolean isMapWithNonProvidedValues(TypeMirror type) {
+ return MoreTypes.isType(type)
+ && MoreTypes.isTypeOf(Map.class, type)
+ && !MoreTypes.isTypeOf(Provider.class, asDeclared(type).getTypeArguments().get(1));
+ }
+
+ /**
+ * Returns true if {@code type} is a {@link Map} whose value type is a {@link Provider}.
+ */
+ public static boolean isMapWithProvidedValues(TypeMirror type) {
+ return MoreTypes.isType(type)
+ && MoreTypes.isTypeOf(Map.class, type)
+ && MoreTypes.isTypeOf(Provider.class, asDeclared(type).getTypeArguments().get(1));
+ }
+
+ /**
+ * Wraps an {@link Optional} of a type in an {@code Optional} of a {@link Wrapper} for that type.
+ */
+ static <T> Optional<Equivalence.Wrapper<T>> wrapOptionalInEquivalence(
+ Equivalence<T> equivalence, Optional<T> optional) {
+ return optional.isPresent()
+ ? Optional.of(equivalence.wrap(optional.get()))
+ : Optional.<Equivalence.Wrapper<T>>absent();
+ }
+
+ /**
+ * Unwraps an {@link Optional} of a {@link Wrapper} into an {@code Optional} of the underlying
+ * type.
+ */
+ static <T> Optional<T> unwrapOptionalEquivalence(
+ Optional<Equivalence.Wrapper<T>> wrappedOptional) {
+ return wrappedOptional.isPresent()
+ ? Optional.of(wrappedOptional.get().get())
+ : Optional.<T>absent();
+ }
+
+ 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;
+ default:
+ throw new AssertionError("TypeElement cannot have nesting kind: "
+ + typeElement.getNestingKind());
+ }
+ }
+
+ /**
+ * Returns true if and only if a component can instantiate new instances (typically of a module)
+ * rather than requiring that they be passed.
+ */
+ static boolean componentCanMakeNewInstances(TypeElement typeElement) {
+ switch (typeElement.getKind()) {
+ case CLASS:
+ break;
+ case ENUM:
+ case ANNOTATION_TYPE:
+ case INTERFACE:
+ return false;
+ default:
+ throw new AssertionError("TypeElement cannot have kind: " + typeElement.getKind());
+ }
+
+ if (typeElement.getModifiers().contains(ABSTRACT)) {
+ return false;
+ }
+
+ if (requiresEnclosingInstance(typeElement)) {
+ return false;
+ }
+
+ for (Element enclosed : typeElement.getEnclosedElements()) {
+ if (enclosed.getKind().equals(CONSTRUCTOR)
+ && ((ExecutableElement) enclosed).getParameters().isEmpty()
+ && !enclosed.getModifiers().contains(PRIVATE)) {
+ return true;
+ }
+ }
+
+ // TODO(gak): still need checks for visibility
+
+ return false;
+ }
+
+ static ImmutableSet<ExecutableElement> getUnimplementedMethods(
+ Elements elements, TypeElement type) {
+ ImmutableSet.Builder<ExecutableElement> unimplementedMethods = ImmutableSet.builder();
+ Set<ExecutableElement> methods = getLocalAndInheritedMethods(type, elements);
+ for (ExecutableElement method : methods) {
+ if (method.getModifiers().contains(Modifier.ABSTRACT)) {
+ unimplementedMethods.add(method);
+ }
+ }
+ return unimplementedMethods.build();
+ }
+
+ private Util() {}
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ValidationReport.java b/compiler/src/main/java/dagger/internal/codegen/ValidationReport.java
new file mode 100644
index 000000000..e17406755
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ValidationReport.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.value.AutoValue;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.util.SimpleElementVisitor6;
+import javax.tools.Diagnostic;
+import javax.tools.Diagnostic.Kind;
+
+import static javax.tools.Diagnostic.Kind.ERROR;
+import static javax.tools.Diagnostic.Kind.NOTE;
+import static javax.tools.Diagnostic.Kind.WARNING;
+
+/**
+ * A collection of items describing contractual issues with the code as presented to an annotation
+ * processor. A "clean" report (i.e. with no issues) is a report with no {@linkplain Item items}
+ * and clean subreports. Callers will typically print the results of the report to a
+ * {@link Messager} instance using {@link #printMessagesTo}.
+ *
+ * <p>A report describes a subject {@link Element}. Callers may choose to add report items about
+ * other elements that are contained within or related to the subject. Since {@link Diagnostic}
+ * reporting is expected to be associated with elements that are currently being compiled,
+ * {@link #printMessagesTo(Messager)} will only associate messages with non-subject elements if they
+ * are contained within the subject. Otherwise, they will be associated with the subject and contain
+ * a reference to the item's element in the message string. It is the responsibility of the caller
+ * to choose subjects that are part of the compilation.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@AutoValue
+abstract class ValidationReport<T extends Element> {
+ abstract T subject();
+ abstract ImmutableSet<Item> items();
+ abstract ImmutableSet<ValidationReport<?>> subreports();
+
+ boolean isClean() {
+ for (Item item : items()) {
+ switch (item.kind()) {
+ case ERROR:
+ return false;
+ default:
+ break;
+ }
+ }
+ for (ValidationReport<?> subreport : subreports()) {
+ if (!subreport.isClean()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void printMessagesTo(Messager messager) {
+ for (Item item : items()) {
+ if (isEnclosedIn(subject(), item.element())) {
+ if (item.annotation().isPresent()) {
+ messager.printMessage(
+ item.kind(), item.message(), item.element(), item.annotation().get());
+ } else {
+ messager.printMessage(item.kind(), item.message(), item.element());
+ }
+ } else {
+ String message = String.format("[%s] %s", elementString(item.element()), item.message());
+ if (item.annotation().isPresent()) {
+ messager.printMessage(item.kind(), message, subject(), item.annotation().get());
+ } else {
+ messager.printMessage(item.kind(), message, subject());
+ }
+ }
+ }
+ for (ValidationReport<?> subreport : subreports()) {
+ subreport.printMessagesTo(messager);
+ }
+ }
+
+ private static String elementString(Element element) {
+ return element.accept(
+ new SimpleElementVisitor6<String, Void>() {
+ @Override
+ protected String defaultAction(Element e, Void p) {
+ return e.toString();
+ }
+
+ @Override
+ public String visitExecutable(ExecutableElement e, Void p) {
+ return e.getEnclosingElement().accept(this, null) + '.' + e.toString();
+ }
+ },
+ null);
+ }
+
+ 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;
+ }
+
+ @AutoValue
+ static abstract class Item {
+ abstract String message();
+ abstract Kind kind();
+ abstract Element element();
+ abstract Optional<AnnotationMirror> annotation();
+ }
+
+ static <T extends Element> Builder<T> about(T subject) {
+ return new Builder<T>(subject);
+ }
+
+ static final class Builder<T extends Element> {
+ private final T subject;
+ private final ImmutableSet.Builder<Item> items = ImmutableSet.builder();
+ private final ImmutableSet.Builder<ValidationReport<?>> subreports = ImmutableSet.builder();
+
+ private Builder(T subject) {
+ this.subject = subject;
+ }
+
+ T getSubject() {
+ return subject;
+ }
+
+ Builder<T> addItems(Iterable<Item> newItems) {
+ items.addAll(newItems);
+ return this;
+ }
+
+ Builder<T> addError(String message) {
+ addItem(message, ERROR, subject, Optional.<AnnotationMirror>absent());
+ return this;
+ }
+
+ Builder<T> addError(String message, Element element) {
+ addItem(message, ERROR, element, Optional.<AnnotationMirror>absent());
+ return this;
+ }
+
+ Builder<T> addError(String message, Element element, AnnotationMirror annotation) {
+ addItem(message, ERROR, element, Optional.of(annotation));
+ return this;
+ }
+
+ Builder<T> addWarning(String message) {
+ addItem(message, WARNING, subject, Optional.<AnnotationMirror>absent());
+ return this;
+ }
+
+ Builder<T> addWarning(String message, Element element) {
+ addItem(message, WARNING, element, Optional.<AnnotationMirror>absent());
+ return this;
+ }
+
+ Builder<T> addWarning(String message, Element element, AnnotationMirror annotation) {
+ addItem(message, WARNING, element, Optional.of(annotation));
+ return this;
+ }
+
+ Builder<T> addNote(String message) {
+ addItem(message, NOTE, subject, Optional.<AnnotationMirror>absent());
+ return this;
+ }
+
+ Builder<T> addNote(String message, Element element) {
+ addItem(message, NOTE, element, Optional.<AnnotationMirror>absent());
+ return this;
+ }
+
+ Builder<T> addNote(String message, Element element, AnnotationMirror annotation) {
+ addItem(message, NOTE, element, Optional.of(annotation));
+ return this;
+ }
+
+ Builder<T> addItem(String message, Kind kind, Element element) {
+ addItem(message, kind, element, Optional.<AnnotationMirror>absent());
+ return this;
+ }
+
+ Builder<T> addItem(String message, Kind kind, Element element, AnnotationMirror annotation) {
+ addItem(message, kind, element, Optional.of(annotation));
+ return this;
+ }
+
+ private Builder<T> addItem(String message, Kind kind, Element element,
+ Optional<AnnotationMirror> annotation) {
+ items.add(new AutoValue_ValidationReport_Item(message, kind, element, annotation));
+ return this;
+ }
+
+ Builder<T> addSubreport(ValidationReport<?> subreport) {
+ subreports.add(subreport);
+ return this;
+ }
+
+ ValidationReport<T> build() {
+ return new AutoValue_ValidationReport<T>(subject, items.build(), subreports.build());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ValidationType.java b/compiler/src/main/java/dagger/internal/codegen/ValidationType.java
new file mode 100644
index 000000000..d60207241
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ValidationType.java
@@ -0,0 +1,40 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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.base.Optional;
+import javax.tools.Diagnostic;
+
+/**
+ * Allows options to control how component process validates things such as scope cycles
+ * or nullability.
+ */
+enum ValidationType {
+ ERROR,
+ WARNING,
+ NONE;
+
+ Optional<Diagnostic.Kind> diagnosticKind() {
+ switch (this) {
+ case ERROR:
+ return Optional.of(Diagnostic.Kind.ERROR);
+ case WARNING:
+ return Optional.of(Diagnostic.Kind.WARNING);
+ default:
+ return Optional.absent();
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/AnnotationWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/AnnotationWriter.java
new file mode 100644
index 000000000..b2cb45134
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/AnnotationWriter.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import java.io.IOException;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedMap;
+
+import static dagger.internal.codegen.writer.Writables.toStringWritable;
+
+public final class AnnotationWriter implements Writable, HasClassReferences {
+ private final ClassName annotationName;
+ private final SortedMap<String, Writable> memberMap = Maps.newTreeMap();
+
+ AnnotationWriter(ClassName annotationName) {
+ this.annotationName = annotationName;
+ }
+
+ public void setValue(String value) {
+ setMember("value", value);
+ }
+
+ public void setMember(String name, int value) {
+ memberMap.put(name, toStringWritable(value));
+ }
+
+ public void setMember(String name, String value) {
+ memberMap.put(name, toStringWritable(StringLiteral.forValue(value)));
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ appendable.append('@');
+ annotationName.write(appendable, context);
+ if (!memberMap.isEmpty()) {
+ appendable.append('(');
+ if (memberMap.size() == 1) {
+ Entry<String, Writable> onlyEntry = Iterables.getOnlyElement(memberMap.entrySet());
+ if (!onlyEntry.getKey().equals("value")) {
+ appendable.append(onlyEntry.getKey()).append(" = ");
+ }
+ onlyEntry.getValue().write(appendable, context);
+ }
+ appendable.append(')');
+ }
+ return appendable;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return ImmutableSet.of(annotationName);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/ArrayTypeName.java b/compiler/src/main/java/dagger/internal/codegen/writer/ArrayTypeName.java
new file mode 100644
index 000000000..e7960629e
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/ArrayTypeName.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import java.io.IOException;
+import java.util.Set;
+
+final class ArrayTypeName implements TypeName {
+ private final TypeName componentType;
+
+ ArrayTypeName(TypeName componentType) {
+ this.componentType = componentType;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return componentType.referencedClasses();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ return componentType.write(appendable, context).append("[]");
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof ArrayTypeName)
+ && this.componentType.equals(((ArrayTypeName) obj).componentType);
+ }
+
+ @Override
+ public int hashCode() {
+ return componentType.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return Writables.writeToString(this);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/BlockWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/BlockWriter.java
new file mode 100644
index 000000000..c00dd5f07
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/BlockWriter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Lists;
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+
+public final class BlockWriter implements Writable, HasClassReferences {
+ private final List<Snippet> snippets;
+
+ BlockWriter() {
+ this.snippets = Lists.newArrayList();
+ }
+
+ public BlockWriter addSnippet(String snippet, Object... args) {
+ snippets.add(Snippet.format(snippet, args));
+ return this;
+ }
+
+ public BlockWriter addSnippet(Snippet snippet) {
+ snippets.add(snippet);
+ return this;
+ }
+
+ boolean isEmpty() {
+ return snippets.isEmpty();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ for (Snippet snippet : snippets) {
+ appendable.append('\n');
+ snippet.write(appendable, context);
+ }
+ return appendable.append('\n');
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(snippets)
+ .transformAndConcat(new Function<HasClassReferences, Set<ClassName>>() {
+ @Override
+ public Set<ClassName> apply(HasClassReferences input) {
+ return input.referencedClasses();
+ }
+ })
+ .toSet();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/ClassName.java b/compiler/src/main/java/dagger/internal/codegen/writer/ClassName.java
new file mode 100644
index 000000000..5b7776853
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/ClassName.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.base.Ascii;
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.NestingKind;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static javax.lang.model.element.NestingKind.MEMBER;
+import static javax.lang.model.element.NestingKind.TOP_LEVEL;
+
+/**
+ * Represents a fully-qualified class name for {@link NestingKind#TOP_LEVEL} and
+ * {@link NestingKind#MEMBER} classes.
+ *
+ * @since 2.0
+ */
+public final class ClassName implements TypeName, Comparable<ClassName> {
+ private String fullyQualifiedName = null;
+ private final String packageName;
+ /* From top to bottom. E.g.: this field will contain ["A", "B"] for pgk.A.B.C */
+ private final ImmutableList<String> enclosingSimpleNames;
+ private final String simpleName;
+
+ private ClassName(String packageName, ImmutableList<String> enclosingSimpleNames,
+ String simpleName) {
+ this.packageName = packageName;
+ this.enclosingSimpleNames = enclosingSimpleNames;
+ this.simpleName = simpleName;
+ }
+
+ public String packageName() {
+ return packageName;
+ }
+
+ public ImmutableList<String> enclosingSimpleNames() {
+ return enclosingSimpleNames;
+ }
+
+ public Optional<ClassName> enclosingClassName() {
+ return enclosingSimpleNames.isEmpty()
+ ? Optional.<ClassName>absent()
+ : Optional.of(new ClassName(packageName,
+ enclosingSimpleNames.subList(0, enclosingSimpleNames.size() - 1),
+ enclosingSimpleNames.get(enclosingSimpleNames.size() - 1)));
+ }
+
+ public String simpleName() {
+ return simpleName;
+ }
+
+ public String canonicalName() {
+ if (fullyQualifiedName == null) {
+ StringBuilder builder = new StringBuilder(packageName());
+ if (builder.length() > 0) {
+ builder.append('.');
+ }
+ for (String enclosingSimpleName : enclosingSimpleNames()) {
+ builder.append(enclosingSimpleName).append('.');
+ }
+ fullyQualifiedName = builder.append(simpleName()).toString();
+ }
+ return fullyQualifiedName;
+ }
+
+ /**
+ * Equivalent to {@link #classFileName(char) classFileName('$')}
+ */
+ public String classFileName() {
+ return classFileName('$');
+ }
+
+ /**
+ * Returns the class name (excluding package).
+ *
+ * <p>The returned value includes the names of its enclosing classes (if any) but not the package
+ * name. e.g. {@code fromClass(Map.Entry.class).classFileName('_')} will return {@code Map_Entry}.
+ */
+ public String classFileName(char separator) {
+ StringBuilder builder = new StringBuilder();
+ for (String enclosingSimpleName : enclosingSimpleNames) {
+ builder.append(enclosingSimpleName).append(separator);
+ }
+ return builder.append(simpleName()).toString();
+ }
+
+ public ClassName topLevelClassName() {
+ Iterator<String> enclosingIterator = enclosingSimpleNames().iterator();
+ return enclosingIterator.hasNext()
+ ? new ClassName(packageName(), ImmutableList.<String>of(),
+ enclosingIterator.next())
+ : this;
+ }
+
+ public ClassName nestedClassNamed(String memberClassName) {
+ checkNotNull(memberClassName);
+ checkArgument(SourceVersion.isIdentifier(memberClassName));
+ checkArgument(Ascii.isUpperCase(memberClassName.charAt(0)));
+ return new ClassName(packageName(),
+ new ImmutableList.Builder<String>()
+ .addAll(enclosingSimpleNames())
+ .add(simpleName())
+ .build(),
+ memberClassName);
+ }
+
+ public ClassName peerNamed(String peerClassName) {
+ checkNotNull(peerClassName);
+ checkArgument(SourceVersion.isIdentifier(peerClassName));
+ checkArgument(Ascii.isUpperCase(peerClassName.charAt(0)));
+ return new ClassName(packageName(), enclosingSimpleNames(), peerClassName);
+ }
+
+ private static final ImmutableSet<NestingKind> ACCEPTABLE_NESTING_KINDS =
+ Sets.immutableEnumSet(TOP_LEVEL, MEMBER);
+
+ public static ClassName fromTypeElement(TypeElement element) {
+ checkNotNull(element);
+ checkArgument(ACCEPTABLE_NESTING_KINDS.contains(element.getNestingKind()));
+ String simpleName = element.getSimpleName().toString();
+ List<String> enclosingNames = new ArrayList<String>();
+ Element current = element.getEnclosingElement();
+ while (current.getKind().isClass() || current.getKind().isInterface()) {
+ checkArgument(ACCEPTABLE_NESTING_KINDS.contains(element.getNestingKind()));
+ enclosingNames.add(current.getSimpleName().toString());
+ current = current.getEnclosingElement();
+ }
+ PackageElement packageElement = getPackage(current);
+ Collections.reverse(enclosingNames);
+ return new ClassName(packageElement.getQualifiedName().toString(),
+ ImmutableList.copyOf(enclosingNames), simpleName);
+ }
+
+ public static ClassName fromClass(Class<?> clazz) {
+ checkNotNull(clazz);
+ List<String> enclosingNames = new ArrayList<String>();
+ Class<?> current = clazz.getEnclosingClass();
+ while (current != null) {
+ enclosingNames.add(current.getSimpleName());
+ current = current.getEnclosingClass();
+ }
+ Collections.reverse(enclosingNames);
+ return create(clazz.getPackage().getName(), enclosingNames, clazz.getSimpleName());
+ }
+
+ private static PackageElement getPackage(Element type) {
+ while (type.getKind() != ElementKind.PACKAGE) {
+ type = type.getEnclosingElement();
+ }
+ return (PackageElement) type;
+ }
+
+ /**
+ * Returns a new {@link ClassName} instance for the given fully-qualified class name string. This
+ * method assumes that the input is ASCII and follows typical Java style (lower-case package
+ * names, upper-camel-case class names) and may produce incorrect results or throw
+ * {@link IllegalArgumentException} otherwise. For that reason, {@link #fromClass(Class)} and
+ * {@link #fromClass(Class)} should be preferred as they can correctly create {@link ClassName}
+ * instances without such restrictions.
+ */
+ public static ClassName bestGuessFromString(String classNameString) {
+ checkNotNull(classNameString);
+ List<String> parts = Splitter.on('.').splitToList(classNameString);
+ int firstClassPartIndex = -1;
+ for (int i = 0; i < parts.size(); i++) {
+ String part = parts.get(i);
+ checkArgument(SourceVersion.isIdentifier(part));
+ char firstChar = part.charAt(0);
+ if (Ascii.isLowerCase(firstChar)) {
+ // looks like a package part
+ if (firstClassPartIndex >= 0) {
+ throw new IllegalArgumentException("couldn't make a guess for " + classNameString);
+ }
+ } else if (Ascii.isUpperCase(firstChar)) {
+ // looks like a class part
+ if (firstClassPartIndex < 0) {
+ firstClassPartIndex = i;
+ }
+ } else {
+ throw new IllegalArgumentException("couldn't make a guess for " + classNameString);
+ }
+ }
+ int lastIndex = parts.size() - 1;
+ return new ClassName(
+ Joiner.on('.').join(parts.subList(0, firstClassPartIndex)),
+ firstClassPartIndex == lastIndex
+ ? ImmutableList.<String>of()
+ : ImmutableList.copyOf(parts.subList(firstClassPartIndex, lastIndex)),
+ parts.get(lastIndex));
+ }
+
+ public static ClassName create(
+ String packageName, List<String> enclosingSimpleNames, String simpleName) {
+ return new ClassName(packageName, ImmutableList.copyOf(enclosingSimpleNames),
+ simpleName);
+ }
+
+ public static ClassName create(String packageName, String simpleName) {
+ return new ClassName(packageName, ImmutableList.<String>of(), simpleName);
+ }
+
+ @Override
+ public String toString() {
+ return canonicalName();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ appendable.append(context.sourceReferenceForClassName(this));
+ return appendable;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ } else if (obj instanceof ClassName) {
+ ClassName that = (ClassName) obj;
+ return this.packageName.equals(that.packageName)
+ && this.enclosingSimpleNames.equals(that.enclosingSimpleNames)
+ && this.simpleName.equals(that.simpleName);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(packageName, enclosingSimpleNames, simpleName);
+ }
+
+ @Override
+ public int compareTo(ClassName o) {
+ return canonicalName().compareTo(o.canonicalName());
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return ImmutableSet.of(this);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/ClassWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/ClassWriter.java
new file mode 100644
index 000000000..edaba3a2d
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/ClassWriter.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+
+import static com.google.common.base.Preconditions.checkState;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PROTECTED;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+public final class ClassWriter extends TypeWriter {
+ private Optional<TypeName> superclass;
+ private final List<ConstructorWriter> constructorWriters;
+ private final List<TypeVariableName> typeParameters;
+
+ ClassWriter(ClassName className) {
+ super(className);
+ this.superclass = Optional.absent();
+ this.constructorWriters = Lists.newArrayList();
+ this.typeParameters = Lists.newArrayList();
+ }
+
+ public void setSuperclass(TypeName typeReference) {
+ checkState(!superclass.isPresent());
+ superclass = Optional.of(typeReference);
+ }
+
+ /**
+ * If {@code supertype} is a class, makes this class extend it; if it is an interface, makes this
+ * class implement it.
+ */
+ public void setSupertype(TypeElement supertype) {
+ switch (supertype.getKind()) {
+ case CLASS:
+ setSuperclass(ClassName.fromTypeElement(supertype));
+ break;
+ case INTERFACE:
+ addImplementedType(supertype);
+ break;
+ default:
+ throw new IllegalArgumentException(supertype + " must be a class or interface");
+ }
+ }
+
+ public ConstructorWriter addConstructor() {
+ ConstructorWriter constructorWriter = new ConstructorWriter(name.simpleName());
+ constructorWriters.add(constructorWriter);
+ return constructorWriter;
+ }
+
+ public void addTypeParameter(TypeVariableName typeVariableName) {
+ this.typeParameters.add(typeVariableName);
+ }
+
+ public void addTypeParameters(Iterable<TypeVariableName> typeVariableNames) {
+ Iterables.addAll(typeParameters, typeVariableNames);
+ }
+
+ public List<TypeVariableName> typeParameters() {
+ return ImmutableList.copyOf(typeParameters);
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ context = context.createSubcontext(FluentIterable.from(nestedTypeWriters)
+ .transform(new Function<TypeWriter, ClassName>() {
+ @Override public ClassName apply(TypeWriter input) {
+ return input.name;
+ }
+ })
+ .toSet());
+ writeAnnotations(appendable, context);
+ writeModifiers(appendable).append("class ").append(name.simpleName());
+ Writables.join(", ", typeParameters, "<", ">", appendable, context);
+ if (superclass.isPresent()) {
+ appendable.append(" extends ");
+ superclass.get().write(appendable, context);
+ }
+ Writables.join(", ", implementedTypes, " implements ", "", appendable, context);
+ appendable.append(" {");
+ if (!fieldWriters.isEmpty()) {
+ appendable.append('\n');
+ }
+ for (VariableWriter fieldWriter : fieldWriters.values()) {
+ fieldWriter.write(new IndentingAppendable(appendable), context).append("\n");
+ }
+ for (ConstructorWriter constructorWriter : constructorWriters) {
+ appendable.append('\n');
+ if (!isDefaultConstructor(constructorWriter)) {
+ constructorWriter.write(new IndentingAppendable(appendable), context);
+ }
+ }
+ for (MethodWriter methodWriter : methodWriters) {
+ appendable.append('\n');
+ methodWriter.write(new IndentingAppendable(appendable), context);
+ }
+ for (TypeWriter nestedTypeWriter : nestedTypeWriters) {
+ appendable.append('\n');
+ nestedTypeWriter.write(new IndentingAppendable(appendable), context);
+ }
+ appendable.append("}\n");
+ return appendable;
+ }
+
+ private static final Set<Modifier> VISIBILIY_MODIFIERS =
+ Sets.immutableEnumSet(PUBLIC, PROTECTED, PRIVATE);
+
+ private boolean isDefaultConstructor(ConstructorWriter constructorWriter) {
+ return Sets.intersection(VISIBILIY_MODIFIERS, modifiers)
+ .equals(Sets.intersection(VISIBILIY_MODIFIERS, constructorWriter.modifiers))
+ && constructorWriter.body().isEmpty();
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(ImmutableList.<HasClassReferences>of())
+ .append(nestedTypeWriters)
+ .append(fieldWriters.values())
+ .append(constructorWriters)
+ .append(methodWriters)
+ .append(implementedTypes)
+ .append(superclass.asSet())
+ .append(annotations)
+ .append(typeParameters)
+ .transformAndConcat(HasClassReferences.COMBINER)
+ .toSet();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/ConstructorWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/ConstructorWriter.java
new file mode 100644
index 000000000..387c1ddf1
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/ConstructorWriter.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+import javax.lang.model.element.TypeElement;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public final class ConstructorWriter extends Modifiable implements Writable, HasClassReferences {
+ private final String name;
+ private final Map<String, VariableWriter> parameterWriters;
+ private final BlockWriter blockWriter;
+
+ ConstructorWriter(String name) {
+ this.name = name;
+ this.parameterWriters = Maps.newLinkedHashMap();
+ this.blockWriter = new BlockWriter();
+ }
+
+ public VariableWriter addParameter(Class<?> type, String name) {
+ return addParameter(ClassName.fromClass(type), name);
+ }
+
+ public VariableWriter addParameter(TypeElement type, String name) {
+ return addParameter(ClassName.fromTypeElement(type), name);
+ }
+
+ public VariableWriter addParameter(TypeWriter type, String name) {
+ return addParameter(type.name, name);
+ }
+
+ public VariableWriter addParameter(TypeName type, String name) {
+ VariableWriter parameterWriter = new VariableWriter(type, name);
+ parameterWriters.put(name, parameterWriter);
+ return parameterWriter;
+ }
+
+ public Map<String, TypeName> parameters() {
+ ImmutableMap.Builder<String, TypeName> params = ImmutableMap.builder();
+ for (Map.Entry<String, VariableWriter> entry : parameterWriters.entrySet()) {
+ params.put(entry.getKey(), entry.getValue().type());
+ }
+ return params.build();
+ }
+
+ public BlockWriter body() {
+ return blockWriter;
+ }
+
+ private VariableWriter addParameter(ClassName type, String name) {
+ checkArgument(!parameterWriters.containsKey(name));
+ VariableWriter parameterWriter = new VariableWriter(type, name);
+ parameterWriters.put(name, parameterWriter);
+ return parameterWriter;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(ImmutableList.<HasClassReferences>of())
+ .append(parameterWriters.values())
+ .append(annotations)
+ .append(blockWriter)
+ .transformAndConcat(HasClassReferences.COMBINER)
+ .toSet();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ writeAnnotations(appendable, context);
+ writeModifiers(appendable).append(name).append('(');
+ Writables.join(", ", parameterWriters.values(), appendable, context);
+ appendable.append(") {");
+ blockWriter.write(new IndentingAppendable(appendable), context);
+ return appendable.append("}\n");
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/EnumWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/EnumWriter.java
new file mode 100644
index 000000000..4ab017d79
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/EnumWriter.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.lang.model.element.Modifier;
+
+import static com.google.common.base.Preconditions.checkState;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PROTECTED;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+public final class EnumWriter extends TypeWriter {
+ private final Map<String, ConstantWriter> constantWriters = Maps.newLinkedHashMap();
+ private final List<ConstructorWriter> constructorWriters = Lists.newArrayList();
+
+ EnumWriter(ClassName name) {
+ super(name);
+ }
+
+ public ConstantWriter addConstant(String name) {
+ ConstantWriter constantWriter = new ConstantWriter(name);
+ constantWriters.put(name, constantWriter);
+ return constantWriter;
+ }
+
+ public ConstructorWriter addConstructor() {
+ ConstructorWriter constructorWriter = new ConstructorWriter(name.simpleName());
+ constructorWriters.add(constructorWriter);
+ return constructorWriter;
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ context = context.createSubcontext(FluentIterable.from(nestedTypeWriters)
+ .transform(new Function<TypeWriter, ClassName>() {
+ @Override public ClassName apply(TypeWriter input) {
+ return input.name;
+ }
+ })
+ .toSet());
+ writeAnnotations(appendable, context);
+ writeModifiers(appendable).append("enum ").append(name.simpleName());
+ Iterator<TypeName> implementedTypesIterator = implementedTypes.iterator();
+ if (implementedTypesIterator.hasNext()) {
+ appendable.append(" implements ");
+ implementedTypesIterator.next().write(appendable, context);
+ while (implementedTypesIterator.hasNext()) {
+ appendable.append(", ");
+ implementedTypesIterator.next().write(appendable, context);
+ }
+ }
+ appendable.append(" {");
+
+ checkState(!constantWriters.isEmpty(), "Cannot write an enum with no constants.");
+ appendable.append('\n');
+ ImmutableList<ConstantWriter> constantWriterList =
+ ImmutableList.copyOf(constantWriters.values());
+ for (ConstantWriter constantWriter
+ : constantWriterList.subList(0, constantWriterList.size() - 1)) {
+ constantWriter.write(appendable, context);
+ appendable.append(",\n");
+ }
+ constantWriterList.get(constantWriterList.size() - 1).write(appendable, context);
+ appendable.append(";\n");
+
+ if (!fieldWriters.isEmpty()) {
+ appendable.append('\n');
+ }
+ for (VariableWriter fieldWriter : fieldWriters.values()) {
+ fieldWriter.write(new IndentingAppendable(appendable), context).append("\n");
+ }
+ for (ConstructorWriter constructorWriter : constructorWriters) {
+ appendable.append('\n');
+ if (!isDefaultConstructor(constructorWriter)) {
+ constructorWriter.write(new IndentingAppendable(appendable), context);
+ }
+ }
+ for (MethodWriter methodWriter : methodWriters) {
+ appendable.append('\n');
+ methodWriter.write(new IndentingAppendable(appendable), context);
+ }
+ for (TypeWriter nestedTypeWriter : nestedTypeWriters) {
+ appendable.append('\n');
+ nestedTypeWriter.write(new IndentingAppendable(appendable), context);
+ }
+ appendable.append("}\n");
+ return appendable;
+ }
+
+ private static final Set<Modifier> VISIBILIY_MODIFIERS =
+ Sets.immutableEnumSet(PUBLIC, PROTECTED, PRIVATE);
+
+ private boolean isDefaultConstructor(ConstructorWriter constructorWriter) {
+ return Sets.intersection(VISIBILIY_MODIFIERS, modifiers)
+ .equals(Sets.intersection(VISIBILIY_MODIFIERS, constructorWriter.modifiers))
+ && constructorWriter.body().isEmpty();
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(ImmutableList.<HasClassReferences>of())
+ .append(nestedTypeWriters)
+ .append(constantWriters.values())
+ .append(fieldWriters.values())
+ .append(constructorWriters)
+ .append(methodWriters)
+ .append(implementedTypes)
+ .append(annotations)
+ .transformAndConcat(HasClassReferences.COMBINER)
+ .toSet();
+ }
+
+ public static final class ConstantWriter implements Writable, HasClassReferences {
+ private final String name;
+ private final List<Snippet> constructorSnippets;
+
+ private ConstantWriter(String name) {
+ this.name = name;
+ this.constructorSnippets = Lists.newArrayList();
+ }
+
+ ConstantWriter addArgument(Snippet snippet) {
+ constructorSnippets.add(snippet);
+ return this;
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ appendable.append(name);
+ Iterator<Snippet> snippetIterator = constructorSnippets.iterator();
+ if (snippetIterator.hasNext()) {
+ appendable.append('(');
+ snippetIterator.next().write(appendable, context);
+ while (snippetIterator.hasNext()) {
+ appendable.append(", ");
+ snippetIterator.next().write(appendable, context);
+ }
+ appendable.append(')');
+ }
+ return appendable;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(constructorSnippets)
+ .transformAndConcat(HasClassReferences.COMBINER)
+ .toSet();
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/FieldWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/FieldWriter.java
new file mode 100644
index 000000000..b45e5d9ae
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/FieldWriter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import java.io.IOException;
+import java.util.Set;
+
+public final class FieldWriter extends VariableWriter {
+ private Optional<Snippet> initializer;
+
+ FieldWriter(TypeName type, String name) {
+ super(type, name);
+ this.initializer = Optional.absent();
+ }
+
+ public void setInitializer(Snippet initializer) {
+ this.initializer = Optional.of(initializer);
+ }
+
+ public void setInitializer(String initializer, Object... args) {
+ this.initializer = Optional.of(Snippet.format(initializer, args));
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ super.write(appendable, context);
+ if (initializer.isPresent()) {
+ appendable.append(" = ");
+ initializer.get().write(appendable, context);
+ }
+ appendable.append(';');
+ return appendable;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ Iterable<? extends HasClassReferences> concat =
+ Iterables.concat(ImmutableList.of(type()), initializer.asSet(), annotations);
+ return FluentIterable.from(concat)
+ .transformAndConcat(new Function<HasClassReferences, Set<ClassName>>() {
+ @Override
+ public Set<ClassName> apply(HasClassReferences input) {
+ return input.referencedClasses();
+ }
+ })
+ .toSet();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/HasClassReferences.java b/compiler/src/main/java/dagger/internal/codegen/writer/HasClassReferences.java
new file mode 100644
index 000000000..e463ea2cb
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/HasClassReferences.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.base.Function;
+import java.util.Set;
+
+public interface HasClassReferences {
+ Set<ClassName> referencedClasses();
+
+ static final Function<HasClassReferences, Set<ClassName>> COMBINER =
+ new Function<HasClassReferences, Set<ClassName>>() {
+ @Override
+ public Set<ClassName> apply(HasClassReferences input) {
+ return input.referencedClasses();
+ }
+ };
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/HasTypeName.java b/compiler/src/main/java/dagger/internal/codegen/writer/HasTypeName.java
new file mode 100644
index 000000000..a6909ed10
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/HasTypeName.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+interface HasTypeName {
+ TypeName name();
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/IndentingAppendable.java b/compiler/src/main/java/dagger/internal/codegen/writer/IndentingAppendable.java
new file mode 100644
index 000000000..d96f8a3a2
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/IndentingAppendable.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.collect.AbstractIterator;
+import java.io.IOException;
+import java.util.Iterator;
+
+final class IndentingAppendable implements Appendable {
+ private final String indentation;
+ private final Appendable delegate;
+ private boolean requiresIndent = true;
+
+ IndentingAppendable(Appendable delegate) {
+ this(" ", delegate);
+ }
+
+ IndentingAppendable(String indentation, Appendable delegate) {
+ this.indentation = indentation;
+ this.delegate = delegate;
+ }
+
+ @Override
+ public Appendable append(CharSequence csq) throws IOException {
+ return append(csq, 0, csq.length());
+ }
+
+ @Override
+ public Appendable append(CharSequence csq, int start, int end) throws IOException {
+ Iterator<CharSequence> lines = lines(csq, start, end);
+ while (lines.hasNext()) {
+ CharSequence line = lines.next();
+ maybeIndent();
+ delegate.append(line);
+ if (line.charAt(line.length() - 1) == '\n') {
+ requiresIndent = true;
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public Appendable append(char c) throws IOException {
+ maybeIndent();
+ delegate.append(c);
+ if (c == '\n') {
+ requiresIndent = true;
+ }
+ return this;
+ }
+
+ void maybeIndent() throws IOException {
+ if (requiresIndent) {
+ delegate.append(indentation);
+ }
+ requiresIndent = false;
+ }
+
+ private static Iterator<CharSequence> lines(
+ final CharSequence csq, final int start, final int end) {
+ return new AbstractIterator<CharSequence>() {
+ int index = start;
+
+ @Override protected CharSequence computeNext() {
+ int nextStart = index;
+ while (index < end && csq.charAt(index) != '\n') {
+ index++;
+ }
+ if (index < end && csq.charAt(index) == '\n') {
+ index++;
+ }
+ int nextEnd = index;
+ return nextStart >= end
+ ? endOfData()
+ : csq.subSequence(nextStart, nextEnd);
+ }
+ };
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/InterfaceWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/InterfaceWriter.java
new file mode 100644
index 000000000..ffcfc7562
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/InterfaceWriter.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+public final class InterfaceWriter extends TypeWriter {
+ private final List<TypeVariableName> typeVariables;
+ InterfaceWriter(ClassName name) {
+ super(name);
+ this.typeVariables = Lists.newArrayList();
+ }
+
+ public void addTypeVariable(TypeVariableName typeVariable) {
+ this.typeVariables.add(typeVariable);
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ context = context.createSubcontext(FluentIterable.from(nestedTypeWriters)
+ .transform(new Function<TypeWriter, ClassName>() {
+ @Override public ClassName apply(TypeWriter input) {
+ return input.name;
+ }
+ })
+ .toSet());
+ writeAnnotations(appendable, context);
+ writeModifiers(appendable).append("interface ").append(name.simpleName());
+ if (!typeVariables.isEmpty()) {
+ appendable.append('<');
+ Joiner.on(", ").appendTo(appendable, typeVariables);
+ appendable.append('>');
+ }
+ Iterator<TypeName> implementedTypesIterator = implementedTypes.iterator();
+ if (implementedTypesIterator.hasNext()) {
+ appendable.append(" extends ");
+ implementedTypesIterator.next().write(appendable, context);
+ while (implementedTypesIterator.hasNext()) {
+ appendable.append(", ");
+ implementedTypesIterator.next().write(appendable, context);
+ }
+ }
+ appendable.append(" {");
+ for (MethodWriter methodWriter : methodWriters) {
+ appendable.append('\n');
+ methodWriter.write(new IndentingAppendable(appendable), context);
+ }
+ for (TypeWriter nestedTypeWriter : nestedTypeWriters) {
+ appendable.append('\n');
+ nestedTypeWriter.write(new IndentingAppendable(appendable), context);
+ }
+ appendable.append("}\n");
+ return appendable;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(ImmutableList.<HasClassReferences>of())
+ .append(nestedTypeWriters)
+ .append(methodWriters)
+ .append(implementedTypes)
+ .append(annotations)
+ .transformAndConcat(HasClassReferences.COMBINER)
+ .toSet();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/JavaWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/JavaWriter.java
new file mode 100644
index 000000000..5977371ac
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/JavaWriter.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+import com.google.common.collect.Sets;
+import com.google.common.io.CharSink;
+import com.google.common.io.CharSource;
+import com.google.googlejavaformat.java.Formatter;
+import com.google.googlejavaformat.java.FormatterException;
+import dagger.internal.codegen.writer.Writable.Context;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.processing.Filer;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.PackageElement;
+import javax.tools.JavaFileObject;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.Collections.unmodifiableList;
+
+/**
+ * Writes a single compilation unit.
+ */
+public final class JavaWriter {
+ public static JavaWriter inPackage(String packageName) {
+ return new JavaWriter(packageName);
+ }
+
+ public static JavaWriter inPackage(Package enclosingPackage) {
+ return new JavaWriter(enclosingPackage.getName());
+ }
+
+ public static JavaWriter inPackage(PackageElement packageElement) {
+ return new JavaWriter(packageElement.getQualifiedName().toString());
+ }
+
+ private final String packageName;
+ // TODO(gak): disallow multiple types in a file?
+ private final List<TypeWriter> typeWriters;
+ private final List<ClassName> explicitImports;
+
+ private JavaWriter(String packageName) {
+ this.packageName = packageName;
+ this.typeWriters = Lists.newArrayList();
+ this.explicitImports = Lists.newArrayList();
+ }
+
+ public List<TypeWriter> getTypeWriters() {
+ return unmodifiableList(typeWriters);
+ }
+
+ public JavaWriter addImport(Class<?> importedClass) {
+ explicitImports.add(ClassName.fromClass(importedClass));
+ return this;
+ }
+
+ public ClassWriter addClass(String simpleName) {
+ checkNotNull(simpleName);
+ ClassWriter classWriter = new ClassWriter(ClassName.create(packageName, simpleName));
+ typeWriters.add(classWriter);
+ return classWriter;
+ }
+
+ public EnumWriter addEnum(String simpleName) {
+ checkNotNull(simpleName);
+ EnumWriter writer = new EnumWriter(ClassName.create(packageName, simpleName));
+ typeWriters.add(writer);
+ return writer;
+ }
+
+ public InterfaceWriter addInterface(String simpleName) {
+ InterfaceWriter writer = new InterfaceWriter(ClassName.create(packageName, simpleName));
+ typeWriters.add(writer);
+ return writer;
+ }
+
+ public <A extends Appendable> A write(A appendable) throws IOException {
+ if (!packageName.isEmpty()) {
+ appendable.append("package ").append(packageName).append(";\n\n");
+ }
+
+ // write imports
+ ImmutableSet<ClassName> classNames = FluentIterable.from(typeWriters)
+ .transformAndConcat(new Function<HasClassReferences, Set<ClassName>>() {
+ @Override
+ public Set<ClassName> apply(HasClassReferences input) {
+ return input.referencedClasses();
+ }
+ })
+ .toSet();
+
+ ImmutableSortedSet<ClassName> importCandidates = ImmutableSortedSet.<ClassName>naturalOrder()
+ .addAll(explicitImports)
+ .addAll(classNames)
+ .build();
+ ImmutableSet<ClassName> typeNames = FluentIterable.from(typeWriters)
+ .transform(new Function<TypeWriter, ClassName>() {
+ @Override public ClassName apply(TypeWriter input) {
+ return input.name;
+ }
+ })
+ .toSet();
+
+ ImmutableSet.Builder<String> declaredSimpleNamesBuilder = ImmutableSet.builder();
+ Deque<TypeWriter> declaredTypes = new ArrayDeque<>(typeWriters);
+ while (!declaredTypes.isEmpty()) {
+ TypeWriter currentType = declaredTypes.pop();
+ declaredSimpleNamesBuilder.add(currentType.name().simpleName());
+ declaredTypes.addAll(currentType.nestedTypeWriters);
+ }
+
+ ImmutableSet<String> declaredSimpleNames = declaredSimpleNamesBuilder.build();
+
+ BiMap<String, ClassName> importedClassIndex = HashBiMap.create();
+ for (ClassName className : importCandidates) {
+ if (!(className.packageName().equals(packageName)
+ && !className.enclosingClassName().isPresent())
+ && !(className.packageName().equals("java.lang")
+ && className.enclosingSimpleNames().isEmpty())
+ && !typeNames.contains(className.topLevelClassName())) {
+ Optional<ClassName> importCandidate = Optional.of(className);
+ while (importCandidate.isPresent()
+ && (importedClassIndex.containsKey(importCandidate.get().simpleName())
+ || declaredSimpleNames.contains(importCandidate.get().simpleName()))) {
+ importCandidate = importCandidate.get().enclosingClassName();
+ }
+ if (importCandidate.isPresent()) {
+ appendable.append("import ").append(importCandidate.get().canonicalName()).append(";\n");
+ importedClassIndex.put(importCandidate.get().simpleName(), importCandidate.get());
+ }
+ }
+ }
+
+ appendable.append('\n');
+
+ CompilationUnitContext context =
+ new CompilationUnitContext(packageName, ImmutableSet.copyOf(importedClassIndex.values()));
+
+ // write types
+ for (TypeWriter typeWriter : typeWriters) {
+ typeWriter.write(appendable, context.createSubcontext(typeNames)).append('\n');
+ }
+ return appendable;
+ }
+
+ public void file(Filer filer, Iterable<? extends Element> originatingElements)
+ throws IOException {
+ file(filer, Iterables.getOnlyElement(typeWriters).name.canonicalName(), originatingElements);
+ }
+
+ public void file(Filer filer, CharSequence name, Iterable<? extends Element> originatingElements)
+ throws IOException {
+ final JavaFileObject sourceFile = filer.createSourceFile(name,
+ Iterables.toArray(originatingElements, Element.class));
+ try {
+ new Formatter().formatSource(
+ CharSource.wrap(write(new StringBuilder())),
+ new CharSink() {
+ @Override public Writer openStream() throws IOException {
+ return sourceFile.openWriter();
+ }
+ });
+ } catch (FormatterException e) {
+ throw new IllegalStateException(
+ "The writer produced code that could not be parsed by the formatter", e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ try {
+ return write(new StringBuilder()).toString();
+ } catch (IOException e) {
+ throw new AssertionError();
+ }
+ }
+
+ static final class CompilationUnitContext implements Context {
+ private final String packageName;
+ private final ImmutableSortedSet<ClassName> visibleClasses;
+
+ CompilationUnitContext(String packageName, Set<ClassName> visibleClasses) {
+ this.packageName = packageName;
+ this.visibleClasses =
+ ImmutableSortedSet.copyOf(Ordering.natural().reverse(), visibleClasses);
+ }
+
+ @Override
+ public Context createSubcontext(Set<ClassName> newTypes) {
+ return new CompilationUnitContext(packageName, Sets.union(visibleClasses, newTypes));
+ }
+
+ @Override
+ public String sourceReferenceForClassName(ClassName className) {
+ if (isImported(className)) {
+ return className.simpleName();
+ }
+ Optional<ClassName> enclosingClassName = className.enclosingClassName();
+ while (enclosingClassName.isPresent()) {
+ if (isImported(enclosingClassName.get())) {
+ return enclosingClassName.get().simpleName()
+ + className.canonicalName()
+ .substring(enclosingClassName.get().canonicalName().length());
+ }
+ enclosingClassName = enclosingClassName.get().enclosingClassName();
+ }
+ return className.canonicalName();
+ }
+
+ private boolean collidesWithVisibleClass(ClassName className) {
+ return collidesWithVisibleClass(className.simpleName());
+ }
+
+ private boolean collidesWithVisibleClass(String simpleName) {
+ return FluentIterable.from(visibleClasses)
+ .transform(new Function<ClassName, String>() {
+ @Override public String apply(ClassName input) {
+ return input.simpleName();
+ }
+ })
+ .contains(simpleName);
+ }
+
+ private boolean isImported(ClassName className) {
+ return (packageName.equals(className.packageName())
+ && !className.enclosingClassName().isPresent()
+ && !collidesWithVisibleClass(className)) // need to account for scope & hiding
+ || visibleClasses.contains(className)
+ || (className.packageName().equals("java.lang")
+ && className.enclosingSimpleNames().isEmpty());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/MethodWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/MethodWriter.java
new file mode 100644
index 000000000..eb4ff8d51
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/MethodWriter.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.lang.model.element.TypeElement;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public final class MethodWriter extends Modifiable implements HasClassReferences, Writable {
+ private final TypeName returnType;
+ private final String name;
+ private final Map<String, VariableWriter> parameterWriters;
+ private final List<TypeVariableName> typeParameters;
+ private Optional<BlockWriter> body;
+
+ MethodWriter(TypeName returnType, String name) {
+ this.returnType = returnType;
+ this.name = name;
+ this.parameterWriters = Maps.newLinkedHashMap();
+ this.typeParameters = Lists.newArrayList();
+ this.body = Optional.absent();
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public TypeName returnType() {
+ return returnType;
+ }
+
+ public void addTypeParameter(TypeVariableName typeVariableName) {
+ this.typeParameters.add(typeVariableName);
+ }
+
+ public void addTypeParameters(Iterable<TypeVariableName> typeVariableNames) {
+ Iterables.addAll(typeParameters, typeVariableNames);
+ }
+
+ public VariableWriter addParameter(Class<?> type, String name) {
+ return addParameter(ClassName.fromClass(type), name);
+ }
+
+ public VariableWriter addParameter(TypeElement type, String name) {
+ return addParameter(ClassName.fromTypeElement(type), name);
+ }
+
+ public VariableWriter addParameter(TypeWriter type, String name) {
+ return addParameter(type.name, name);
+ }
+
+ public VariableWriter addParameter(TypeName type, String name) {
+ checkArgument(!parameterWriters.containsKey(name));
+ VariableWriter parameterWriter = new VariableWriter(type, name);
+ parameterWriters.put(name, parameterWriter);
+ return parameterWriter;
+ }
+
+ public BlockWriter body() {
+ if (body.isPresent()) {
+ return body.get();
+ } else {
+ BlockWriter blockWriter = new BlockWriter();
+ body = Optional.of(blockWriter);
+ return blockWriter;
+ }
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ writeAnnotations(appendable, context);
+ writeModifiers(appendable);
+ Writables.join(", ", typeParameters, "<", "> ", appendable, context);
+ returnType.write(appendable, context);
+ appendable.append(' ').append(name).append('(');
+ Writables.join(", ", parameterWriters.values(), appendable, context);
+ appendable.append(")");
+ if (body.isPresent()) {
+ appendable.append(" {");
+ body.get().write(new IndentingAppendable(appendable), context);
+ appendable.append("}\n");
+ } else {
+ appendable.append(";\n");
+ }
+ return appendable;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(ImmutableList.<HasClassReferences>of())
+ .append(parameterWriters.values())
+ .append(returnType)
+ .append(body.asSet())
+ .append(annotations)
+ .transformAndConcat(HasClassReferences.COMBINER)
+ .toSet();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/Modifiable.java b/compiler/src/main/java/dagger/internal/codegen/writer/Modifiable.java
new file mode 100644
index 000000000..bb4c6ffd9
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/Modifiable.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import dagger.internal.codegen.writer.Writable.Context;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import javax.lang.model.element.Modifier;
+
+public abstract class Modifiable {
+ final Set<Modifier> modifiers;
+ final List<AnnotationWriter> annotations;
+
+ Modifiable() {
+ this.modifiers = EnumSet.noneOf(Modifier.class);
+ this.annotations = Lists.newArrayList();
+ }
+
+ public void addModifiers(Modifier first, Modifier... rest) {
+ addModifiers(Lists.asList(first, rest));
+ }
+
+ public void addModifiers(Iterable<Modifier> modifiers) {
+ Iterables.addAll(this.modifiers, modifiers);
+ }
+
+ public AnnotationWriter annotate(ClassName annotation) {
+ AnnotationWriter annotationWriter = new AnnotationWriter(annotation);
+ this.annotations.add(annotationWriter);
+ return annotationWriter;
+ }
+
+ public AnnotationWriter annotate(Class<? extends Annotation> annotation) {
+ return annotate(ClassName.fromClass(annotation));
+ }
+
+ Appendable writeModifiers(Appendable appendable) throws IOException {
+ for (Modifier modifier : modifiers) {
+ appendable.append(modifier.toString()).append(' ');
+ }
+ return appendable;
+ }
+
+ Appendable writeAnnotations(Appendable appendable, Context context) throws IOException {
+ for (AnnotationWriter annotationWriter : annotations) {
+ annotationWriter.write(appendable, context).append('\n');
+ }
+ return appendable;
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/NullName.java b/compiler/src/main/java/dagger/internal/codegen/writer/NullName.java
new file mode 100644
index 000000000..0d3588b77
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/NullName.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.util.Set;
+
+enum NullName implements TypeName {
+ NULL;
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return ImmutableSet.of();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ return appendable.append("null");
+ }
+
+ @Override
+ public String toString() {
+ return "null";
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/ParameterizedTypeName.java b/compiler/src/main/java/dagger/internal/codegen/writer/ParameterizedTypeName.java
new file mode 100644
index 000000000..e46a96186
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/ParameterizedTypeName.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
+
+public final class ParameterizedTypeName implements TypeName {
+ private final ClassName type;
+ private final ImmutableList<TypeName> parameters;
+
+ ParameterizedTypeName(ClassName type, Iterable<? extends TypeName> parameters) {
+ this.type = type;
+ this.parameters = ImmutableList.<TypeName>copyOf(parameters);
+ }
+
+ public ClassName type() {
+ return type;
+ }
+
+ public ImmutableList<TypeName> parameters() {
+ return parameters;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ ImmutableSet.Builder<ClassName> builder = new ImmutableSet.Builder<ClassName>()
+ .add(type);
+ for (TypeName parameter : parameters) {
+ builder.addAll(parameter.referencedClasses());
+ }
+ return builder.build();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ appendable.append(context.sourceReferenceForClassName(type));
+ Iterator<? extends TypeName> parameterIterator = parameters.iterator();
+ verify(parameterIterator.hasNext(), type.toString());
+ appendable.append('<');
+ parameterIterator.next().write(appendable, context);
+ while (parameterIterator.hasNext()) {
+ appendable.append(", ");
+ parameterIterator.next().write(appendable, context);
+ }
+ appendable.append('>');
+ return appendable;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof ParameterizedTypeName) {
+ ParameterizedTypeName that = (ParameterizedTypeName) obj;
+ return this.type.equals(that.type)
+ && this.parameters.equals(that.parameters);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(type, parameters);
+ }
+
+ @Override
+ public String toString() {
+ return Writables.writeToString(this);
+ }
+
+ public static ParameterizedTypeName create(ClassName className,
+ TypeName... parameters) {
+ return new ParameterizedTypeName(className, ImmutableList.copyOf(parameters));
+ }
+
+ public static ParameterizedTypeName create(ClassName className,
+ Iterable<? extends TypeName> parameters) {
+ return new ParameterizedTypeName(className, ImmutableList.copyOf(parameters));
+ }
+
+ public static ParameterizedTypeName create(Class<?> parameterizedClass,
+ TypeName... parameters) {
+ checkArgument(parameterizedClass.getTypeParameters().length == parameters.length);
+ return new ParameterizedTypeName(ClassName.fromClass(parameterizedClass),
+ ImmutableList.copyOf(parameters));
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/PrimitiveName.java b/compiler/src/main/java/dagger/internal/codegen/writer/PrimitiveName.java
new file mode 100644
index 000000000..94961dd7a
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/PrimitiveName.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.base.Ascii;
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.util.Set;
+import javax.lang.model.type.PrimitiveType;
+
+public enum PrimitiveName implements TypeName {
+ BOOLEAN, BYTE, SHORT, INT, LONG, CHAR, FLOAT, DOUBLE;
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return ImmutableSet.of();
+ }
+
+ @Override
+ public String toString() {
+ return Ascii.toLowerCase(name());
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ return appendable.append(toString());
+ }
+
+ static PrimitiveName forTypeMirror(PrimitiveType mirror) {
+ switch (mirror.getKind()) {
+ case BOOLEAN:
+ return BOOLEAN;
+ case BYTE:
+ return BYTE;
+ case SHORT:
+ return SHORT;
+ case INT:
+ return INT;
+ case LONG:
+ return LONG;
+ case CHAR:
+ return CHAR;
+ case FLOAT:
+ return FLOAT;
+ case DOUBLE:
+ return DOUBLE;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ static PrimitiveName forClass(Class<?> primitiveClass) {
+ if (boolean.class.equals(primitiveClass)) {
+ return BOOLEAN;
+ }
+ if (byte.class.equals(primitiveClass)) {
+ return BYTE;
+ }
+ if (short.class.equals(primitiveClass)) {
+ return SHORT;
+ }
+ if (int.class.equals(primitiveClass)) {
+ return INT;
+ }
+ if (long.class.equals(primitiveClass)) {
+ return LONG;
+ }
+ if (char.class.equals(primitiveClass)) {
+ return CHAR;
+ }
+ if (float.class.equals(primitiveClass)) {
+ return FLOAT;
+ }
+ if (double.class.equals(primitiveClass)) {
+ return DOUBLE;
+ }
+ throw new IllegalArgumentException(primitiveClass + " is not a primitive type");
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/Snippet.java b/compiler/src/main/java/dagger/internal/codegen/writer/Snippet.java
new file mode 100644
index 000000000..2d11f60f7
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/Snippet.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Formatter;
+import java.util.Iterator;
+import java.util.Set;
+
+public final class Snippet implements HasClassReferences, Writable {
+ private final String format;
+ private final ImmutableSet<TypeName> types;
+ private final ImmutableList<Object> args;
+
+ private Snippet(String format, ImmutableSet<TypeName> types, ImmutableList<Object> args) {
+ this.format = format;
+ this.types = types;
+ this.args = args;
+ }
+
+ public String format() {
+ return format;
+ }
+
+ public ImmutableList<Object> args() {
+ return args;
+ }
+
+ public ImmutableSet<TypeName> types() {
+ return types;
+ }
+
+ @Override
+ public String toString() {
+ return Writables.writeToString(this);
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(types)
+ .transformAndConcat(new Function<TypeName, Set<ClassName>>() {
+ @Override
+ public Set<ClassName> apply(TypeName input) {
+ return input.referencedClasses();
+ }
+ })
+ .toSet();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ ImmutableList.Builder<Object> formattedArgsBuilder = ImmutableList.builder();
+ for (Object arg : args) {
+ if (arg instanceof Writable) {
+ formattedArgsBuilder.add(((Writable) arg).write(new StringBuilder(), context).toString());
+ } else {
+ formattedArgsBuilder.add(arg);
+ }
+ }
+
+ @SuppressWarnings("resource") // intentionally don't close the formatter
+ Formatter formatter = new Formatter(appendable);
+ formatter.format(format, formattedArgsBuilder.build().toArray(new Object[0]));
+
+ return appendable;
+ }
+
+ public static Snippet format(String format, Object... args) {
+ ImmutableSet.Builder<TypeName> types = ImmutableSet.builder();
+ for (Object arg : args) {
+ if (arg instanceof Snippet) {
+ types.addAll(((Snippet) arg).types);
+ }
+ if (arg instanceof TypeName) {
+ types.add((TypeName) arg);
+ }
+ if (arg instanceof HasTypeName) {
+ types.add(((HasTypeName) arg).name());
+ }
+ }
+ return new Snippet(format, types.build(), ImmutableList.copyOf(args));
+ }
+
+ public static Snippet format(String format, Iterable<? extends Object> args) {
+ return format(format, Iterables.toArray(args, Object.class));
+ }
+
+ public static Snippet memberSelectSnippet(Iterable<? extends Object> selectors) {
+ return format(Joiner.on('.').join(Collections.nCopies(Iterables.size(selectors), "%s")),
+ selectors);
+ }
+
+ public static Snippet nullCheck(Object thingToCheck) {
+ return format("if (%s == null) { throw new NullPointerException(); } ", thingToCheck);
+ }
+
+ public static Snippet nullCheck(Object thingToCheck, String message) {
+ return format("if (%s == null) { throw new NullPointerException(%s); } ",
+ thingToCheck,
+ StringLiteral.forValue(message));
+ }
+
+ public static Snippet makeParametersSnippet(Iterable<Snippet> parameterSnippets) {
+ Iterator<Snippet> iterator = parameterSnippets.iterator();
+ StringBuilder stringBuilder = new StringBuilder();
+ ImmutableSet.Builder<TypeName> typesBuilder = ImmutableSet.builder();
+ ImmutableList.Builder<Object> argsBuilder = ImmutableList.builder();
+ if (iterator.hasNext()) {
+ Snippet firstSnippet = iterator.next();
+ stringBuilder.append(firstSnippet.format());
+ typesBuilder.addAll(firstSnippet.types());
+ argsBuilder.addAll(firstSnippet.args());
+ }
+ while (iterator.hasNext()) {
+ Snippet nextSnippet = iterator.next();
+ stringBuilder.append(", ").append(nextSnippet.format());
+ typesBuilder.addAll(nextSnippet.types());
+ argsBuilder.addAll(nextSnippet.args());
+ }
+ return new Snippet(stringBuilder.toString(), typesBuilder.build(), argsBuilder.build());
+ }
+
+ /**
+ * A snippet that concatenates its arguments.
+ */
+ public static Snippet concat(Iterable<Snippet> snippets) {
+ return join(Joiner.on(""), snippets);
+ }
+
+ /**
+ * A snippet that joins its arguments with {@code joiner}.
+ */
+ public static Snippet join(Joiner joiner, Iterable<Snippet> snippets) {
+ FluentIterable<Snippet> fluentSnippets = FluentIterable.from(snippets);
+ return new Snippet(
+ joiner
+ .appendTo(
+ new StringBuilder(),
+ fluentSnippets.transform(
+ new Function<Snippet, String>() {
+ @Override
+ public String apply(Snippet snippet) {
+ return snippet.format;
+ }
+ }))
+ .toString(),
+ fluentSnippets
+ .transformAndConcat(
+ new Function<Snippet, ImmutableSet<TypeName>>() {
+ @Override
+ public ImmutableSet<TypeName> apply(Snippet snippet) {
+ return snippet.types;
+ }
+ })
+ .toSet(),
+ fluentSnippets
+ .transformAndConcat(
+ new Function<Snippet, ImmutableList<Object>>() {
+ @Override
+ public ImmutableList<Object> apply(Snippet snippet) {
+ return snippet.args;
+ }
+ })
+ .toList());
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/StringLiteral.java b/compiler/src/main/java/dagger/internal/codegen/writer/StringLiteral.java
new file mode 100644
index 000000000..2d059f9af
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/StringLiteral.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2014 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import java.util.Formatter;
+
+/**
+ * Represents a string literal as found in Java source code.
+ */
+public final class StringLiteral {
+ /** Returns a new {@link StringLiteral} instance for the intended value of the literal. */
+ public static StringLiteral forValue(String value) {
+ return new StringLiteral(value, stringLiteral(value));
+ }
+
+ /** Returns the string literal representing {@code data}, including wrapping quotes. */
+ private static String stringLiteral(String value) {
+ StringBuilder result = new StringBuilder();
+ result.append('"');
+ for (int i = 0; i < value.length(); i++) {
+ char c = value.charAt(i);
+ switch (c) {
+ case '"':
+ result.append("\\\"");
+ break;
+ case '\\':
+ result.append("\\\\");
+ break;
+ case '\b':
+ result.append("\\b");
+ break;
+ case '\t':
+ result.append("\\t");
+ break;
+ case '\n':
+ result.append("\\n");
+ break;
+ case '\f':
+ result.append("\\f");
+ break;
+ case '\r':
+ result.append("\\r");
+ break;
+ default:
+ if (Character.isISOControl(c)) {
+ new Formatter(result).format("\\u%04x", (int) c);
+ } else {
+ result.append(c);
+ }
+ }
+ }
+ result.append('"');
+ return result.toString();
+ }
+
+ private final String value;
+ private final String literal;
+
+ private StringLiteral(String value, String literal) {
+ this.value = value;
+ this.literal = literal;
+ }
+
+ public String value() {
+ return value;
+ }
+
+ public String literal() {
+ return literal;
+ }
+
+ @Override
+ public String toString() {
+ return literal;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ } else if (obj instanceof StringLiteral) {
+ return this.value.equals(((StringLiteral) obj).value);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/TypeName.java b/compiler/src/main/java/dagger/internal/codegen/writer/TypeName.java
new file mode 100644
index 000000000..e0daf5312
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/TypeName.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+public interface TypeName extends HasClassReferences, Writable {
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/TypeNames.java b/compiler/src/main/java/dagger/internal/codegen/writer/TypeNames.java
new file mode 100644
index 000000000..4bc234739
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/TypeNames.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.ArrayType;
+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.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.WildcardType;
+import javax.lang.model.util.SimpleTypeVisitor6;
+
+public final class TypeNames {
+ static final Function<TypeMirror, TypeName> FOR_TYPE_MIRROR =
+ new Function<TypeMirror, TypeName>() {
+ @Override public TypeName apply(TypeMirror input) {
+ return forTypeMirror(input);
+ }
+ };
+
+ public static TypeName forClass(Class<?> clazz) {
+ if (clazz.isPrimitive()) {
+ return PrimitiveName.forClass(clazz);
+ } else if (void.class.equals(clazz)) {
+ return VoidName.VOID;
+ } else if (clazz.isArray()) {
+ return new ArrayTypeName(forClass(clazz.getComponentType()));
+ } else {
+ return ClassName.fromClass(clazz);
+ }
+ }
+
+ public static TypeName forTypeMirror(TypeMirror mirror) {
+ return mirror.accept(new SimpleTypeVisitor6<TypeName, Void>() {
+ @Override
+ protected TypeName defaultAction(TypeMirror e, Void p) {
+ throw new IllegalArgumentException(e.toString());
+ }
+
+ @Override
+ public TypeName visitTypeVariable(TypeVariable t, Void p) {
+ return TypeVariableName.fromTypeVariable(t);
+ }
+
+ @Override
+ public ArrayTypeName visitArray(ArrayType t, Void p) {
+ return new ArrayTypeName(t.getComponentType().accept(this, null));
+ }
+
+ @Override
+ public TypeName visitDeclared(DeclaredType t, Void p) {
+ return t.getTypeArguments().isEmpty()
+ ? ClassName.fromTypeElement((TypeElement) t.asElement())
+ : new ParameterizedTypeName(
+ ClassName.fromTypeElement((TypeElement) t.asElement()),
+ FluentIterable.from(t.getTypeArguments()).transform(FOR_TYPE_MIRROR));
+ }
+
+ @Override
+ public PrimitiveName visitPrimitive(PrimitiveType t, Void p) {
+ return PrimitiveName.forTypeMirror(t);
+ }
+
+ @Override
+ public WildcardName visitWildcard(WildcardType t, Void p) {
+ return WildcardName.forTypeMirror(t);
+ }
+
+ @Override
+ public NullName visitNull(NullType t, Void p) {
+ return NullName.NULL;
+ }
+
+ @Override
+ public TypeName visitNoType(NoType t, Void p) {
+ switch (t.getKind()) {
+ case VOID:
+ return VoidName.VOID;
+ case PACKAGE:
+ throw new IllegalArgumentException();
+ default:
+ throw new IllegalStateException();
+ }
+ }
+ }, null);
+ }
+
+ private TypeNames() {
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/TypeVariableName.java b/compiler/src/main/java/dagger/internal/codegen/writer/TypeVariableName.java
new file mode 100644
index 000000000..c6ee533ca
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/TypeVariableName.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Set;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+
+public final class TypeVariableName implements TypeName {
+ private final CharSequence name;
+ private final Iterable<? extends TypeName> extendsBounds;
+
+ TypeVariableName(CharSequence name, Iterable<? extends TypeName> extendsBounds) {
+ this.name = name;
+ this.extendsBounds = extendsBounds;
+ }
+
+ public CharSequence name() {
+ return name;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ ImmutableSet.Builder<ClassName> builder = new ImmutableSet.Builder<ClassName>();
+ for (TypeName bound : extendsBounds) {
+ builder.addAll(bound.referencedClasses());
+ }
+ return builder.build();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ appendable.append(name);
+ if (!Iterables.isEmpty(extendsBounds)) {
+ appendable.append(" extends ");
+ Iterator<? extends TypeName> iter = extendsBounds.iterator();
+ iter.next().write(appendable, context);
+ while (iter.hasNext()) {
+ appendable.append(" & ");
+ iter.next().write(appendable, context);
+ }
+ }
+ return appendable;
+ }
+
+ @Override
+ public String toString() {
+ return Writables.writeToString(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof TypeVariableName) {
+ TypeVariableName that = (TypeVariableName) obj;
+ return this.name.toString().equals(that.name.toString())
+ && this.extendsBounds.equals(that.extendsBounds);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name, extendsBounds);
+ }
+
+ static TypeVariableName named(CharSequence name) {
+ return new TypeVariableName(name, ImmutableList.<TypeName>of());
+ }
+
+ public static TypeVariableName fromTypeVariable(TypeVariable variable) {
+ // Note: We don't have any use right now for the bounds because these are references
+ // to the type & not the specification of the type itself. We never generate
+ // code with type variables that include upper or lower bounds.
+ return named(variable.asElement().getSimpleName());
+ }
+
+ // TODO(sameb): Consider making this a whole different thing: TypeParameterName since it
+ // has different semantics than a TypeVariable (parameters only have upper bounds).
+ public static TypeVariableName fromTypeParameterElement(TypeParameterElement element) {
+ // We filter out bounds of type Object because those would just clutter the generated code.
+ Iterable<? extends TypeName> bounds =
+ FluentIterable.from(element.getBounds())
+ .filter(new Predicate<TypeMirror>() {
+ @Override public boolean apply(TypeMirror input) {
+ return !MoreTypes.isType(input) || !MoreTypes.isTypeOf(Object.class, input);
+ }
+ })
+ .transform(TypeNames.FOR_TYPE_MIRROR);
+ return new TypeVariableName(element.getSimpleName(), bounds);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/TypeWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/TypeWriter.java
new file mode 100644
index 000000000..b13d0831e
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/TypeWriter.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import java.util.List;
+import java.util.Map;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Only named types. Doesn't cover anonymous inner classes.
+ */
+public abstract class TypeWriter /* ha ha */ extends Modifiable
+ implements Writable, HasTypeName, HasClassReferences {
+ final ClassName name;
+ final List<TypeName> implementedTypes;
+ final List<MethodWriter> methodWriters;
+ final List<TypeWriter> nestedTypeWriters;
+ final Map<String, FieldWriter> fieldWriters;
+
+ TypeWriter(ClassName name) {
+ this.name = name;
+ this.implementedTypes = Lists.newArrayList();
+ this.methodWriters = Lists.newArrayList();
+ this.nestedTypeWriters = Lists.newArrayList();
+ this.fieldWriters = Maps.newLinkedHashMap();
+ }
+
+ @Override
+ public ClassName name() {
+ return name;
+ }
+
+ public MethodWriter addMethod(TypeWriter returnType, String name) {
+ MethodWriter methodWriter = new MethodWriter(returnType.name, name);
+ methodWriters.add(methodWriter);
+ return methodWriter;
+ }
+
+ public MethodWriter addMethod(TypeMirror returnType, String name) {
+ MethodWriter methodWriter =
+ new MethodWriter(TypeNames.forTypeMirror(returnType), name);
+ methodWriters.add(methodWriter);
+ return methodWriter;
+ }
+
+ public MethodWriter addMethod(TypeName returnType, String name) {
+ MethodWriter methodWriter = new MethodWriter(returnType, name);
+ methodWriters.add(methodWriter);
+ return methodWriter;
+ }
+
+ public MethodWriter addMethod(Class<?> returnType, String name) {
+ MethodWriter methodWriter =
+ new MethodWriter(ClassName.fromClass(returnType), name);
+ methodWriters.add(methodWriter);
+ return methodWriter;
+ }
+
+ public ClassWriter addNestedClass(String name) {
+ ClassWriter innerClassWriter = new ClassWriter(this.name.nestedClassNamed(name));
+ nestedTypeWriters.add(innerClassWriter);
+ return innerClassWriter;
+ }
+
+ public void addImplementedType(TypeName typeReference) {
+ implementedTypes.add(typeReference);
+ }
+
+ public void addImplementedType(TypeElement typeElement) {
+ implementedTypes.add(ClassName.fromTypeElement(typeElement));
+ }
+
+ public FieldWriter addField(Class<?> type, String name) {
+ return addField(ClassName.fromClass(type), name);
+ }
+
+ public FieldWriter addField(TypeElement type, String name) {
+ return addField(ClassName.fromTypeElement(type), name);
+ }
+
+ public FieldWriter addField(TypeName type, String name) {
+ String candidateName = name;
+ int differentiator = 1;
+ while (fieldWriters.containsKey(candidateName)) {
+ candidateName = name + differentiator;
+ differentiator++;
+ }
+ FieldWriter fieldWriter = new FieldWriter(type, candidateName);
+ fieldWriters.put(candidateName, fieldWriter);
+ return fieldWriter;
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/VariableWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/VariableWriter.java
new file mode 100644
index 000000000..58ee1e494
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/VariableWriter.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class VariableWriter extends Modifiable implements Writable, HasClassReferences {
+ private final TypeName type;
+ private final String name;
+
+ VariableWriter(TypeName type, String name) {
+ this.type = checkNotNull(type);
+ this.name = checkNotNull(name);
+ }
+
+ public TypeName type() {
+ return type;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ writeAnnotations(appendable, context);
+ writeModifiers(appendable);
+ type.write(appendable, context);
+ return appendable.append(' ').append(name);
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(ImmutableList.<HasClassReferences>of())
+ .append(annotations)
+ .append(type)
+ .transformAndConcat(HasClassReferences.COMBINER)
+ .toSet();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/VoidName.java b/compiler/src/main/java/dagger/internal/codegen/writer/VoidName.java
new file mode 100644
index 000000000..f82a4cab4
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/VoidName.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.util.Set;
+
+public enum VoidName implements TypeName {
+ VOID;
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return ImmutableSet.of();
+ }
+
+ @Override
+ public String toString() {
+ return "void";
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ return appendable.append("void");
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/WildcardName.java b/compiler/src/main/java/dagger/internal/codegen/writer/WildcardName.java
new file mode 100644
index 000000000..7756f9311
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/WildcardName.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.util.Set;
+import javax.lang.model.type.WildcardType;
+
+import static dagger.internal.codegen.writer.TypeNames.FOR_TYPE_MIRROR;
+
+public final class WildcardName implements TypeName {
+ private final Optional<TypeName> extendsBound;
+ private final Optional<TypeName> superBound;
+
+ WildcardName(Optional<TypeName> extendsBound,
+ Optional<TypeName> superBound) {
+ this.extendsBound = extendsBound;
+ this.superBound = superBound;
+ }
+
+ static WildcardName forTypeMirror(WildcardType mirror) {
+ return new WildcardName(
+ Optional.fromNullable(mirror.getExtendsBound()).transform(FOR_TYPE_MIRROR),
+ Optional.fromNullable(mirror.getSuperBound()).transform(FOR_TYPE_MIRROR));
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ ImmutableSet.Builder<ClassName> builder = new ImmutableSet.Builder<ClassName>();
+ if (extendsBound.isPresent()) {
+ builder.addAll(extendsBound.get().referencedClasses());
+ }
+ if (superBound.isPresent()) {
+ builder.addAll(superBound.get().referencedClasses());
+ }
+ return builder.build();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ appendable.append('?');
+ if (extendsBound.isPresent()) {
+ appendable.append(" extends ");
+ extendsBound.get().write(appendable, context);
+ }
+ if (superBound.isPresent()) {
+ appendable.append(" super ");
+ superBound.get().write(appendable, context);
+ }
+ return appendable;
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/Writable.java b/compiler/src/main/java/dagger/internal/codegen/writer/Writable.java
new file mode 100644
index 000000000..9a88f433d
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/Writable.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import java.io.IOException;
+import java.util.Set;
+
+interface Writable {
+ interface Context {
+ String sourceReferenceForClassName(ClassName className);
+ Context createSubcontext(Set<ClassName> newTypes);
+ }
+
+ Appendable write(Appendable appendable, Context context) throws IOException;
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/Writables.java b/compiler/src/main/java/dagger/internal/codegen/writer/Writables.java
new file mode 100644
index 000000000..0186cbfcf
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/Writables.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import dagger.internal.codegen.writer.Writable.Context;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Set;
+
+final class Writables {
+
+ /**
+ * Joins the writables by the given delimiter, writing out the
+ * prefix & suffix if there's at least one element.
+ */
+ static void join(String delimiter, Iterable<? extends Writable> writables,
+ String prefix, String suffix,
+ Appendable appendable, Context context) throws IOException {
+ Iterator<? extends Writable> iter = writables.iterator();
+ if (iter.hasNext()) {
+ appendable.append(prefix);
+ iter.next().write(appendable, context);
+ while (iter.hasNext()) {
+ appendable.append(delimiter);
+ iter.next().write(appendable, context);
+ }
+ appendable.append(suffix);
+ }
+ }
+
+ /** Joins the writables by the given delimiter. */
+ static void join(String delimiter, Iterable<? extends Writable> writables,
+ Appendable appendable, Context context) throws IOException {
+ join(delimiter, writables, "", "", appendable, context);
+ }
+
+ static Writable toStringWritable(final Object object) {
+ return new Writable() {
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ return appendable.append(object.toString());
+ }
+ };
+ }
+
+ private static final Context DEFAULT_CONTEXT = new Context() {
+ @Override
+ public String sourceReferenceForClassName(ClassName className) {
+ return className.canonicalName();
+ }
+
+ @Override
+ public Context createSubcontext(Set<ClassName> newTypes) {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+ static String writeToString(Writable writable) {
+ StringBuilder builder = new StringBuilder();
+ try {
+ writable.write(builder, DEFAULT_CONTEXT);
+ } catch (IOException e) {
+ throw new AssertionError("StringBuilder doesn't throw IOException" + e);
+ }
+ return builder.toString();
+ }
+
+ private Writables() {
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/BindingFieldTest.java b/compiler/src/test/java/dagger/internal/codegen/BindingFieldTest.java
new file mode 100644
index 000000000..eaaa595d3
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/BindingFieldTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.Iterables;
+import com.google.testing.compile.CompilationRule;
+import dagger.MembersInjector;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ParameterizedTypeName;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+/**
+ * Test case for {@link FrameworkField}.
+ */
+@RunWith(JUnit4.class)
+public class BindingFieldTest {
+ @Rule public CompilationRule compilationRule = new CompilationRule();
+
+ private Elements elements;
+ private Types types;
+ private Key.Factory keyFactory;
+
+ @Before public void setUp() {
+ this.types = compilationRule.getTypes();
+ this.elements = compilationRule.getElements();
+ this.keyFactory = new Key.Factory(types, elements);
+ }
+
+ private ExecutableElement getXConstructor() {
+ TypeElement classElement = elements.getTypeElement(X.class.getCanonicalName());
+ return Iterables.getOnlyElement(
+ ElementFilter.constructorsIn(classElement.getEnclosedElements()));
+ }
+
+ @Test public void frameworkType() {
+ Key key = keyFactory.forInjectConstructorWithResolvedType(
+ getXConstructor().getEnclosingElement().asType());
+ TypeName xClass = TypeNames.forTypeMirror(key.type());
+ assertThat(FrameworkField.createWithTypeFromKey(Provider.class,
+ BindingKey.create(BindingKey.Kind.CONTRIBUTION, key), "test")
+ .frameworkType())
+ .isEqualTo(ParameterizedTypeName.create(
+ ClassName.fromClass(Provider.class), xClass));
+ assertThat(FrameworkField.createWithTypeFromKey(MembersInjector.class,
+ BindingKey.create(BindingKey.Kind.MEMBERS_INJECTION, key), "test")
+ .frameworkType())
+ .isEqualTo(ParameterizedTypeName.create(
+ ClassName.fromClass(MembersInjector.class), xClass));
+ }
+
+ @Test public void nameSuffix() {
+ Key key = keyFactory.forInjectConstructorWithResolvedType(
+ getXConstructor().getEnclosingElement().asType());
+ assertThat(FrameworkField.createWithTypeFromKey(Provider.class,
+ BindingKey.create(BindingKey.Kind.CONTRIBUTION, key), "foo").name())
+ .isEqualTo("fooProvider");
+ assertThat(FrameworkField.createWithTypeFromKey(Provider.class,
+ BindingKey.create(BindingKey.Kind.CONTRIBUTION, key), "fooProvider").name())
+ .isEqualTo("fooProvider");
+
+ }
+
+ static final class X {
+ @Inject X() {}
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ComponentBuilderTest.java b/compiler/src/test/java/dagger/internal/codegen/ComponentBuilderTest.java
new file mode 100644
index 000000000..20bafff65
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ComponentBuilderTest.java
@@ -0,0 +1,938 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+/** Tests for {@link dagger.Component.Builder} */
+@RunWith(JUnit4.class)
+public class ComponentBuilderTest {
+
+ private static final ErrorMessages.ComponentBuilderMessages MSGS =
+ ErrorMessages.ComponentBuilderMessages.INSTANCE;
+
+ @Test
+ public void testEmptyBuilder() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " SomeInjectableType someInjectableType();",
+ "",
+ " @Component.Builder",
+ " static interface Builder {",
+ " SimpleComponent build();",
+ " }",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import test.SimpleComponent",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static SimpleComponent.Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " }",
+ "",
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return SomeInjectableType_Factory.create().get();",
+ " }",
+ "",
+ " private static final class Builder implements SimpleComponent.Builder {",
+ " @Override",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(injectableTypeFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void testUsesBuildAndSetterNames() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides String string() { return null; }",
+ "}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " String string();",
+ "",
+ " @Component.Builder",
+ " interface Builder {",
+ " Builder setTestModule(TestModule testModule);",
+ " TestComponent create();",
+ " }",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import test.TestComponent;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<String> stringProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static TestComponent.Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().create();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.stringProvider = TestModule_StringFactory.create(builder.testModule);",
+ " }",
+ "",
+ " @Override",
+ " public String string() {",
+ " return stringProvider.get();",
+ " }",
+ "",
+ " private static final class Builder implements TestComponent.Builder {",
+ " private TestModule testModule;",
+ "",
+ " @Override",
+ " public TestComponent create() {",
+ " if (testModule == null) {",
+ " this.testModule = new TestModule();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " @Override",
+ " public Builder setTestModule(TestModule testModule) {",
+ " if (testModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.testModule = testModule;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(moduleFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void testIgnoresModulesNotInApi() {
+ JavaFileObject module1 = JavaFileObjects.forSourceLines("test.TestModule1",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule1 {",
+ " @Provides String string() { return null; }",
+ "}");
+ JavaFileObject module2 = JavaFileObjects.forSourceLines("test.TestModule2",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule2 {",
+ " @Provides Integer integer() { return null; }",
+ "}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = {TestModule1.class, TestModule2.class})",
+ "interface TestComponent {",
+ " String string();",
+ " Integer integer();",
+ "",
+ " @Component.Builder",
+ " interface Builder {",
+ " Builder testModule1(TestModule1 testModule1);",
+ " TestComponent build();",
+ " }",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import test.TestComponent;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<String> stringProvider;",
+ " private Provider<Integer> integerProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static TestComponent.Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.stringProvider = TestModule1_StringFactory.create(builder.testModule1);",
+ " this.integerProvider = TestModule2_IntegerFactory.create(builder.testModule2);",
+ " }",
+ "",
+ " @Override",
+ " public String string() {",
+ " return stringProvider.get();",
+ " }",
+ "",
+ " @Override",
+ " public Integer integer() {",
+ " return integerProvider.get();",
+ " }",
+ "",
+ " private static final class Builder implements TestComponent.Builder {",
+ " private TestModule1 testModule1;",
+ " private TestModule2 testModule2;",
+ "",
+ " @Override",
+ " public TestComponent build() {",
+ " if (testModule1 == null) {",
+ " this.testModule1 = new TestModule1();",
+ " }",
+ " if (testModule2 == null) {",
+ " this.testModule2 = new TestModule2();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " @Override",
+ " public Builder testModule1(TestModule1 testModule1) {",
+ " if (testModule1 == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.testModule1 = testModule1;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(module1, module2, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void testMoreThanOneBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " @Component.Builder",
+ " static interface Builder {",
+ " SimpleComponent build();",
+ " }",
+ "",
+ " @Component.Builder",
+ " interface Builder2 {",
+ " SimpleComponent build();",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(MSGS.moreThanOne(),
+ "[test.SimpleComponent.Builder, test.SimpleComponent.Builder2]"))
+ .in(componentFile);
+ }
+
+ @Test
+ public void testBuilderGenericsFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder<T> {",
+ " SimpleComponent build();",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.generics())
+ .in(componentFile);
+ }
+
+ @Test
+ public void testBuilderNotInComponentFails() {
+ JavaFileObject builder = JavaFileObjects.forSourceLines("test.Builder",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component.Builder",
+ "interface Builder {}");
+ assertAbout(javaSource()).that(builder)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeInComponent())
+ .in(builder);
+ }
+
+ @Test
+ public void testBuilderMissingBuildMethodFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.missingBuildMethod())
+ .in(componentFile);
+ }
+
+ @Test
+ public void testPrivateBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " private interface Builder {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.isPrivate())
+ .in(componentFile);
+ }
+
+ @Test
+ public void testNonStaticBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " abstract class Builder {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeStatic())
+ .in(componentFile);
+ }
+
+ @Test
+ public void testNonAbstractBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " static class Builder {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeAbstract());
+ }
+
+ @Test
+ public void testBuilderOneCxtorWithArgsFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " static abstract class Builder {",
+ " Builder(String unused) {}",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.cxtorOnlyOneAndNoArgs())
+ .in(componentFile);
+ }
+
+ @Test
+ public void testBuilderMoreThanOneCxtorFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " static abstract class Builder {",
+ " Builder() {}",
+ " Builder(String unused) {}",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.cxtorOnlyOneAndNoArgs())
+ .in(componentFile);
+ }
+
+ @Test
+ public void testBuilderEnumFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " enum Builder {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeClassOrInterface())
+ .in(componentFile);
+ }
+
+ @Test
+ public void testBuilderBuildReturnsWrongTypeFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " String build();",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.buildMustReturnComponentType())
+ .in(componentFile).onLine(11);
+ }
+
+ @Test
+ public void testInheritedBuilderBuildReturnsWrongTypeFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " interface Parent {",
+ " String build();",
+ " }",
+ "",
+ " @Component.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedBuildMustReturnComponentType(), "build"))
+ .in(componentFile).onLine(14);
+ }
+
+ @Test
+ public void testTwoBuildMethodsFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " SimpleComponent build();",
+ " SimpleComponent create();",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(MSGS.twoBuildMethods(), "build()"))
+ .in(componentFile).onLine(12);
+ }
+
+ @Test
+ public void testInheritedTwoBuildMethodsFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " interface Parent {",
+ " SimpleComponent build();",
+ " SimpleComponent create();",
+ " }",
+ "",
+ " @Component.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedTwoBuildMethods(), "create()", "build()"))
+ .in(componentFile).onLine(15);
+ }
+
+ @Test
+ public void testMoreThanOneArgFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " SimpleComponent build();",
+ " Builder set(String s, Integer i);",
+ " Builder set(Number n, Double d);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.methodsMustTakeOneArg())
+ .in(componentFile).onLine(12)
+ .and().withErrorContaining(MSGS.methodsMustTakeOneArg())
+ .in(componentFile).onLine(13);
+ }
+
+ @Test
+ public void testInheritedMoreThanOneArgFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " interface Parent {",
+ " SimpleComponent build();",
+ " Builder set1(String s, Integer i);",
+ " }",
+ "",
+ " @Component.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedMethodsMustTakeOneArg(),
+ "set1(java.lang.String,java.lang.Integer)"))
+ .in(componentFile).onLine(15);
+ }
+
+ @Test
+ public void testSetterReturningNonVoidOrBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " SimpleComponent build();",
+ " String set(Integer i);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.methodsMustReturnVoidOrBuilder())
+ .in(componentFile).onLine(12);
+ }
+
+ @Test
+ public void testInheritedSetterReturningNonVoidOrBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " interface Parent {",
+ " SimpleComponent build();",
+ " String set(Integer i);",
+ " }",
+ "",
+ " @Component.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedMethodsMustReturnVoidOrBuilder(),
+ "set(java.lang.Integer)"))
+ .in(componentFile).onLine(15);
+ }
+
+ @Test
+ public void testGenericsOnSetterMethodFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " SimpleComponent build();",
+ " <T> Builder set(T t);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.methodsMayNotHaveTypeParameters())
+ .in(componentFile).onLine(12);
+ }
+
+ @Test
+ public void testGenericsOnInheritedSetterMethodFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " interface Parent {",
+ " SimpleComponent build();",
+ " <T> Builder set(T t);",
+ " }",
+ "",
+ " @Component.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedMethodsMayNotHaveTypeParameters(), "<T>set(T)"))
+ .in(componentFile).onLine(15);
+ }
+
+ @Test
+ public void testMultipleSettersPerTypeFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " SimpleComponent build();",
+ " void set1(String s);",
+ " void set2(String s);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.manyMethodsForType(),
+ "java.lang.String", "[set1(java.lang.String), set2(java.lang.String)]"))
+ .in(componentFile).onLine(10);
+ }
+
+ @Test
+ public void testMultipleSettersPerTypeIncludingResolvedGenericsFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " interface Parent<T> {",
+ " void set1(T t);",
+ " }",
+ "",
+ " @Component.Builder",
+ " interface Builder extends Parent<String> {",
+ " SimpleComponent build();",
+ " void set2(String s);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.manyMethodsForType(),
+ "java.lang.String", "[set1(T), set2(java.lang.String)]"))
+ .in(componentFile).onLine(14);
+ }
+
+ @Test
+ public void testExtraSettersFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " SimpleComponent build();",
+ " void set1(String s);",
+ " void set2(Integer s);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.extraSetters(),
+ "[void test.SimpleComponent.Builder.set1(String),"
+ + " void test.SimpleComponent.Builder.set2(Integer)]"))
+ .in(componentFile).onLine(10);
+
+ }
+
+ @Test
+ public void testMissingSettersFail() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " TestModule(String unused) {}",
+ " @Provides String s() { return null; }",
+ "}");
+ JavaFileObject module2File = JavaFileObjects.forSourceLines("test.Test2Module",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class Test2Module {",
+ " @Provides Integer i() { return null; }",
+ "}");
+ JavaFileObject module3File = JavaFileObjects.forSourceLines("test.Test3Module",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class Test3Module {",
+ " Test3Module(String unused) {}",
+ " @Provides Double d() { return null; }",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = {TestModule.class, Test2Module.class, Test3Module.class},",
+ " dependencies = OtherComponent.class)",
+ "interface TestComponent {",
+ " String string();",
+ " Integer integer();",
+ "",
+ " @Component.Builder",
+ " interface Builder {",
+ " TestComponent create();",
+ " }",
+ "}");
+ JavaFileObject otherComponent = JavaFileObjects.forSourceLines("test.OtherComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface OtherComponent {}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(moduleFile, module2File, module3File, componentFile, otherComponent))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ // Ignores Test2Module because we can construct it ourselves.
+ // TODO(sameb): Ignore Test3Module because it's not used within transitive dependencies.
+ String.format(MSGS.missingSetters(),
+ "[test.TestModule, test.Test3Module, test.OtherComponent]"))
+ .in(componentFile).onLine(12);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ComponentProcessorTest.java b/compiler/src/test/java/dagger/internal/codegen/ComponentProcessorTest.java
new file mode 100644
index 000000000..94e48e2c8
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ComponentProcessorTest.java
@@ -0,0 +1,2016 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.testing.compile.JavaFileObjects;
+import dagger.internal.codegen.writer.StringLiteral;
+import java.io.IOException;
+import java.io.Writer;
+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;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static dagger.internal.codegen.ErrorMessages.REFERENCED_MODULES_MUST_NOT_BE_ABSTRACT;
+import static javax.tools.StandardLocation.SOURCE_OUTPUT;
+
+@RunWith(JUnit4.class)
+public class ComponentProcessorTest {
+ private static final StringLiteral NPE_LITERAL =
+ StringLiteral.forValue(ErrorMessages.CANNOT_RETURN_NULL_FROM_NON_NULLABLE_COMPONENT_METHOD);
+
+ @Test public void componentOnConcreteClass() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "final class NotAComponent {}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("interface");
+ }
+
+ @Test public void componentOnEnum() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "enum NotAComponent {",
+ " INSTANCE",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("interface");
+ }
+
+ @Test public void componentOnAnnotation() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "@interface NotAComponent {}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("interface");
+ }
+
+ @Test public void nonModuleModule() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = Object.class)",
+ "interface NotAComponent {}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("is not annotated with @Module");
+ }
+
+ private void checkCannotReferToModuleOfType(String moduleType) {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ moduleType + " TestModule {}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.BadComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface BadComponent {}");
+ assertAbout(javaSources()).that(ImmutableList.of(moduleFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(REFERENCED_MODULES_MUST_NOT_BE_ABSTRACT, "test.TestModule"));
+ }
+
+ @Test public void cannotReferToAbstractClassModules() {
+ checkCannotReferToModuleOfType("abstract class");
+ }
+
+ @Test public void cannotReferToInterfaceModules() {
+ checkCannotReferToModuleOfType("interface");
+ }
+
+ @Test public void doubleBindingFromResolvedModules() {
+ JavaFileObject parent = JavaFileObjects.forSourceLines("test.ParentModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.List;",
+ "",
+ "@Module",
+ "abstract class ParentModule<A> {",
+ " @Provides List<A> provideListB(A a) { return null; }",
+ "}");
+ JavaFileObject child = JavaFileObjects.forSourceLines("test.ChildModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class ChildNumberModule extends ParentModule<Integer> {",
+ " @Provides Integer provideInteger() { return null; }",
+ "}");
+ JavaFileObject another = JavaFileObjects.forSourceLines("test.AnotherModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.List;",
+ "",
+ "@Module",
+ "class AnotherModule {",
+ " @Provides List<Integer> provideListOfInteger() { return null; }",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.BadComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.List;",
+ "",
+ "@Component(modules = {ChildNumberModule.class, AnotherModule.class})",
+ "interface BadComponent {",
+ " List<Integer> listOfInteger();",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(parent, child, another, componentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile().withErrorContaining(
+ "java.util.List<java.lang.Integer> is bound multiple times")
+ .and().withErrorContaining(
+ "@Provides List<Integer> test.ChildNumberModule.provideListB(Integer)")
+ .and().withErrorContaining(
+ "@Provides List<Integer> test.AnotherModule.provideListOfInteger()");
+ }
+
+ @Test public void simpleComponent() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " SomeInjectableType someInjectableType();",
+ " Lazy<SomeInjectableType> lazySomeInjectableType();",
+ " Provider<SomeInjectableType> someInjectableTypeProvider();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Lazy;",
+ "import dagger.internal.DoubleCheckLazy;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " }",
+ "",
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return SomeInjectableType_Factory.create().get();",
+ " }",
+ "",
+ " @Override",
+ " public Lazy<SomeInjectableType> lazySomeInjectableType() {",
+ " return DoubleCheckLazy.create(SomeInjectableType_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public Provider<SomeInjectableType> someInjectableTypeProvider() {",
+ " return SomeInjectableType_Factory.create();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(injectableTypeFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void componentWithScope() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "import javax.inject.Provider;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "@Component",
+ "interface SimpleComponent {",
+ " SomeInjectableType someInjectableType();",
+ " Lazy<SomeInjectableType> lazySomeInjectableType();",
+ " Provider<SomeInjectableType> someInjectableTypeProvider();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Lazy;",
+ "import dagger.internal.DoubleCheckLazy;",
+ "import dagger.internal.ScopedProvider;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private Provider<SomeInjectableType> someInjectableTypeProvider;",
+ "",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.someInjectableTypeProvider =",
+ " ScopedProvider.create(SomeInjectableType_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return someInjectableTypeProvider.get();",
+ " }",
+ "",
+ " @Override",
+ " public Lazy<SomeInjectableType> lazySomeInjectableType() {",
+ " return DoubleCheckLazy.create(someInjectableTypeProvider);",
+ " }",
+ "",
+ " @Override",
+ " public Provider<SomeInjectableType> someInjectableTypeProvider() {",
+ " return someInjectableTypeProvider;",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(injectableTypeFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void simpleComponentWithNesting() {
+ JavaFileObject nestedTypesFile = JavaFileObjects.forSourceLines("test.OuterType",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Inject;",
+ "",
+ "final class OuterType {",
+ " static class A {",
+ " @Inject A() {}",
+ " }",
+ " static class B {",
+ " @Inject A a;",
+ " }",
+ " @Component interface SimpleComponent {",
+ " A a();",
+ " void inject(B b);",
+ " }",
+ "}");
+
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerOuterType_SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import test.OuterType.A;",
+ "import test.OuterType.B;",
+ "import test.OuterType.SimpleComponent;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerOuterType_SimpleComponent implements SimpleComponent {",
+ " private MembersInjector<B> bMembersInjector;",
+ "",
+ " private DaggerOuterType_SimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.bMembersInjector =",
+ " OuterType$B_MembersInjector.create(OuterType$A_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public A a() {",
+ " return OuterType$A_Factory.create().get();",
+ " }",
+ "",
+ " @Override",
+ " public void inject(B b) {",
+ " bMembersInjector.injectMembers(b);",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerOuterType_SimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(nestedTypesFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void componentWithModule() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A(B b) {}",
+ "}");
+ JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
+ "package test;",
+ "",
+ "interface B {}");
+ JavaFileObject cFile = JavaFileObjects.forSourceLines("test.C",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class C {",
+ " @Inject C() {}",
+ "}");
+
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides B b(C c) { return null; }",
+ "}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " A a();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<B> bProvider;",
+ " private Provider<A> aProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.bProvider = TestModule_BFactory.create(builder.testModule,",
+ " C_Factory.create());",
+ " this.aProvider = A_Factory.create(bProvider);",
+ " }",
+ "",
+ " @Override",
+ " public A a() {",
+ " return aProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private TestModule testModule;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (testModule == null) {",
+ " this.testModule = new TestModule();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder testModule(TestModule testModule) {",
+ " if (testModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.testModule = testModule;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(aFile, bFile, cFile, moduleFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void transitiveModuleDeps() {
+ JavaFileObject always = JavaFileObjects.forSourceLines("test.AlwaysIncluded",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class AlwaysIncluded {}");
+ JavaFileObject testModule = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = {DepModule.class, AlwaysIncluded.class})",
+ "final class TestModule extends ParentTestModule {}");
+ JavaFileObject parentTest = JavaFileObjects.forSourceLines("test.ParentTestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = {ParentTestIncluded.class, AlwaysIncluded.class})",
+ "class ParentTestModule {}");
+ JavaFileObject parentTestIncluded = JavaFileObjects.forSourceLines("test.ParentTestIncluded",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = AlwaysIncluded.class)",
+ "final class ParentTestIncluded {}");
+ JavaFileObject depModule = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = {RefByDep.class, AlwaysIncluded.class})",
+ "final class DepModule extends ParentDepModule {}");
+ JavaFileObject refByDep = JavaFileObjects.forSourceLines("test.RefByDep",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = AlwaysIncluded.class)",
+ "final class RefByDep extends ParentDepModule {}");
+ JavaFileObject parentDep = JavaFileObjects.forSourceLines("test.ParentDepModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = {ParentDepIncluded.class, AlwaysIncluded.class})",
+ "class ParentDepModule {}");
+ JavaFileObject parentDepIncluded = JavaFileObjects.forSourceLines("test.ParentDepIncluded",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = AlwaysIncluded.class)",
+ "final class ParentDepIncluded {}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ "}");
+ // Generated code includes all includes, but excludes the parent modules.
+ // The "always" module should only be listed once.
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " @Deprecated",
+ " public Builder testModule(TestModule testModule) {",
+ " if (testModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " return this;",
+ " }",
+ "",
+ " @Deprecated",
+ " public Builder parentTestIncluded(ParentTestIncluded parentTestIncluded) {",
+ " if (parentTestIncluded == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " return this;",
+ " }",
+ "",
+ " @Deprecated",
+ " public Builder alwaysIncluded(AlwaysIncluded alwaysIncluded) {",
+ " if (alwaysIncluded == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " return this;",
+ " }",
+ "",
+ " @Deprecated",
+ " public Builder depModule(DepModule depModule) {",
+ " if (depModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " return this;",
+ " }",
+ "",
+ " @Deprecated",
+ " public Builder parentDepIncluded(ParentDepIncluded parentDepIncluded) {",
+ " if (parentDepIncluded == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " return this;",
+ " }",
+ "",
+ " @Deprecated",
+ " public Builder refByDep(RefByDep refByDep) {",
+ " if (refByDep == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(always,
+ testModule,
+ parentTest,
+ parentTestIncluded,
+ depModule,
+ refByDep,
+ parentDep,
+ parentDepIncluded,
+ componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void generatedTransitiveModule() {
+ JavaFileObject rootModule = JavaFileObjects.forSourceLines("test.RootModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = GeneratedModule.class)",
+ "final class RootModule {}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = RootModule.class)",
+ "interface TestComponent {}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(rootModule, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile();
+ assertAbout(javaSources())
+ .that(ImmutableList.of(rootModule, component))
+ .processedWith(
+ new ComponentProcessor(),
+ new GeneratingProcessor(
+ "test.GeneratedModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class GeneratedModule {}"))
+ .compilesWithoutError();
+ }
+
+ @Test
+ public void generatedModuleInSubcomponent() {
+ JavaFileObject subcomponent =
+ JavaFileObjects.forSourceLines(
+ "test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = GeneratedModule.class)",
+ "interface ChildComponent {}");
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " ChildComponent childComponent();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(subcomponent, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile();
+ assertAbout(javaSources())
+ .that(ImmutableList.of(subcomponent, component))
+ .processedWith(
+ new ComponentProcessor(),
+ new GeneratingProcessor(
+ "test.GeneratedModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class GeneratedModule {}"))
+ .compilesWithoutError();
+ }
+
+ @Test public void testDefaultPackage() {
+ JavaFileObject aClass = JavaFileObjects.forSourceLines("AClass", "class AClass {}");
+ JavaFileObject bClass = JavaFileObjects.forSourceLines("BClass",
+ "import javax.inject.Inject;",
+ "",
+ "class BClass {",
+ " @Inject BClass(AClass a) {}",
+ "}");
+ JavaFileObject aModule = JavaFileObjects.forSourceLines("AModule",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module class AModule {",
+ " @Provides AClass aClass() {",
+ " return new AClass();",
+ " }",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("SomeComponent",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = AModule.class)",
+ "interface SomeComponent {",
+ " BClass bClass();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(aModule, aClass, bClass, component))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @Test public void setBindings() {
+ JavaFileObject emptySetModuleFile = JavaFileObjects.forSourceLines("test.EmptySetModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET_VALUES;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.Collections;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "final class EmptySetModule {",
+ " @Provides(type = SET_VALUES) Set<String> emptySet() { return Collections.emptySet(); }",
+ "}");
+ JavaFileObject setModuleFile = JavaFileObjects.forSourceLines("test.SetModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class SetModule {",
+ " @Provides(type = SET) String string() { return \"\"; }",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {EmptySetModule.class, SetModule.class})",
+ "interface TestComponent {",
+ " Set<String> strings();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.internal.SetFactory;",
+ "import java.util.Set;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Set<String>> setOfStringContribution1Provider;",
+ " private Provider<Set<String>> setOfStringContribution2Provider;",
+ " private Provider<Set<String>> setOfStringProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.setOfStringContribution1Provider =",
+ " EmptySetModule_EmptySetFactory.create(builder.emptySetModule);",
+ " this.setOfStringContribution2Provider =",
+ " SetModule_StringFactory.create(builder.setModule);",
+ " this.setOfStringProvider = SetFactory.create(",
+ " setOfStringContribution1Provider, setOfStringContribution2Provider);",
+ " }",
+ "",
+ " @Override",
+ " public Set<String> strings() {",
+ " return setOfStringProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private EmptySetModule emptySetModule;",
+ " private SetModule setModule;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (emptySetModule == null) {",
+ " this.emptySetModule = new EmptySetModule();",
+ " }",
+ " if (setModule == null) {",
+ " this.setModule = new SetModule();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder emptySetModule(EmptySetModule emptySetModule) {",
+ " if (emptySetModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.emptySetModule = emptySetModule;",
+ " return this;",
+ " }",
+ "",
+ " public Builder setModule(SetModule setModule) {",
+ " if (setModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.setModule = setModule;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(emptySetModuleFile, setModuleFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void membersInjection() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject injectedTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectedType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectedType {",
+ " @Inject SomeInjectableType injectedField;",
+ " SomeInjectedType() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " void inject(SomeInjectedType instance);",
+ " SomeInjectedType injectAndReturn(SomeInjectedType instance);",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private MembersInjector<SomeInjectedType> someInjectedTypeMembersInjector;",
+ "",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.someInjectedTypeMembersInjector =",
+ " SomeInjectedType_MembersInjector.create(SomeInjectableType_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public void inject(SomeInjectedType instance) {",
+ " someInjectedTypeMembersInjector.injectMembers(instance);",
+ " }",
+ "",
+ " @Override",
+ " public SomeInjectedType injectAndReturn(SomeInjectedType instance) {",
+ " someInjectedTypeMembersInjector.injectMembers(instance);",
+ " return instance;",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(injectableTypeFile, injectedTypeFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void componentInjection() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType(SimpleComponent component) {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " SomeInjectableType someInjectableType();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import dagger.internal.InstanceFactory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private Provider<SimpleComponent> simpleComponentProvider;",
+ " private Provider<SomeInjectableType> someInjectableTypeProvider;",
+ "",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.simpleComponentProvider = InstanceFactory.<SimpleComponent>create(this);",
+ " this.someInjectableTypeProvider =",
+ " SomeInjectableType_Factory.create(simpleComponentProvider);",
+ " }",
+ "",
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return someInjectableTypeProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(injectableTypeFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void membersInjectionInsideProvision() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject injectedTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectedType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectedType {",
+ " @Inject SomeInjectableType injectedField;",
+ " @Inject SomeInjectedType() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " SomeInjectedType createAndInject();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private MembersInjector<SomeInjectedType> someInjectedTypeMembersInjector;",
+ " private Provider<SomeInjectedType> someInjectedTypeProvider;",
+ "",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.someInjectedTypeMembersInjector =",
+ " SomeInjectedType_MembersInjector.create(SomeInjectableType_Factory.create());",
+ " this.someInjectedTypeProvider =",
+ " SomeInjectedType_Factory.create(someInjectedTypeMembersInjector);",
+ " }",
+ "",
+ " @Override",
+ " public SomeInjectedType createAndInject() {",
+ " return someInjectedTypeProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(injectableTypeFile, injectedTypeFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void injectionWithGenericBaseClass() {
+ JavaFileObject genericType = JavaFileObjects.forSourceLines("test.AbstractGenericType",
+ "package test;",
+ "",
+ "abstract class AbstractGenericType<T> {",
+ "}");
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType extends AbstractGenericType<String> {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " SomeInjectableType someInjectableType();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.MembersInjectors;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private Provider<SomeInjectableType> someInjectableTypeProvider;",
+ "",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.someInjectableTypeProvider =",
+ " SomeInjectableType_Factory.create((MembersInjector) MembersInjectors.noOp());",
+ " }",
+ "",
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return someInjectableTypeProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(genericType, injectableTypeFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void componentDependency() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A() {}",
+ "}");
+ JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class B {",
+ " @Inject B(A a) {}",
+ "}");
+ JavaFileObject aComponentFile = JavaFileObjects.forSourceLines("test.AComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface AComponent {",
+ " A a();",
+ "}");
+ JavaFileObject bComponentFile = JavaFileObjects.forSourceLines("test.AComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(dependencies = AComponent.class)",
+ "interface BComponent {",
+ " B b();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerBComponent",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerBComponent implements BComponent {",
+ " private Provider<A> aProvider;",
+ " private Provider<B> bProvider;",
+ "",
+ " private DaggerBComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.aProvider = new Factory<A>() {",
+ " private final AComponent aComponent = builder.aComponent;",
+ " @Override public A get() {",
+ " A provided = aComponent.a();",
+ " if (provided == null) {",
+ " throw new NullPointerException(" + NPE_LITERAL + ");",
+ " }",
+ " return provided;",
+ " }",
+ " };",
+ " this.bProvider = B_Factory.create(aProvider);",
+ " }",
+ "",
+ " @Override",
+ " public B b() {",
+ " return bProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private AComponent aComponent;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public BComponent build() {",
+ " if (aComponent == null) {",
+ " throw new IllegalStateException(AComponent.class.getCanonicalName()",
+ " + \" must be set\");",
+ " }",
+ " return new DaggerBComponent(this);",
+ " }",
+ "",
+ " public Builder aComponent(AComponent aComponent) {",
+ " if (aComponent == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.aComponent = aComponent;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(aFile, bFile, aComponentFile, bComponentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void moduleNameCollision() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "public final class A {}");
+ JavaFileObject otherAFile = JavaFileObjects.forSourceLines("other.test.A",
+ "package other.test;",
+ "",
+ "public final class A {}");
+
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "public final class TestModule {",
+ " @Provides A a() { return null; }",
+ "}");
+ JavaFileObject otherModuleFile = JavaFileObjects.forSourceLines("other.test.TestModule",
+ "package other.test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "public final class TestModule {",
+ " @Provides A a() { return null; }",
+ "}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {TestModule.class, other.test.TestModule.class})",
+ "interface TestComponent {",
+ " A a();",
+ " other.test.A otherA();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import other.test.A;",
+ "import other.test.TestModule;",
+ "import other.test.TestModule_AFactory;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<test.A> aProvider;",
+ " private Provider<A> aProvider1;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.aProvider = test.TestModule_AFactory.create(builder.testModule);",
+ " this.aProvider1 = TestModule_AFactory.create(builder.testModule1);",
+ " }",
+ "",
+ " @Override",
+ " public test.A a() {",
+ " return aProvider.get();",
+ " }",
+ "",
+ " @Override",
+ " public A otherA() {",
+ " return aProvider1.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private test.TestModule testModule;",
+ " private TestModule testModule1;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (testModule == null) {",
+ " this.testModule = new test.TestModule();",
+ " }",
+ " if (testModule1 == null) {",
+ " this.testModule1 = new TestModule();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder testModule(test.TestModule testModule) {",
+ " if (testModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.testModule = testModule;",
+ " return this;",
+ " }",
+ "",
+ " public Builder testModule(TestModule testModule) {",
+ " if (testModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.testModule1 = testModule;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(aFile, otherAFile, moduleFile, otherModuleFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void resolutionOrder() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A(B b) {}",
+ "}");
+ JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class B {",
+ " @Inject B(C c) {}",
+ "}");
+ JavaFileObject cFile = JavaFileObjects.forSourceLines("test.C",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class C {",
+ " @Inject C() {}",
+ "}");
+ JavaFileObject xFile = JavaFileObjects.forSourceLines("test.X",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class X {",
+ " @Inject X(C c) {}",
+ "}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " A a();",
+ " C c();",
+ " X x();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<B> bProvider;",
+ " private Provider<A> aProvider;",
+ " private Provider<X> xProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.bProvider = B_Factory.create(C_Factory.create());",
+ " this.aProvider = A_Factory.create(bProvider);",
+ " this.xProvider = X_Factory.create(C_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public A a() {",
+ " return aProvider.get();",
+ " }",
+ "",
+ " @Override",
+ " public C c() {",
+ " return C_Factory.create().get();",
+ " }",
+ "",
+ " @Override",
+ " public X x() {",
+ " return xProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " return new DaggerTestComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(aFile, bFile, cFile, xFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void simpleComponent_redundantComponentMethod() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject componentSupertypeAFile = JavaFileObjects.forSourceLines("test.SupertypeA",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SupertypeA {",
+ " SomeInjectableType someInjectableType();",
+ "}");
+ JavaFileObject componentSupertypeBFile = JavaFileObjects.forSourceLines("test.SupertypeB",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SupertypeB {",
+ " SomeInjectableType someInjectableType();",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent extends SupertypeA, SupertypeB {",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {}",
+ "",
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return SomeInjectableType_Factory.create().get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(
+ injectableTypeFile, componentSupertypeAFile, componentSupertypeBFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void simpleComponent_inheritedComponentMethodDep() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject componentSupertype = JavaFileObjects.forSourceLines("test.Supertype",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface Supertype {",
+ " SomeInjectableType someInjectableType();",
+ "}");
+ JavaFileObject depComponentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent extends Supertype {",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ComponentWithDep",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(dependencies = SimpleComponent.class)",
+ "interface ComponentWithDep {",
+ " SomeInjectableType someInjectableType();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {}",
+ "",
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return SomeInjectableType_Factory.create().get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(
+ injectableTypeFile, componentSupertype, depComponentFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void wildcardGenericsRequiresAtProvides() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A() {}",
+ "}");
+ JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class B<T> {",
+ " @Inject B(T t) {}",
+ "}");
+ JavaFileObject cFile = JavaFileObjects.forSourceLines("test.C",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class C {",
+ " @Inject C(B<? extends A> bA) {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " C c();",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(aFile, bFile, cFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ "test.B<? extends test.A> cannot be provided without an @Provides-annotated method");
+ }
+ @Test
+ public void componentImplicitlyDependsOnGeneratedType() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType(GeneratedType generatedType) {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " SomeInjectableType someInjectableType();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(injectableTypeFile, componentFile))
+ .processedWith(
+ new ComponentProcessor(),
+ new GeneratingProcessor(
+ "test.GeneratedType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class GeneratedType {",
+ " @Inject GeneratedType() {}",
+ "}"))
+ .compilesWithoutError()
+ .and()
+ .generatesFileNamed(SOURCE_OUTPUT, "test", "DaggerSimpleComponent.java");
+ }
+ @Test
+ public void componentSupertypeDependsOnGeneratedType() {
+ JavaFileObject componentFile =
+ JavaFileObjects.forSourceLines(
+ "test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface SimpleComponent extends SimpleComponentInterface {}");
+ JavaFileObject interfaceFile =
+ JavaFileObjects.forSourceLines(
+ "test.SimpleComponentInterface",
+ "package test;",
+ "",
+ "interface SimpleComponentInterface {",
+ " GeneratedType generatedType();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(componentFile, interfaceFile))
+ .processedWith(
+ new ComponentProcessor(),
+ new GeneratingProcessor(
+ "test.GeneratedType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class GeneratedType {",
+ " @Inject GeneratedType() {}",
+ "}"))
+ .compilesWithoutError()
+ .and()
+ .generatesFileNamed(SOURCE_OUTPUT, "test", "DaggerSimpleComponent.java");
+ }
+
+ @Test
+ @Ignore // modify this test as necessary while debugging for your situation.
+ @SuppressWarnings("unused")
+ public void genericTestToLetMeDebugInEclipse() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public final class A {",
+ " @Inject A() {}",
+ "}");
+ JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "public class B<T> {",
+ " @Inject B() {}",
+ "}");
+ JavaFileObject dFile = JavaFileObjects.forSourceLines("test.sub.D",
+ "package test.sub;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "import test.B;",
+ "",
+ "public class D {",
+ " @Inject D(B<A.InA> ba) {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " B<A> d();",
+ " Provider<B<A>> d2();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private Provider<D> dProvider;",
+ "",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.dProvider = new D_Factory(B_Factory.INSTANCE);",
+ " }",
+ "",
+ " @Override",
+ " public D d() {",
+ " return dProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(aFile, bFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ /**
+ * A simple {@link Processor} that generates one source file.
+ */
+ private static final class GeneratingProcessor extends AbstractProcessor {
+ private final String generatedClassName;
+ private final String generatedSource;
+ private boolean processed;
+
+ GeneratingProcessor(String generatedClassName, String... source) {
+ this.generatedClassName = generatedClassName;
+ this.generatedSource = Joiner.on("\n").join(source);
+ }
+
+ @Override
+ public Set<String> getSupportedAnnotationTypes() {
+ return ImmutableSet.of("*");
+ }
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (!processed) {
+ processed = true;
+ try (Writer writer =
+ processingEnv.getFiler().createSourceFile(generatedClassName).openWriter()) {
+ writer.append(generatedSource);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/DependencyRequestMapperTest.java b/compiler/src/test/java/dagger/internal/codegen/DependencyRequestMapperTest.java
new file mode 100644
index 000000000..7766f244a
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/DependencyRequestMapperTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.Iterables;
+import com.google.testing.compile.CompilationRule;
+import dagger.Lazy;
+import dagger.MembersInjector;
+import dagger.Module;
+import dagger.Provides;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.util.List;
+import javax.inject.Provider;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+/**
+ * Test case for {@link DependencyRequestMapper}.
+ */
+@RunWith(JUnit4.class)
+public class DependencyRequestMapperTest {
+ @Rule public CompilationRule compilationRule = new CompilationRule();
+
+ private Elements elements;
+ private Types types;
+ private Key.Factory keyFactory;
+ private DependencyRequest.Factory dependencyRequestFactory;
+
+ @Before public void setUp() {
+ this.types = compilationRule.getTypes();
+ this.elements = compilationRule.getElements();
+ this.keyFactory = new Key.Factory(types, elements);
+ this.dependencyRequestFactory = new DependencyRequest.Factory(keyFactory);
+ }
+
+ private List<? extends VariableElement> sampleProviderParameters() {
+ TypeElement moduleElement =
+ elements.getTypeElement(ProvidesMethodModule.class.getCanonicalName());
+ ExecutableElement providesMethod =
+ Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements()));
+ return providesMethod.getParameters();
+ }
+
+ private List<? extends VariableElement> sampleProducerParameters() {
+ TypeElement moduleElement =
+ elements.getTypeElement(ProducesMethodModule.class.getCanonicalName());
+ ExecutableElement producesMethod =
+ Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements()));
+ return producesMethod.getParameters();
+ }
+
+ private DependencyRequest dependencyRequestForInstance() {
+ return dependencyRequestFactory.forRequiredVariable(sampleProviderParameters().get(0));
+ }
+
+ private DependencyRequest dependencyRequestForLazy() {
+ return dependencyRequestFactory.forRequiredVariable(sampleProviderParameters().get(1));
+ }
+
+ private DependencyRequest dependencyRequestForProvider() {
+ return dependencyRequestFactory.forRequiredVariable(sampleProviderParameters().get(2));
+ }
+
+ private DependencyRequest dependencyRequestForMembersInjector() {
+ return dependencyRequestFactory.forRequiredVariable(sampleProviderParameters().get(3));
+ }
+
+ private DependencyRequest dependencyRequestForProducer() {
+ return dependencyRequestFactory.forRequiredVariable(sampleProducerParameters().get(0));
+ }
+
+ private DependencyRequest dependencyRequestForProduced() {
+ return dependencyRequestFactory.forRequiredVariable(sampleProducerParameters().get(1));
+ }
+
+ @Test public void forProvider() {
+ DependencyRequestMapper mapper = DependencyRequestMapper.FOR_PROVIDER;
+ assertThat(mapper.getFrameworkClass(dependencyRequestForInstance()))
+ .isEqualTo(Provider.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForLazy()))
+ .isEqualTo(Provider.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForProvider()))
+ .isEqualTo(Provider.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForMembersInjector()))
+ .isEqualTo(MembersInjector.class);
+ }
+
+ @Test public void forProducer() {
+ DependencyRequestMapper mapper = DependencyRequestMapper.FOR_PRODUCER;
+ assertThat(mapper.getFrameworkClass(dependencyRequestForInstance()))
+ .isEqualTo(Producer.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForLazy()))
+ .isEqualTo(Provider.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForProvider()))
+ .isEqualTo(Provider.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForMembersInjector()))
+ .isEqualTo(MembersInjector.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForProducer()))
+ .isEqualTo(Producer.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForProduced()))
+ .isEqualTo(Producer.class);
+ }
+
+ @Module
+ static final class ProvidesMethodModule {
+ @Provides String provideString(
+ Integer a, Lazy<Integer> b, Provider<Integer> c, MembersInjector<Y> d) {
+ return null;
+ }
+ }
+
+ @ProducerModule
+ static final class ProducesMethodModule {
+ @Produces String produceString(Producer<Integer> a, Produced<Integer> b) {
+ return null;
+ }
+ }
+
+ static final class Y {}
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ErrorMessagesTest.java b/compiler/src/test/java/dagger/internal/codegen/ErrorMessagesTest.java
new file mode 100644
index 000000000..141d5c452
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ErrorMessagesTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class ErrorMessagesTest {
+ @Test public void stripCommonTypePrefixes() {
+ String typeName = "com.google.common.collect.ImmutableList<java.lang.Boolean>";
+ assertThat(ErrorMessages.stripCommonTypePrefixes(typeName)).isEqualTo("ImmutableList<Boolean>");
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/GraphValidationScopingTest.java b/compiler/src/test/java/dagger/internal/codegen/GraphValidationScopingTest.java
new file mode 100644
index 000000000..e207fe0ee
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/GraphValidationScopingTest.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assert_;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static java.util.Arrays.asList;
+
+@RunWith(JUnit4.class)
+public class GraphValidationScopingTest {
+ @Test public void componentWithoutScopeIncludesScopedBindings_Fail() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Component(modules = ScopedModule.class)",
+ "interface MyComponent {",
+ " ScopedType string();",
+ "}");
+ JavaFileObject typeFile = JavaFileObjects.forSourceLines("test.ScopedType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "class ScopedType {",
+ " @Inject ScopedType(String s, long l, float f) {}",
+ "}");
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.ScopedModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Module",
+ "class ScopedModule {",
+ " @Provides @Singleton String string() { return \"a string\"; }",
+ " @Provides long integer() { return 0L; }",
+ " @Provides float floatingPoint() { return 0.0f; }",
+ "}");
+ String errorMessage = "test.MyComponent (unscoped) may not reference scoped bindings:\n"
+ + " @Provides @Singleton String test.ScopedModule.string()\n"
+ + " @Singleton class test.ScopedType";
+ assert_().about(javaSources()).that(asList(componentFile, typeFile, moduleFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage);
+ }
+
+ @Test public void componentWithScopeIncludesIncompatiblyScopedBindings_Fail() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "@Component(modules = ScopedModule.class)",
+ "interface MyComponent {",
+ " ScopedType string();",
+ "}");
+ JavaFileObject scopeFile = JavaFileObjects.forSourceLines("test.PerTest",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope",
+ "@interface PerTest {}");
+ JavaFileObject typeFile = JavaFileObjects.forSourceLines("test.ScopedType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "@PerTest", // incompatible scope
+ "class ScopedType {",
+ " @Inject ScopedType(String s, long l, float f) {}",
+ "}");
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.ScopedModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Module",
+ "class ScopedModule {",
+ " @Provides @PerTest String string() { return \"a string\"; }", // incompatible scope
+ " @Provides long integer() { return 0L; }", // unscoped - valid
+ " @Provides @Singleton float floatingPoint() { return 0.0f; }", // same scope - valid
+ "}");
+ String errorMessage = "test.MyComponent scoped with @Singleton "
+ + "may not reference bindings with different scopes:\n"
+ + " @Provides @test.PerTest String test.ScopedModule.string()\n"
+ + " @test.PerTest class test.ScopedType";
+ assert_().about(javaSources()).that(asList(componentFile, scopeFile, typeFile, moduleFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage);
+ }
+
+ @Test public void componentWithScopeMayDependOnOnlyOneScopedComponent() {
+ // If a scoped component will have dependencies, they must only include, at most, a single
+ // scoped component
+ JavaFileObject type = JavaFileObjects.forSourceLines("test.SimpleType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class SimpleType {",
+ " @Inject SimpleType() {}",
+ " static class A { @Inject A() {} }",
+ " static class B { @Inject B() {} }",
+ "}");
+ JavaFileObject simpleScope = JavaFileObjects.forSourceLines("test.SimpleScope",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope @interface SimpleScope {}");
+ JavaFileObject singletonScopedA = JavaFileObjects.forSourceLines("test.SingletonComponentA",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "@Component",
+ "interface SingletonComponentA {",
+ " SimpleType.A type();",
+ "}");
+ JavaFileObject singletonScopedB = JavaFileObjects.forSourceLines("test.SingletonComponentB",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "@Component",
+ "interface SingletonComponentB {",
+ " SimpleType.B type();",
+ "}");
+ JavaFileObject scopeless = JavaFileObjects.forSourceLines("test.ScopelessComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface ScopelessComponent {",
+ " SimpleType type();",
+ "}");
+ JavaFileObject simpleScoped = JavaFileObjects.forSourceLines("test.SimpleScopedComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@SimpleScope",
+ "@Component(dependencies = {SingletonComponentA.class, SingletonComponentB.class})",
+ "interface SimpleScopedComponent {",
+ " SimpleType.A type();",
+ "}");
+ String errorMessage =
+ "@test.SimpleScope test.SimpleScopedComponent depends on more than one scoped component:\n"
+ + " @Singleton test.SingletonComponentA\n"
+ + " @Singleton test.SingletonComponentB";
+ assert_().about(javaSources())
+ .that(
+ asList(type, simpleScope, simpleScoped, singletonScopedA, singletonScopedB, scopeless))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage);
+ }
+
+ @Test public void componentWithoutScopeCannotDependOnScopedComponent() {
+ JavaFileObject type = JavaFileObjects.forSourceLines("test.SimpleType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class SimpleType {",
+ " @Inject SimpleType() {}",
+ "}");
+ JavaFileObject scopedComponent = JavaFileObjects.forSourceLines("test.ScopedComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "@Component",
+ "interface ScopedComponent {",
+ " SimpleType type();",
+ "}");
+ JavaFileObject unscopedComponent = JavaFileObjects.forSourceLines("test.UnscopedComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Component(dependencies = ScopedComponent.class)",
+ "interface UnscopedComponent {",
+ " SimpleType type();",
+ "}");
+ String errorMessage =
+ "test.UnscopedComponent (unscoped) cannot depend on scoped components:\n"
+ + " @Singleton test.ScopedComponent";
+ assert_().about(javaSources())
+ .that(asList(type, scopedComponent, unscopedComponent))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage);
+ }
+
+ @Test public void componentWithSingletonScopeMayNotDependOnOtherScope() {
+ // Singleton must be the widest lifetime of present scopes.
+ JavaFileObject type = JavaFileObjects.forSourceLines("test.SimpleType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class SimpleType {",
+ " @Inject SimpleType() {}",
+ "}");
+ JavaFileObject simpleScope = JavaFileObjects.forSourceLines("test.SimpleScope",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope @interface SimpleScope {}");
+ JavaFileObject simpleScoped = JavaFileObjects.forSourceLines("test.SimpleScopedComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@SimpleScope",
+ "@Component",
+ "interface SimpleScopedComponent {",
+ " SimpleType type();",
+ "}");
+ JavaFileObject singletonScoped = JavaFileObjects.forSourceLines("test.SingletonComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "@Component(dependencies = SimpleScopedComponent.class)",
+ "interface SingletonComponent {",
+ " SimpleType type();",
+ "}");
+ String errorMessage =
+ "This @Singleton component cannot depend on scoped components:\n"
+ + " @test.SimpleScope test.SimpleScopedComponent";
+ assert_().about(javaSources())
+ .that(asList(type, simpleScope, simpleScoped, singletonScoped))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage);
+ }
+
+ @Test public void componentScopeAncestryMustNotCycle() {
+ // The dependency relationship of components is necessarily from shorter lifetimes to
+ // longer lifetimes. The scoping annotations must reflect this, and so one cannot declare
+ // scopes on components such that they cycle.
+ JavaFileObject type = JavaFileObjects.forSourceLines("test.SimpleType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class SimpleType {",
+ " @Inject SimpleType() {}",
+ "}");
+ JavaFileObject scopeA = JavaFileObjects.forSourceLines("test.ScopeA",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope @interface ScopeA {}");
+ JavaFileObject scopeB = JavaFileObjects.forSourceLines("test.ScopeB",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope @interface ScopeB {}");
+ JavaFileObject longLifetime = JavaFileObjects.forSourceLines("test.ComponentLong",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@ScopeA",
+ "@Component",
+ "interface ComponentLong {",
+ " SimpleType type();",
+ "}");
+ JavaFileObject mediumLifetime = JavaFileObjects.forSourceLines("test.ComponentMedium",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@ScopeB",
+ "@Component(dependencies = ComponentLong.class)",
+ "interface ComponentMedium {",
+ " SimpleType type();",
+ "}");
+ JavaFileObject shortLifetime = JavaFileObjects.forSourceLines("test.ComponentShort",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@ScopeA",
+ "@Component(dependencies = ComponentMedium.class)",
+ "interface ComponentShort {",
+ " SimpleType type();",
+ "}");
+ String errorMessage =
+ "test.ComponentShort depends on scoped components in a non-hierarchical scope ordering:\n"
+ + " @test.ScopeA test.ComponentLong\n"
+ + " @test.ScopeB test.ComponentMedium\n"
+ + " @test.ScopeA test.ComponentShort";
+ assert_().about(javaSources())
+ .that(asList(type, scopeA, scopeB, longLifetime, mediumLifetime, shortLifetime))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/GraphValidationTest.java b/compiler/src/test/java/dagger/internal/codegen/GraphValidationTest.java
new file mode 100644
index 000000000..36303f1e9
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/GraphValidationTest.java
@@ -0,0 +1,1123 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import java.util.Arrays;
+import javax.tools.JavaFileObject;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static dagger.internal.codegen.ErrorMessages.NULLABLE_TO_NON_NULLABLE;
+import static java.util.Arrays.asList;
+
+@RunWith(JUnit4.class)
+public class GraphValidationTest {
+ private final JavaFileObject NULLABLE = JavaFileObjects.forSourceLines("test.Nullable",
+ "package test;",
+ "public @interface Nullable {}");
+
+ @Test public void componentOnConcreteClass() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface MyComponent {",
+ " Foo getFoo();",
+ "}");
+ JavaFileObject injectable = JavaFileObjects.forSourceLines("test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Foo {",
+ " @Inject Foo(Bar bar) {}",
+ "}");
+ JavaFileObject nonInjectable = JavaFileObjects.forSourceLines("test.Bar",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "interface Bar {}");
+ assertAbout(javaSources()).that(Arrays.asList(component, injectable, nonInjectable))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("test.Bar cannot be provided without an @Provides-annotated method.")
+ .in(component).onLine(7);
+ }
+
+ @Test public void componentProvisionWithNoDependencyChain() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "final class TestClass {",
+ " interface A {}",
+ "",
+ " @Component()",
+ " interface AComponent {",
+ " A getA();",
+ " }",
+ "}");
+ String expectedError =
+ "test.TestClass.A cannot be provided without an @Provides-annotated method.";
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(10);
+ }
+
+ @Test public void constructorInjectionWithoutAnnotation() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "final class TestClass {",
+ " static class A {",
+ " A() {}",
+ " }",
+ "",
+ " @Component()",
+ " interface AComponent {",
+ " A getA();",
+ " }",
+ "}");
+ String expectedError = "test.TestClass.A cannot be provided without an "
+ + "@Inject constructor or from an @Provides-annotated method.";
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(15);
+ }
+
+ @Test public void membersInjectWithoutProvision() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "final class TestClass {",
+ " static class A {",
+ " @Inject A() {}",
+ " }",
+ "",
+ " static class B {",
+ " @Inject A a;",
+ " }",
+ "",
+ " @Component()",
+ " interface AComponent {",
+ " B getB();",
+ " }",
+ "}");
+ String expectedError = "test.TestClass.B cannot be provided without an "
+ + "@Inject constructor or from an @Provides-annotated method. "
+ + "This type supports members injection but cannot be implicitly provided.";
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(19);
+ }
+
+ @Test public void cyclicDependency() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "final class Outer {",
+ " static class A {",
+ " @Inject A(C cParam) {}",
+ " }",
+ "",
+ " static class B {",
+ " @Inject B(A aParam) {}",
+ " }",
+ "",
+ " static class C {",
+ " @Inject C(B bParam) {}",
+ " }",
+ "",
+ " @Component()",
+ " interface CComponent {",
+ " C getC();",
+ " }",
+ "}");
+
+ String expectedError = "test.Outer.CComponent.getC() contains a dependency cycle:\n"
+ + " test.Outer.C.<init>(test.Outer.B bParam)\n"
+ + " [parameter: test.Outer.B bParam]\n"
+ + " test.Outer.B.<init>(test.Outer.A aParam)\n"
+ + " [parameter: test.Outer.A aParam]\n"
+ + " test.Outer.A.<init>(test.Outer.C cParam)\n"
+ + " [parameter: test.Outer.C cParam]";
+
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(23);
+ }
+
+ @Test public void cyclicDependencyNotIncludingEntryPoint() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "final class Outer {",
+ " static class A {",
+ " @Inject A(C cParam) {}",
+ " }",
+ "",
+ " static class B {",
+ " @Inject B(A aParam) {}",
+ " }",
+ "",
+ " static class C {",
+ " @Inject C(B bParam) {}",
+ " }",
+ "",
+ " static class D {",
+ " @Inject D(C cParam) {}",
+ " }",
+ "",
+ " @Component()",
+ " interface DComponent {",
+ " D getD();",
+ " }",
+ "}");
+
+ String expectedError = "test.Outer.DComponent.getD() contains a dependency cycle:\n"
+ + " test.Outer.D.<init>(test.Outer.C cParam)\n"
+ + " [parameter: test.Outer.C cParam]\n"
+ + " test.Outer.C.<init>(test.Outer.B bParam)\n"
+ + " [parameter: test.Outer.B bParam]\n"
+ + " test.Outer.B.<init>(test.Outer.A aParam)\n"
+ + " [parameter: test.Outer.A aParam]\n"
+ + " test.Outer.A.<init>(test.Outer.C cParam)\n"
+ + " [parameter: test.Outer.C cParam]";
+
+ assertAbout(javaSource())
+ .that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError)
+ .in(component)
+ .onLine(27);
+ }
+
+ @Test
+ public void cyclicDependencyNotBrokenByMapBinding() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.MapKey;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.Map;",
+ "import javax.inject.Inject;",
+ "",
+ "final class Outer {",
+ " static class A {",
+ " @Inject A(Map<String, C> cMap) {}",
+ " }",
+ "",
+ " static class B {",
+ " @Inject B(A aParam) {}",
+ " }",
+ "",
+ " static class C {",
+ " @Inject C(B bParam) {}",
+ " }",
+ "",
+ " @Component(modules = CModule.class)",
+ " interface CComponent {",
+ " C getC();",
+ " }",
+ "",
+ " @Module",
+ " static class CModule {",
+ " @Provides(type = Provides.Type.MAP)",
+ " @StringKey(\"C\")",
+ " static C c(C c) {",
+ " return c;",
+ " }",
+ " }",
+ "",
+ " @MapKey",
+ " @interface StringKey {",
+ " String value();",
+ " }",
+ "}");
+
+ String expectedError =
+ Joiner.on('\n')
+ .join(
+ "test.Outer.CComponent.getC() contains a dependency cycle:",
+ " test.Outer.C.<init>(test.Outer.B bParam)",
+ " [parameter: test.Outer.B bParam]",
+ " test.Outer.B.<init>(test.Outer.A aParam)",
+ " [parameter: test.Outer.A aParam]",
+ " test.Outer.A.<init>(java.util.Map<java.lang.String,test.Outer.C> cMap)",
+ " [parameter: java.util.Map<java.lang.String,test.Outer.C> cMap]",
+ " test.Outer.A.<init>(java.util.Map<java.lang.String,test.Outer.C> cMap)",
+ " [parameter: java.util.Map<java.lang.String,test.Outer.C> cMap]",
+ " test.Outer.CModule.c(test.Outer.C c)",
+ " [parameter: test.Outer.C c]");
+
+ assertAbout(javaSource())
+ .that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError)
+ .in(component)
+ .onLine(25);
+ }
+
+ @Test
+ public void falsePositiveCyclicDependencyIndirectionDetected() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class Outer {",
+ " static class A {",
+ " @Inject A(C cParam) {}",
+ " }",
+ "",
+ " static class B {",
+ " @Inject B(A aParam) {}",
+ " }",
+ "",
+ " static class C {",
+ " @Inject C(B bParam) {}",
+ " }",
+ "",
+ " static class D {",
+ " @Inject D(Provider<C> cParam) {}",
+ " }",
+ "",
+ " @Component()",
+ " interface DComponent {",
+ " D getD();",
+ " }",
+ "}");
+
+ String expectedError =
+ "test.Outer.DComponent.getD() contains a dependency cycle:\n"
+ + " test.Outer.D.<init>(javax.inject.Provider<test.Outer.C> cParam)\n"
+ + " [parameter: javax.inject.Provider<test.Outer.C> cParam]\n"
+ + " test.Outer.C.<init>(test.Outer.B bParam)\n"
+ + " [parameter: test.Outer.B bParam]\n"
+ + " test.Outer.B.<init>(test.Outer.A aParam)\n"
+ + " [parameter: test.Outer.A aParam]\n"
+ + " test.Outer.A.<init>(test.Outer.C cParam)\n"
+ + " [parameter: test.Outer.C cParam]";
+
+ assertAbout(javaSource())
+ .that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError)
+ .in(component)
+ .onLine(28);
+ }
+
+ @Ignore @Test public void cyclicDependencySimpleProviderIndirectionWarning() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class Outer {",
+ " static class A {",
+ " @Inject A(B bParam) {}",
+ " }",
+ "",
+ " static class B {",
+ " @Inject B(C bParam, D dParam) {}",
+ " }",
+ "",
+ " static class C {",
+ " @Inject C(Provider<A> aParam) {}",
+ " }",
+ "",
+ " static class D {",
+ " @Inject D() {}",
+ " }",
+ "",
+ " @Component()",
+ " interface CComponent {",
+ " C get();",
+ " }",
+ "}");
+
+ /* String expectedWarning =
+ "test.Outer.CComponent.get() contains a dependency cycle:"
+ + " test.Outer.C.<init>(javax.inject.Provider<test.Outer.A> aParam)"
+ + " [parameter: javax.inject.Provider<test.Outer.A> aParam]"
+ + " test.Outer.A.<init>(test.Outer.B bParam)"
+ + " [parameter: test.Outer.B bParam]"
+ + " test.Outer.B.<init>(test.Outer.C bParam, test.Outer.D dParam)"
+ + " [parameter: test.Outer.C bParam]";
+ */
+ assertAbout(javaSource()) // TODO(cgruber): Implement warning checks.
+ .that(component)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ //.withWarningContaining(expectedWarning).in(component).onLine(X);
+ }
+
+ @Ignore @Test public void cyclicDependencySimpleProviderIndirectionWarningSuppressed() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class Outer {",
+ " static class A {",
+ " @Inject A(B bParam) {}",
+ " }",
+ "",
+ " static class B {",
+ " @Inject B(C bParam, D dParam) {}",
+ " }",
+ "",
+ " static class C {",
+ " @Inject C(Provider<A> aParam) {}",
+ " }",
+ "",
+ " static class D {",
+ " @Inject D() {}",
+ " }",
+ "",
+ " @SuppressWarnings(\"dependency-cycle\")",
+ " @Component()",
+ " interface CComponent {",
+ " C get();",
+ " }",
+ "}");
+
+ assertAbout(javaSource())
+ .that(component)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ //.compilesWithoutWarning(); //TODO(cgruber)
+ }
+
+ @Test public void duplicateExplicitBindings_ProvidesAndComponentProvision() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "final class Outer {",
+ " interface A {}",
+ "",
+ " interface B {}",
+ "",
+ " @Module",
+ " static class AModule {",
+ " @Provides String provideString() { return \"\"; }",
+ " @Provides A provideA(String s) { return new A() {}; }",
+ " }",
+ "",
+ " @Component(modules = AModule.class)",
+ " interface Parent {",
+ " A getA();",
+ " }",
+ "",
+ " @Module",
+ " static class BModule {",
+ " @Provides B provideB(A a) { return new B() {}; }",
+ " }",
+ "",
+ " @Component(dependencies = Parent.class, modules = { BModule.class, AModule.class})",
+ " interface Child {",
+ " B getB();",
+ " }",
+ "}");
+
+ String expectedError = "test.Outer.A is bound multiple times:\n"
+ + " test.Outer.A test.Outer.Parent.getA()\n"
+ + " @Provides test.Outer.A test.Outer.AModule.provideA(String)";
+
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(30);
+ }
+
+ @Test public void duplicateExplicitBindings_TwoProvidesMethods() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "final class Outer {",
+ " interface A {}",
+ "",
+ " @Module",
+ " static class Module1 {",
+ " @Provides A provideA1() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module2 {",
+ " @Provides String provideString() { return \"\"; }",
+ " @Provides A provideA2(String s) { return new A() {}; }",
+ " }",
+ "",
+ " @Component(modules = { Module1.class, Module2.class})",
+ " interface TestComponent {",
+ " A getA();",
+ " }",
+ "}");
+
+ String expectedError = "test.Outer.A is bound multiple times:\n"
+ + " @Provides test.Outer.A test.Outer.Module1.provideA1()\n"
+ + " @Provides test.Outer.A test.Outer.Module2.provideA2(String)";
+
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(24);
+ }
+
+ @Test public void duplicateExplicitBindings_MultipleProvisionTypes() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.MapKey;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.MapKey;",
+ "import java.util.HashMap;",
+ "import java.util.HashSet;",
+ "import java.util.Map;",
+ "import java.util.Set;",
+ "",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "import static dagger.Provides.Type.MAP;",
+ "import static dagger.Provides.Type.SET;",
+ "",
+ "final class Outer {",
+ " @MapKey(unwrapValue = true)",
+ " @interface StringKey {",
+ " String value();",
+ " }",
+ "",
+ " @Module",
+ " static class TestModule1 {",
+ " @Provides(type = MAP)",
+ " @StringKey(\"foo\")",
+ " String stringMapEntry() { return \"\"; }",
+ "",
+ " @Provides(type = SET) String stringSetElement() { return \"\"; }",
+ " }",
+ "",
+ " @Module",
+ " static class TestModule2 {",
+ " @Provides Set<String> stringSet() { return new HashSet<String>(); }",
+ "",
+ " @Provides Map<String, String> stringMap() {",
+ " return new HashMap<String, String>();",
+ " }",
+ " }",
+ "",
+ " @Component(modules = { TestModule1.class, TestModule2.class })",
+ " interface TestComponent {",
+ " Set<String> getStringSet();",
+ " Map<String, String> getStringMap();",
+ " }",
+ "}");
+
+ String expectedSetError =
+ "java.util.Set<java.lang.String> has incompatible bindings:\n"
+ + " Set bindings:\n"
+ + " @Provides(type=SET) String test.Outer.TestModule1.stringSetElement()\n"
+ + " Unique bindings:\n"
+ + " @Provides Set<String> test.Outer.TestModule2.stringSet()";
+
+ String expectedMapError =
+ "java.util.Map<java.lang.String,java.lang.String> has incompatible bindings:\n"
+ + " Map bindings:\n"
+ + " @Provides(type=MAP) @test.Outer.StringKey(\"foo\") String"
+ + " test.Outer.TestModule1.stringMapEntry()\n"
+ + " Unique bindings:\n"
+ + " @Provides Map<String,String> test.Outer.TestModule2.stringMap()";
+
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedSetError).in(component).onLine(43)
+ .and().withErrorContaining(expectedMapError).in(component).onLine(44);
+ }
+
+ @Test public void duplicateBindings_TruncateAfterLimit() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "final class Outer {",
+ " interface A {}",
+ "",
+ " @Module",
+ " static class Module1 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module2 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module3 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module4 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module5 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module6 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module7 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module8 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module9 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module10 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module11 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module12 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Component(modules = {",
+ " Module1.class,",
+ " Module2.class,",
+ " Module3.class,",
+ " Module4.class,",
+ " Module5.class,",
+ " Module6.class,",
+ " Module7.class,",
+ " Module8.class,",
+ " Module9.class,",
+ " Module10.class,",
+ " Module11.class,",
+ " Module12.class",
+ " })",
+ " interface TestComponent {",
+ " A getA();",
+ " }",
+ "}");
+
+ String expectedError = "test.Outer.A is bound multiple times:\n"
+ + " @Provides test.Outer.A test.Outer.Module1.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module2.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module3.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module4.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module5.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module6.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module7.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module8.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module9.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module10.provideA()\n"
+ + " and 2 others";
+
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(86);
+ }
+
+ @Test public void longChainOfDependencies() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "final class TestClass {",
+ " interface A {}",
+ "",
+ " static class B {",
+ " @Inject B(A a) {}",
+ " }",
+ "",
+ " static class C {",
+ " @Inject B b;",
+ " @Inject C(B b) {}",
+ " }",
+ "",
+ " interface D { }",
+ "",
+ " static class DImpl implements D {",
+ " @Inject DImpl(C c, B b) {}",
+ " }",
+ "",
+ " @Module",
+ " static class DModule {",
+ " @Provides D d(DImpl impl) { return impl; }",
+ " }",
+ "",
+ " @Component(modules = { DModule.class })",
+ " interface AComponent {",
+ " D getFoo();",
+ " C injectC(C c);",
+ " }",
+ "}");
+ String errorText =
+ "test.TestClass.A cannot be provided without an @Provides-annotated method.\n";
+ String firstError = errorText
+ + " test.TestClass.DModule.d(test.TestClass.DImpl impl)\n"
+ + " [parameter: test.TestClass.DImpl impl]\n"
+ + " test.TestClass.DImpl.<init>(test.TestClass.C c, test.TestClass.B b)\n"
+ + " [parameter: test.TestClass.C c]\n"
+ + " test.TestClass.C.b\n"
+ + " [injected field of type: test.TestClass.B b]\n"
+ + " test.TestClass.B.<init>(test.TestClass.A a)\n"
+ + " [parameter: test.TestClass.A a]";
+ String secondError = errorText
+ + " test.TestClass.C.b\n"
+ + " [injected field of type: test.TestClass.B b]\n"
+ + " test.TestClass.B.<init>(test.TestClass.A a)\n"
+ + " [parameter: test.TestClass.A a]";
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(firstError).in(component).onLine(33)
+ .and().withErrorContaining(secondError).in(component).onLine(34);
+ }
+
+ @Test public void resolvedParametersInDependencyTrace() {
+ JavaFileObject generic = JavaFileObjects.forSourceLines("test.Generic",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class Generic<T> {",
+ " @Inject Generic(T t) {}",
+ "}");
+ JavaFileObject testClass = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import java.util.List;",
+ "",
+ "final class TestClass {",
+ " @Inject TestClass(List list) {}",
+ "}");
+ JavaFileObject usesTest = JavaFileObjects.forSourceLines("test.UsesTest",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class UsesTest {",
+ " @Inject UsesTest(Generic<TestClass> genericTestClass) {}",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " UsesTest usesTest();",
+ "}");
+ String expectedMsg = Joiner.on("\n").join(
+ "java.util.List cannot be provided without an @Provides-annotated method.",
+ " test.UsesTest.<init>(test.Generic<test.TestClass> genericTestClass)",
+ " [parameter: test.Generic<test.TestClass> genericTestClass]",
+ " test.Generic.<init>(test.TestClass t)",
+ " [parameter: test.TestClass t]",
+ " test.TestClass.<init>(java.util.List list)",
+ " [parameter: java.util.List list]");
+ assertAbout(javaSources()).that(ImmutableList.of(generic, testClass, usesTest, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedMsg);
+ }
+
+ @Test public void resolvedVariablesInDependencyTrace() {
+ JavaFileObject generic = JavaFileObjects.forSourceLines("test.Generic",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class Generic<T> {",
+ " @Inject T t;",
+ " @Inject Generic() {}",
+ "}");
+ JavaFileObject testClass = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import java.util.List;",
+ "",
+ "final class TestClass {",
+ " @Inject TestClass(List list) {}",
+ "}");
+ JavaFileObject usesTest = JavaFileObjects.forSourceLines("test.UsesTest",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class UsesTest {",
+ " @Inject UsesTest(Generic<TestClass> genericTestClass) {}",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " UsesTest usesTest();",
+ "}");
+ String expectedMsg = Joiner.on("\n").join(
+ "java.util.List cannot be provided without an @Provides-annotated method.",
+ " test.UsesTest.<init>(test.Generic<test.TestClass> genericTestClass)",
+ " [parameter: test.Generic<test.TestClass> genericTestClass]",
+ " test.Generic.t",
+ " [injected field of type: test.TestClass t]",
+ " test.TestClass.<init>(java.util.List list)",
+ " [parameter: java.util.List list]");
+ assertAbout(javaSources()).that(ImmutableList.of(generic, testClass, usesTest, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedMsg);
+ }
+
+ @Test public void nullCheckForConstructorParameters() {
+ JavaFileObject a = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A(String string) {}",
+ "}");
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "final class TestModule {",
+ " @Nullable @Provides String provideString() { return null; }",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " A a();",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, a, module, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(NULLABLE_TO_NON_NULLABLE, "java.lang.String",
+ "@test.Nullable @Provides String test.TestModule.provideString()"));
+
+ // but if we disable the validation, then it compiles fine.
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, a, module, component))
+ .withCompilerOptions("-Adagger.nullableValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @Test public void nullCheckForMembersInjectParam() {
+ JavaFileObject a = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A() {}",
+ " @Inject void register(String string) {}",
+ "}");
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "final class TestModule {",
+ " @Nullable @Provides String provideString() { return null; }",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " A a();",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, a, module, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(NULLABLE_TO_NON_NULLABLE, "java.lang.String",
+ "@test.Nullable @Provides String test.TestModule.provideString()"));
+
+ // but if we disable the validation, then it compiles fine.
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, a, module, component))
+ .withCompilerOptions("-Adagger.nullableValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @Test public void nullCheckForVariable() {
+ JavaFileObject a = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject String string;",
+ " @Inject A() {}",
+ "}");
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "final class TestModule {",
+ " @Nullable @Provides String provideString() { return null; }",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " A a();",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, a, module, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(NULLABLE_TO_NON_NULLABLE, "java.lang.String",
+ "@test.Nullable @Provides String test.TestModule.provideString()"));
+
+ // but if we disable the validation, then it compiles fine.
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, a, module, component))
+ .withCompilerOptions("-Adagger.nullableValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @Test public void nullCheckForComponentReturn() {
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "final class TestModule {",
+ " @Nullable @Provides String provideString() { return null; }",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " String string();",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, module, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(NULLABLE_TO_NON_NULLABLE, "java.lang.String",
+ "@test.Nullable @Provides String test.TestModule.provideString()"));
+
+ // but if we disable the validation, then it compiles fine.
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, module, component))
+ .withCompilerOptions("-Adagger.nullableValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @Test public void componentDependencyMustNotCycle_Direct() {
+ JavaFileObject shortLifetime = JavaFileObjects.forSourceLines("test.ComponentShort",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(dependencies = ComponentShort.class)",
+ "interface ComponentShort {",
+ "}");
+ String errorMessage =
+ "test.ComponentShort contains a cycle in its component dependencies:\n"
+ + " test.ComponentShort";
+ assertAbout(javaSource())
+ .that(shortLifetime)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage);
+ }
+
+ @Test public void componentDependencyMustNotCycle_Indirect() {
+ JavaFileObject longLifetime = JavaFileObjects.forSourceLines("test.ComponentLong",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(dependencies = ComponentMedium.class)",
+ "interface ComponentLong {",
+ "}");
+ JavaFileObject mediumLifetime = JavaFileObjects.forSourceLines("test.ComponentMedium",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(dependencies = ComponentLong.class)",
+ "interface ComponentMedium {",
+ "}");
+ JavaFileObject shortLifetime = JavaFileObjects.forSourceLines("test.ComponentShort",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(dependencies = ComponentMedium.class)",
+ "interface ComponentShort {",
+ "}");
+ String longErrorMessage =
+ "test.ComponentLong contains a cycle in its component dependencies:\n"
+ + " test.ComponentLong\n"
+ + " test.ComponentMedium\n"
+ + " test.ComponentLong";
+ String mediumErrorMessage =
+ "test.ComponentMedium contains a cycle in its component dependencies:\n"
+ + " test.ComponentMedium\n"
+ + " test.ComponentLong\n"
+ + " test.ComponentMedium";
+ String shortErrorMessage =
+ "test.ComponentShort contains a cycle in its component dependencies:\n"
+ + " test.ComponentMedium\n"
+ + " test.ComponentLong\n"
+ + " test.ComponentMedium\n"
+ + " test.ComponentShort";
+ assertAbout(javaSources())
+ .that(ImmutableList.of(longLifetime, mediumLifetime, shortLifetime))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(longErrorMessage).in(longLifetime)
+ .and()
+ .withErrorContaining(mediumErrorMessage).in(mediumLifetime)
+ .and()
+ .withErrorContaining(shortErrorMessage).in(shortLifetime);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java b/compiler/src/test/java/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java
new file mode 100644
index 000000000..ca0494e47
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java
@@ -0,0 +1,1128 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static dagger.internal.codegen.ErrorMessages.ABSTRACT_INJECT_METHOD;
+import static dagger.internal.codegen.ErrorMessages.FINAL_INJECT_FIELD;
+import static dagger.internal.codegen.ErrorMessages.GENERIC_INJECT_METHOD;
+import static dagger.internal.codegen.ErrorMessages.INJECT_CONSTRUCTOR_ON_ABSTRACT_CLASS;
+import static dagger.internal.codegen.ErrorMessages.INJECT_CONSTRUCTOR_ON_INNER_CLASS;
+import static dagger.internal.codegen.ErrorMessages.INJECT_ON_PRIVATE_CONSTRUCTOR;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_INJECT_CONSTRUCTORS;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_QUALIFIERS;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_SCOPES;
+import static dagger.internal.codegen.ErrorMessages.PRIVATE_INJECT_FIELD;
+import static dagger.internal.codegen.ErrorMessages.PRIVATE_INJECT_METHOD;
+import static dagger.internal.codegen.ErrorMessages.QUALIFIER_ON_INJECT_CONSTRUCTOR;
+import static dagger.internal.codegen.ErrorMessages.STATIC_INJECT_FIELD;
+import static dagger.internal.codegen.ErrorMessages.STATIC_INJECT_METHOD;
+
+@RunWith(JUnit4.class)
+// TODO(gak): add tests for generation in the default package.
+public final class InjectConstructorFactoryGeneratorTest {
+ private static final JavaFileObject QUALIFIER_A =
+ JavaFileObjects.forSourceLines("test.QualifierA",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier @interface QualifierA {}");
+ private static final JavaFileObject QUALIFIER_B =
+ JavaFileObjects.forSourceLines("test.QualifierB",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier @interface QualifierB {}");
+ private static final JavaFileObject SCOPE_A =
+ JavaFileObjects.forSourceLines("test.ScopeA",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope @interface ScopeA {}");
+ private static final JavaFileObject SCOPE_B =
+ JavaFileObjects.forSourceLines("test.ScopeB",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope @interface ScopeB {}");
+
+ @Test public void injectOnPrivateConstructor() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateConstructor",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class PrivateConstructor {",
+ " @Inject private PrivateConstructor() {}",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(INJECT_ON_PRIVATE_CONSTRUCTOR).in(file).onLine(6);
+ }
+
+ @Test public void injectConstructorOnInnerClass() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class OuterClass {",
+ " class InnerClass {",
+ " @Inject InnerClass() {}",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(INJECT_CONSTRUCTOR_ON_INNER_CLASS).in(file).onLine(7);
+ }
+
+ @Test public void injectConstructorOnAbstractClass() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.AbstractClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "abstract class AbstractClass {",
+ " @Inject AbstractClass() {}",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(INJECT_CONSTRUCTOR_ON_ABSTRACT_CLASS).in(file).onLine(6);
+ }
+
+ @Test public void injectConstructorOnGenericClass() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class GenericClass<T> {",
+ " @Inject GenericClass(T t) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines("test.GenericClass_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class GenericClass_Factory<T> implements Factory<GenericClass<T>> {",
+ " private final Provider<T> tProvider;",
+ "",
+ " public GenericClass_Factory(Provider<T> tProvider) {",
+ " assert tProvider != null;",
+ " this.tProvider = tProvider;",
+ " }",
+ "",
+ " @Override",
+ " public GenericClass<T> get() {",
+ " return new GenericClass<T>(tProvider.get());",
+ " }",
+ "",
+ " public static <T> Factory<GenericClass<T>> create(Provider<T> tProvider) {",
+ " return new GenericClass_Factory<T>(tProvider);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test public void fieldAndMethodGenerics() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class GenericClass<A, B> {",
+ " @Inject A a;",
+ "",
+ " @Inject GenericClass() {}",
+ "",
+ " @Inject void register(B b) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines("test.GenericClass_Factory",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class GenericClass_Factory<A, B> implements Factory<GenericClass<A, B>> {",
+ " private final MembersInjector<GenericClass<A, B>> membersInjector;",
+ "",
+ " public GenericClass_Factory(MembersInjector<GenericClass<A, B>> membersInjector) {",
+ " assert membersInjector != null;",
+ " this.membersInjector = membersInjector;",
+ " }",
+ "",
+ " @Override",
+ " public GenericClass<A, B> get() {",
+ " GenericClass<A, B> instance = new GenericClass<A, B>();",
+ " membersInjector.injectMembers(instance);",
+ " return instance;",
+ " }",
+ "",
+ " public static <A, B> Factory<GenericClass<A, B>> create(",
+ " MembersInjector<GenericClass<A, B>> membersInjector) {",
+ " return new GenericClass_Factory<A, B>(membersInjector);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test public void genericClassWithNoDependencies() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class GenericClass<T> {",
+ " @Inject GenericClass() {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines("test.GenericClass_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@SuppressWarnings(\"rawtypes\")",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public enum GenericClass_Factory implements Factory<GenericClass> {",
+ " INSTANCE;",
+ "",
+ " @Override",
+ " public GenericClass get() {",
+ " return new GenericClass();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " public static <T> Factory<GenericClass<T>> create() {",
+ " return (Factory) INSTANCE;",
+ " }",
+ "",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test public void twoGenericTypes() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class GenericClass<A, B> {",
+ " @Inject GenericClass(A a, B b) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines("test.GenericClass_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class GenericClass_Factory<A, B> implements Factory<GenericClass<A, B>> {",
+ " private final Provider<A> aProvider;",
+ " private final Provider<B> bProvider;",
+ "",
+ " public GenericClass_Factory(Provider<A> aProvider, Provider<B> bProvider) {",
+ " assert aProvider != null;",
+ " this.aProvider = aProvider;",
+ " assert bProvider != null;",
+ " this.bProvider = bProvider;",
+ " }",
+ "",
+ " @Override",
+ " public GenericClass<A, B> get() {",
+ " return new GenericClass<A, B>(aProvider.get(), bProvider.get());",
+ " }",
+ "",
+ " public static <A, B> Factory<GenericClass<A, B>> create(",
+ " Provider<A> aProvider, Provider<B> bProvider) {",
+ " return new GenericClass_Factory<A, B>(aProvider, bProvider);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test public void boundedGenerics() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import java.util.List;",
+ "",
+ "class GenericClass<A extends Number & Comparable<A>,",
+ " B extends List<? extends String>,",
+ " C extends List<? super String>> {",
+ " @Inject GenericClass(A a, B b, C c) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines("test.GenericClass_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import java.util.List;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class GenericClass_Factory<A extends Number & Comparable<A>,",
+ " B extends List<? extends String>,",
+ " C extends List<? super String>>",
+ " implements Factory<GenericClass<A, B, C>> {",
+ " private final Provider<A> aProvider;",
+ " private final Provider<B> bProvider;",
+ " private final Provider<C> cProvider;",
+ "",
+ " public GenericClass_Factory(Provider<A> aProvider,",
+ " Provider<B> bProvider,",
+ " Provider<C> cProvider) {",
+ " assert aProvider != null;",
+ " this.aProvider = aProvider;",
+ " assert bProvider != null;",
+ " this.bProvider = bProvider;",
+ " assert cProvider != null;",
+ " this.cProvider = cProvider;",
+ " }",
+ "",
+ " @Override",
+ " public GenericClass<A, B, C> get() {",
+ " return new GenericClass<A, B, C>(aProvider.get(), bProvider.get(), cProvider.get());",
+ " }",
+ "",
+ " public static <A extends Number & Comparable<A>,",
+ " B extends List<? extends String>,",
+ " C extends List<? super String>> Factory<GenericClass<A, B, C>> create(",
+ " Provider<A> aProvider, Provider<B> bProvider, Provider<C> cProvider) {",
+ " return new GenericClass_Factory<A, B, C>(aProvider, bProvider, cProvider);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test public void multipleSameTypesWithGenericsAndQualifiersAndLazies() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "import dagger.Lazy;",
+ "",
+ "class GenericClass<A, B> {",
+ " @Inject GenericClass(A a, A a2, Provider<A> pa, @QualifierA A qa, Lazy<A> la, ",
+ " String s, String s2, Provider<String> ps, ",
+ " @QualifierA String qs, Lazy<String> ls,",
+ " B b, B b2, Provider<B> pb, @QualifierA B qb, Lazy<B> lb) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines("test.GenericClass_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.DoubleCheckLazy;",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class GenericClass_Factory<A, B> implements Factory<GenericClass<A, B>> {",
+ " private final Provider<A> aAndA2AndPaAndLaProvider;",
+ " private final Provider<A> qaProvider;",
+ " private final Provider<String> sAndS2AndPsAndLsProvider;",
+ " private final Provider<String> qsProvider;",
+ " private final Provider<B> bAndB2AndPbAndLbProvider;",
+ " private final Provider<B> qbProvider;",
+ "",
+ " public GenericClass_Factory(Provider<A> aAndA2AndPaAndLaProvider,",
+ " Provider<A> qaProvider,",
+ " Provider<String> sAndS2AndPsAndLsProvider,",
+ " Provider<String> qsProvider,",
+ " Provider<B> bAndB2AndPbAndLbProvider,",
+ " Provider<B> qbProvider) {",
+ " assert aAndA2AndPaAndLaProvider != null;",
+ " this.aAndA2AndPaAndLaProvider = aAndA2AndPaAndLaProvider;",
+ " assert qaProvider != null;",
+ " this.qaProvider = qaProvider;",
+ " assert sAndS2AndPsAndLsProvider != null;",
+ " this.sAndS2AndPsAndLsProvider = sAndS2AndPsAndLsProvider;",
+ " assert qsProvider != null;",
+ " this.qsProvider = qsProvider;",
+ " assert bAndB2AndPbAndLbProvider != null;",
+ " this.bAndB2AndPbAndLbProvider = bAndB2AndPbAndLbProvider;",
+ " assert qbProvider != null;",
+ " this.qbProvider = qbProvider;",
+ " }",
+ "",
+ " @Override",
+ " public GenericClass<A, B> get() {",
+ " return new GenericClass<A, B>(",
+ " aAndA2AndPaAndLaProvider.get(),",
+ " aAndA2AndPaAndLaProvider.get(),",
+ " aAndA2AndPaAndLaProvider,",
+ " qaProvider.get(),",
+ " DoubleCheckLazy.create(aAndA2AndPaAndLaProvider),",
+ " sAndS2AndPsAndLsProvider.get(),",
+ " sAndS2AndPsAndLsProvider.get(),",
+ " sAndS2AndPsAndLsProvider,",
+ " qsProvider.get(),",
+ " DoubleCheckLazy.create(sAndS2AndPsAndLsProvider),",
+ " bAndB2AndPbAndLbProvider.get(),",
+ " bAndB2AndPbAndLbProvider.get(),",
+ " bAndB2AndPbAndLbProvider,",
+ " qbProvider.get(),",
+ " DoubleCheckLazy.create(bAndB2AndPbAndLbProvider));",
+ " }",
+ "",
+ " public static <A, B> Factory<GenericClass<A, B>> create(",
+ " Provider<A> aAndA2AndPaAndLaProvider,",
+ " Provider<A> qaProvider,",
+ " Provider<String> sAndS2AndPsAndLsProvider,",
+ " Provider<String> qsProvider,",
+ " Provider<B> bAndB2AndPbAndLbProvider,",
+ " Provider<B> qbProvider) {",
+ " return new GenericClass_Factory<A, B>(",
+ " aAndA2AndPaAndLaProvider,",
+ " qaProvider,",
+ " sAndS2AndPsAndLsProvider,",
+ " qsProvider,",
+ " bAndB2AndPbAndLbProvider,",
+ " qbProvider);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(file, QUALIFIER_A))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test public void multipleInjectConstructors() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.TooManyInjectConstructors",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class TooManyInjectConstructors {",
+ " @Inject TooManyInjectConstructors() {}",
+ " TooManyInjectConstructors(int i) {}",
+ " @Inject TooManyInjectConstructors(String s) {}",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MULTIPLE_INJECT_CONSTRUCTORS).in(file).onLine(6)
+ .and().withErrorContaining(MULTIPLE_INJECT_CONSTRUCTORS).in(file).onLine(8);
+ }
+
+ @Test public void multipleQualifiersOnInjectConstructorParameter() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleQualifierConstructorParam",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class MultipleQualifierConstructorParam {",
+ " @Inject MultipleQualifierConstructorParam(@QualifierA @QualifierB String s) {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(file, QUALIFIER_A, QUALIFIER_B))
+ .processedWith(new ComponentProcessor()).failsToCompile()
+ // for whatever reason, javac only reports the error once on the constructor
+ .withErrorContaining(MULTIPLE_QUALIFIERS).in(file).onLine(6);
+ }
+
+ @Test public void injectConstructorOnClassWithMultipleScopes() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleScopeClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "@ScopeA @ScopeB class MultipleScopeClass {",
+ " @Inject MultipleScopeClass() {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(file, SCOPE_A, SCOPE_B))
+ .processedWith(new ComponentProcessor()).failsToCompile()
+ .withErrorContaining(MULTIPLE_SCOPES).in(file).onLine(5).atColumn(1)
+ .and().withErrorContaining(MULTIPLE_SCOPES).in(file).onLine(5).atColumn(9);
+ }
+
+ @Test public void injectConstructorWithQualifier() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleScopeClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class MultipleScopeClass {",
+ " @Inject",
+ " @QualifierA",
+ " @QualifierB",
+ " MultipleScopeClass() {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(file, QUALIFIER_A, QUALIFIER_B))
+ .processedWith(new ComponentProcessor()).failsToCompile()
+ .withErrorContaining(QUALIFIER_ON_INJECT_CONSTRUCTOR).in(file).onLine(7)
+ .and().withErrorContaining(QUALIFIER_ON_INJECT_CONSTRUCTOR).in(file).onLine(8);
+ }
+
+ @Test public void finalInjectField() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.FinalInjectField",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class FinalInjectField {",
+ " @Inject final String s;",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(FINAL_INJECT_FIELD).in(file).onLine(6);
+ }
+
+ @Test public void privateInjectFieldError() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectField",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class PrivateInjectField {",
+ " @Inject private String s;",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRIVATE_INJECT_FIELD).in(file).onLine(6);
+ }
+
+ @Test public void privateInjectFieldWarning() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectField",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class PrivateInjectField {",
+ " @Inject private String s;",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .withCompilerOptions("-Adagger.privateMemberValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError(); // TODO: Verify warning message when supported
+ }
+
+ @Test public void staticInjectFieldError() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectField",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class StaticInjectField {",
+ " @Inject static String s;",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(STATIC_INJECT_FIELD).in(file).onLine(6);
+ }
+
+ @Test public void staticInjectFieldWarning() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectField",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class StaticInjectField {",
+ " @Inject static String s;",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .withCompilerOptions("-Adagger.staticMemberValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError(); // TODO: Verify warning message when supported
+ }
+
+ @Test public void multipleQualifiersOnField() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleQualifierInjectField",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class MultipleQualifierInjectField {",
+ " @Inject @QualifierA @QualifierB String s;",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(file, QUALIFIER_A, QUALIFIER_B))
+ .processedWith(new ComponentProcessor()).failsToCompile()
+ .withErrorContaining(MULTIPLE_QUALIFIERS).in(file).onLine(6).atColumn(11)
+ .and().withErrorContaining(MULTIPLE_QUALIFIERS).in(file).onLine(6).atColumn(23);
+ }
+
+ @Test public void abstractInjectMethod() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.AbstractInjectMethod",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "abstract class AbstractInjectMethod {",
+ " @Inject abstract void method();",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(ABSTRACT_INJECT_METHOD).in(file).onLine(6);
+ }
+
+ @Test public void privateInjectMethodError() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectMethod",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class PrivateInjectMethod {",
+ " @Inject private void method(){}",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRIVATE_INJECT_METHOD).in(file).onLine(6);
+ }
+
+ @Test public void privateInjectMethodWarning() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectMethod",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class PrivateInjectMethod {",
+ " @Inject private void method(){}",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .withCompilerOptions("-Adagger.privateMemberValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError(); // TODO: Verify warning message when supported
+ }
+
+ @Test public void staticInjectMethodError() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectMethod",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class StaticInjectMethod {",
+ " @Inject static void method(){}",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(STATIC_INJECT_METHOD).in(file).onLine(6);
+ }
+
+ @Test public void staticInjectMethodWarning() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectMethod",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class StaticInjectMethod {",
+ " @Inject static void method(){}",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .withCompilerOptions("-Adagger.staticMemberValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError(); // TODO: Verify warning message when supported
+ }
+
+ @Test public void genericInjectMethod() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericInjectMethod",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class AbstractInjectMethod {",
+ " @Inject <T> void method();",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(GENERIC_INJECT_METHOD).in(file).onLine(6);
+ }
+
+ @Test public void multipleQualifiersOnInjectMethodParameter() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleQualifierMethodParam",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class MultipleQualifierMethodParam {",
+ " @Inject void method(@QualifierA @QualifierB String s) {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(file, QUALIFIER_A, QUALIFIER_B))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ // for whatever reason, javac only reports the error once on the method
+ .withErrorContaining(MULTIPLE_QUALIFIERS).in(file).onLine(6);
+ }
+
+ @Test public void injectConstructor() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class InjectConstructor {",
+ " @Inject InjectConstructor(String s) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.InjectConstructor_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class InjectConstructor_Factory ",
+ " implements Factory<InjectConstructor> {",
+ "",
+ " private final Provider<String> sProvider;",
+ "",
+ " public InjectConstructor_Factory(Provider<String> sProvider) {",
+ " assert sProvider != null;",
+ " this.sProvider = sProvider;",
+ " }",
+ "",
+ " @Override public InjectConstructor get() {",
+ " return new InjectConstructor(sProvider.get());",
+ " }",
+ "",
+ " public static Factory<InjectConstructor> create(Provider<String> sProvider) {",
+ " return new InjectConstructor_Factory(sProvider);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file).processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test public void injectConstructorAndMembersInjection() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.AllInjections",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class AllInjections {",
+ " @Inject String s;",
+ " @Inject AllInjections(String s) {}",
+ " @Inject void s(String s) {}",
+ "}");
+ JavaFileObject expectedFactory = JavaFileObjects.forSourceLines(
+ "test.AllInjections_Factory",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class AllInjections_Factory ",
+ " implements Factory<AllInjections> {",
+ "",
+ " private final MembersInjector<AllInjections> membersInjector;",
+ " private final Provider<String> sProvider;",
+ "",
+ " public AllInjections_Factory(MembersInjector<AllInjections> membersInjector, ",
+ " Provider<String> sProvider) {",
+ " assert membersInjector != null;",
+ " this.membersInjector = membersInjector;",
+ " assert sProvider != null;",
+ " this.sProvider = sProvider;",
+ " }",
+ "",
+ " @Override public AllInjections get() {",
+ " AllInjections instance = new AllInjections(sProvider.get());",
+ " membersInjector.injectMembers(instance);",
+ " return instance;",
+ " }",
+ "",
+ " public static Factory<AllInjections> create(",
+ " MembersInjector<AllInjections> membersInjector, ",
+ " Provider<String> sProvider) {",
+ " return new AllInjections_Factory(membersInjector, sProvider);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file).processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expectedFactory);
+ }
+
+ @Test public void supertypeRequiresMemberInjection() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "class A {}");
+ JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class B extends A {",
+ " @Inject B() {}",
+ "}");
+ JavaFileObject expectedFactory = JavaFileObjects.forSourceLines(
+ "test.B_Factory",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class B_Factory implements Factory<B> {",
+ "",
+ " private final MembersInjector<B> membersInjector;",
+ "",
+ " public B_Factory(MembersInjector<B> membersInjector) {",
+ " assert membersInjector != null;",
+ " this.membersInjector = membersInjector;",
+ " }",
+ "",
+ " @Override public B get() {",
+ " B instance = new B();",
+ " membersInjector.injectMembers(instance);",
+ " return instance;",
+ " }",
+ "",
+ " public static Factory<B> create(MembersInjector<B> membersInjector) {",
+ " return new B_Factory(membersInjector);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(aFile, bFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expectedFactory);
+ }
+
+ @Test
+ public void wildcardDependency() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
+ "package test;",
+ "",
+ "import java.util.List;",
+ "import javax.inject.Inject;",
+ "",
+ "class InjectConstructor {",
+ " @Inject InjectConstructor(List<? extends Object> objects) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.InjectConstructor_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import java.util.List;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class InjectConstructor_Factory ",
+ " implements Factory<InjectConstructor> {",
+ "",
+ " private final Provider<List<? extends Object>> objectsProvider;",
+ "",
+ " public InjectConstructor_Factory(Provider<List<? extends Object>> objectsProvider) {",
+ " assert objectsProvider != null;",
+ " this.objectsProvider = objectsProvider;",
+ " }",
+ "",
+ " @Override public InjectConstructor get() {",
+ " return new InjectConstructor(objectsProvider.get());",
+ " }",
+ "",
+ " public static Factory<InjectConstructor> create(",
+ " Provider<List<? extends Object>> objectsProvider) {",
+ " return new InjectConstructor_Factory(objectsProvider);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file).processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test
+ public void basicNameCollision() {
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines("other.pkg.Factory",
+ "package other.pkg;",
+ "",
+ "public class Factory {}");
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import other.pkg.Factory;",
+ "",
+ "class InjectConstructor {",
+ " @Inject InjectConstructor(Factory factory) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.InjectConstructor_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class InjectConstructor_Factory ",
+ " implements Factory<InjectConstructor> {",
+ "",
+ " private final Provider<other.pkg.Factory> factoryProvider;",
+ "",
+ " public InjectConstructor_Factory(Provider<other.pkg.Factory> factoryProvider) {",
+ " assert factoryProvider != null;",
+ " this.factoryProvider = factoryProvider;",
+ " }",
+ "",
+ " @Override public InjectConstructor get() {",
+ " return new InjectConstructor(factoryProvider.get());",
+ " }",
+ "",
+ " public static Factory<InjectConstructor> create(",
+ " Provider<other.pkg.Factory> factoryProvider) {",
+ " return new InjectConstructor_Factory(factoryProvider);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(factoryFile, file))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test
+ public void nestedNameCollision() {
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines("other.pkg.Outer",
+ "package other.pkg;",
+ "",
+ "public class Outer {",
+ " public class Factory {}",
+ "}");
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import other.pkg.Outer;",
+ "",
+ "class InjectConstructor {",
+ " @Inject InjectConstructor(Outer.Factory factory) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.InjectConstructor_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import other.pkg.Outer;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class InjectConstructor_Factory ",
+ " implements Factory<InjectConstructor> {",
+ "",
+ " private final Provider<Outer.Factory> factoryProvider;",
+ "",
+ " public InjectConstructor_Factory(Provider<Outer.Factory> factoryProvider) {",
+ " assert factoryProvider != null;",
+ " this.factoryProvider = factoryProvider;",
+ " }",
+ "",
+ " @Override public InjectConstructor get() {",
+ " return new InjectConstructor(factoryProvider.get());",
+ " }",
+ "",
+ " public static Factory<InjectConstructor> create(",
+ " Provider<Outer.Factory> factoryProvider) {",
+ " return new InjectConstructor_Factory(factoryProvider);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(factoryFile, file))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test
+ public void samePackageNameCollision() {
+ JavaFileObject samePackageInterface = JavaFileObjects.forSourceLines("test.CommonName",
+ "package test;",
+ "",
+ "public interface CommonName {}");
+ JavaFileObject differentPackageInterface = JavaFileObjects.forSourceLines(
+ "other.pkg.CommonName",
+ "package other.pkg;",
+ "",
+ "public interface CommonName {}");
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class InjectConstructor implements CommonName {",
+ " @Inject InjectConstructor(other.pkg.CommonName otherPackage, CommonName samePackage) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.InjectConstructor_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import other.pkg.CommonName;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class InjectConstructor_Factory ",
+ " implements Factory<InjectConstructor> {",
+ "",
+ " private final Provider<CommonName> otherPackageProvider;",
+ " private final Provider<test.CommonName> samePackageProvider;",
+ "",
+ " public InjectConstructor_Factory(Provider<CommonName> otherPackageProvider,",
+ " Provider<test.CommonName> samePackageProvider) {",
+ " assert otherPackageProvider != null;",
+ " this.otherPackageProvider = otherPackageProvider;",
+ " assert samePackageProvider != null;",
+ " this.samePackageProvider = samePackageProvider;",
+ " }",
+ "",
+ " @Override public InjectConstructor get() {",
+ " return new InjectConstructor(otherPackageProvider.get(), samePackageProvider.get());",
+ " }",
+ "",
+ " public static Factory<InjectConstructor> create(",
+ " Provider<CommonName> otherPackageProvider,",
+ " Provider<test.CommonName> samePackageProvider) {",
+ " return new InjectConstructor_Factory(otherPackageProvider, samePackageProvider);",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(samePackageInterface, differentPackageInterface, file))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test
+ public void noDeps() {
+ JavaFileObject simpleType = JavaFileObjects.forSourceLines("test.SimpleType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SimpleType {",
+ " @Inject SimpleType() {}",
+ "}");
+ JavaFileObject factory = JavaFileObjects.forSourceLines("test.SimpleType_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public enum SimpleType_Factory implements Factory<SimpleType> {",
+ " INSTANCE;",
+ "",
+ " @Override public SimpleType get() {",
+ " return new SimpleType();",
+ " }",
+ "",
+ " public static Factory<SimpleType> create() {",
+ " return INSTANCE;",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(simpleType)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(factory);
+ }
+
+ @Test public void simpleComponentWithNesting() {
+ JavaFileObject nestedTypesFile = JavaFileObjects.forSourceLines("test.OuterType",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Inject;",
+ "",
+ "final class OuterType {",
+ " static class A {",
+ " @Inject A() {}",
+ " }",
+ " static class B {",
+ " @Inject A a;",
+ " }",
+ " @Component interface SimpleComponent {",
+ " A a();",
+ " void inject(B b);",
+ " }",
+ "}");
+ JavaFileObject aFactory = JavaFileObjects.forSourceLines(
+ "test.OuterType$A_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import test.OuterType.A;",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public enum OuterType$A_Factory implements Factory<A> {",
+ " INSTANCE;",
+ "",
+ " @Override public A get() {",
+ " return new A();",
+ " }",
+ "",
+ " public static Factory<A> create() {",
+ " return INSTANCE;",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(nestedTypesFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(aFactory);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/KeyTest.java b/compiler/src/test/java/dagger/internal/codegen/KeyTest.java
new file mode 100644
index 000000000..c1d622dfd
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/KeyTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.common.MoreTypes;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.testing.compile.CompilationRule;
+import dagger.Module;
+import dagger.Provides;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.util.Set;
+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.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static dagger.Provides.Type.SET;
+import static dagger.Provides.Type.SET_VALUES;
+
+/**
+ * Tests {@link Key}.
+ */
+@RunWith(JUnit4.class)
+public class KeyTest {
+ @Rule public CompilationRule compilationRule = new CompilationRule();
+
+ private Elements elements;
+ private Types types;
+ private Key.Factory keyFactory;
+
+ @Before public void setUp() {
+ this.types = compilationRule.getTypes();
+ this.elements = compilationRule.getElements();
+ this.keyFactory = new Key.Factory(types, elements);
+ }
+
+ @Test public void forInjectConstructorWithResolvedType() {
+ TypeElement typeElement =
+ compilationRule.getElements().getTypeElement(InjectedClass.class.getCanonicalName());
+ ExecutableElement constructor =
+ Iterables.getOnlyElement(ElementFilter.constructorsIn(typeElement.getEnclosedElements()));
+ assertThat(
+ keyFactory.forInjectConstructorWithResolvedType(constructor.getEnclosingElement().asType()))
+ .isEqualTo(new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(typeElement.asType())));
+ }
+
+ static final class InjectedClass {
+ @SuppressWarnings("unused")
+ @Inject InjectedClass(String s, int i) {}
+ }
+
+ @Test public void forProvidesMethod() {
+ TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
+ TypeElement moduleElement =
+ elements.getTypeElement(ProvidesMethodModule.class.getCanonicalName());
+ ExecutableElement providesMethod =
+ Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements()));
+ assertThat(
+ keyFactory.forProvidesMethod((ExecutableType) providesMethod.asType(), providesMethod))
+ .isEqualTo(new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(stringType)));
+ }
+
+ @Module
+ static final class ProvidesMethodModule {
+ @Provides String provideString() {
+ return null;
+ }
+ }
+
+ @Test public void forProvidesMethod_qualified() {
+ TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
+ TypeElement qualifierElement =
+ elements.getTypeElement(TestQualifier.class.getCanonicalName());
+ TypeElement moduleElement =
+ elements.getTypeElement(QualifiedProvidesMethodModule.class.getCanonicalName());
+ ExecutableElement providesMethod =
+ Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements()));
+ Key key =
+ keyFactory.forProvidesMethod((ExecutableType) providesMethod.asType(), providesMethod);
+ assertThat(MoreTypes.equivalence().wrap(key.qualifier().get().getAnnotationType()))
+ .isEqualTo(MoreTypes.equivalence().wrap(qualifierElement.asType()));
+ assertThat(key.wrappedType()).isEqualTo(MoreTypes.equivalence().wrap(stringType));
+ }
+
+ @Test public void qualifiedKeyEquivalents() {
+ TypeElement moduleElement =
+ elements.getTypeElement(QualifiedProvidesMethodModule.class.getCanonicalName());
+ ExecutableElement providesMethod =
+ Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements()));
+ Key provisionKey =
+ keyFactory.forProvidesMethod((ExecutableType) providesMethod.asType(), providesMethod);
+
+ TypeMirror type = elements.getTypeElement(String.class.getCanonicalName()).asType();
+ TypeElement injectableElement =
+ elements.getTypeElement(QualifiedFieldHolder.class.getCanonicalName());
+ Element injectionField =
+ Iterables.getOnlyElement(ElementFilter.fieldsIn(injectableElement.getEnclosedElements()));
+ AnnotationMirror qualifier = Iterables.getOnlyElement(injectionField.getAnnotationMirrors());
+ Key injectionKey = keyFactory.forQualifiedType(Optional.<AnnotationMirror>of(qualifier), type);
+
+ assertThat(provisionKey).isEqualTo(injectionKey);
+ }
+
+ @Module
+ static final class QualifiedProvidesMethodModule {
+ @Provides
+ @TestQualifier(@InnerAnnotation)
+ String provideQualifiedString() {
+ return null;
+ }
+ }
+
+ static final class QualifiedFieldHolder {
+ @TestQualifier(@InnerAnnotation) String aString;
+ }
+
+ @Qualifier
+ @interface TestQualifier {
+ InnerAnnotation[] value();
+ }
+
+ @interface InnerAnnotation {}
+
+ @Test public void forProvidesMethod_sets() {
+ TypeElement setElement = elements.getTypeElement(Set.class.getCanonicalName());
+ TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
+ TypeMirror setOfStringsType = types.getDeclaredType(setElement, stringType);
+ TypeElement moduleElement =
+ elements.getTypeElement(SetProvidesMethodsModule.class.getCanonicalName());
+ for (ExecutableElement providesMethod
+ : ElementFilter.methodsIn(moduleElement.getEnclosedElements())) {
+ assertThat(
+ keyFactory.forProvidesMethod((ExecutableType) providesMethod.asType(), providesMethod))
+ .isEqualTo(new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(setOfStringsType)));
+ }
+ }
+
+ @Module
+ static final class SetProvidesMethodsModule {
+ @Provides(type = SET) String provideString() {
+ return null;
+ }
+
+ @Provides(type = SET_VALUES) Set<String> provideStrings() {
+ return null;
+ }
+ }
+
+ @Module
+ static final class PrimitiveTypes {
+ @Provides int foo() {
+ return 0;
+ }
+ }
+
+ @Module
+ static final class BoxedPrimitiveTypes {
+ @Provides Integer foo() {
+ return 0;
+ }
+ }
+
+ @Test public void primitiveKeysMatchBoxedKeys() {
+ TypeElement primitiveHolder = elements.getTypeElement(PrimitiveTypes.class.getCanonicalName());
+ ExecutableElement intMethod =
+ Iterables.getOnlyElement(ElementFilter.methodsIn(primitiveHolder.getEnclosedElements()));
+ TypeElement boxedPrimitiveHolder =
+ elements.getTypeElement(BoxedPrimitiveTypes.class.getCanonicalName());
+ ExecutableElement integerMethod = Iterables.getOnlyElement(
+ ElementFilter.methodsIn(boxedPrimitiveHolder.getEnclosedElements()));
+
+ // TODO(cgruber): Truth subject for TypeMirror and TypeElement
+ TypeMirror intType = intMethod.getReturnType();
+ assertThat(intType.getKind().isPrimitive()).isTrue();
+ TypeMirror integerType = integerMethod.getReturnType();
+ assertThat(integerType.getKind().isPrimitive()).isFalse();
+ assertThat(types.isSameType(intType, integerType)).named("type equality").isFalse();
+
+ Key intKey = keyFactory.forProvidesMethod((ExecutableType) intMethod.asType(), intMethod);
+ Key integerKey =
+ keyFactory.forProvidesMethod((ExecutableType) integerMethod.asType(), integerMethod);
+ assertThat(intKey).isEqualTo(integerKey);
+ }
+
+ @Test public void forProducesMethod() {
+ TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
+ TypeElement moduleElement =
+ elements.getTypeElement(ProducesMethodsModule.class.getCanonicalName());
+ for (ExecutableElement producesMethod
+ : ElementFilter.methodsIn(moduleElement.getEnclosedElements())) {
+ assertThat(keyFactory.forProducesMethod(
+ (ExecutableType) producesMethod.asType(), producesMethod))
+ .isEqualTo(new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(stringType)));
+ }
+ }
+
+ @ProducerModule
+ static final class ProducesMethodsModule {
+ @Produces String produceString() {
+ return null;
+ }
+
+ @Produces ListenableFuture<String> produceFutureString() {
+ return null;
+ }
+ }
+
+ @Test public void forProducesMethod_sets() {
+ TypeElement setElement = elements.getTypeElement(Set.class.getCanonicalName());
+ TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
+ TypeMirror setOfStringsType = types.getDeclaredType(setElement, stringType);
+ TypeElement moduleElement =
+ elements.getTypeElement(SetProducesMethodsModule.class.getCanonicalName());
+ for (ExecutableElement producesMethod
+ : ElementFilter.methodsIn(moduleElement.getEnclosedElements())) {
+ assertThat(keyFactory.forProducesMethod(
+ (ExecutableType) producesMethod.asType(), producesMethod))
+ .isEqualTo(new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(setOfStringsType)));
+ }
+ }
+
+ @ProducerModule
+ static final class SetProducesMethodsModule {
+ @Produces(type = Produces.Type.SET) String produceString() {
+ return null;
+ }
+
+ @Produces(type = Produces.Type.SET) ListenableFuture<String> produceFutureString() {
+ return null;
+ }
+
+ @Produces(type = Produces.Type.SET_VALUES) Set<String> produceStrings() {
+ return null;
+ }
+
+ @Produces(type = Produces.Type.SET_VALUES)
+ ListenableFuture<Set<String>> produceFutureStrings() {
+ return null;
+ }
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/MapBindingComponentProcessorTest.java b/compiler/src/test/java/dagger/internal/codegen/MapBindingComponentProcessorTest.java
new file mode 100644
index 000000000..5f488c814
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/MapBindingComponentProcessorTest.java
@@ -0,0 +1,901 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.value.processor.AutoAnnotationProcessor;
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+@RunWith(JUnit4.class)
+public class MapBindingComponentProcessorTest {
+
+ @Test
+ public void mapBindingsWithEnumKey() {
+ JavaFileObject mapModuleOneFile =
+ JavaFileObjects
+ .forSourceLines("test.MapModuleOne",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleOne {",
+ " @Provides(type = MAP) @PathKey(PathEnum.ADMIN) Handler provideAdminHandler() {",
+ " return new AdminHandler();",
+ " }",
+ "}");
+ JavaFileObject mapModuleTwoFile =
+ JavaFileObjects
+ .forSourceLines("test.MapModuleTwo",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleTwo {",
+ " @Provides(type = MAP) @PathKey(PathEnum.LOGIN) Handler provideLoginHandler() {",
+ " return new LoginHandler();",
+ " }",
+ "}");
+ JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.PathKey",
+ "package test;",
+ "import dagger.MapKey;",
+ "import java.lang.annotation.Retention;",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "",
+ "@MapKey(unwrapValue = true)",
+ "@Retention(RUNTIME)",
+ "public @interface PathKey {",
+ " PathEnum value();",
+ "}");
+ JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
+ "package test;",
+ "",
+ "public enum PathEnum {",
+ " 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 componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
+ "interface TestComponent {",
+ " Map<PathEnum, Provider<Handler>> dispatcher();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.internal.MapProviderFactory;",
+ "import java.util.Map;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Handler> mapOfPathEnumAndProviderOfHandlerContribution1;",
+ " private Provider<Handler> mapOfPathEnumAndProviderOfHandlerContribution2;",
+ " private Provider<Map<PathEnum, Provider<Handler>>>",
+ " mapOfPathEnumAndProviderOfHandlerProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.mapOfPathEnumAndProviderOfHandlerContribution1 =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(builder.mapModuleOne);",
+ " this.mapOfPathEnumAndProviderOfHandlerContribution2 =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(builder.mapModuleTwo);",
+ " this.mapOfPathEnumAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<PathEnum, Handler>builder(2)",
+ " .put(PathEnum.ADMIN,",
+ " mapOfPathEnumAndProviderOfHandlerContribution1)",
+ " .put(PathEnum.LOGIN,",
+ " mapOfPathEnumAndProviderOfHandlerContribution2)",
+ " .build();",
+ " }",
+ "",
+ " @Override",
+ " public Map<PathEnum, Provider<Handler>> dispatcher() {",
+ " return mapOfPathEnumAndProviderOfHandlerProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private MapModuleOne mapModuleOne;",
+ " private MapModuleTwo mapModuleTwo;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (mapModuleOne == null) {",
+ " this.mapModuleOne = new MapModuleOne();",
+ " }",
+ " if (mapModuleTwo == null) {",
+ " this.mapModuleTwo = new MapModuleTwo();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder mapModuleOne(MapModuleOne mapModuleOne) {",
+ " if (mapModuleOne == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleOne = mapModuleOne;",
+ " return this;",
+ " }",
+ "",
+ " public Builder mapModuleTwo(MapModuleTwo mapModuleTwo) {",
+ " if (mapModuleTwo == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleTwo = mapModuleTwo;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(mapModuleOneFile,
+ mapModuleTwoFile,
+ enumKeyFile,
+ pathEnumFile,
+ HandlerFile,
+ LoginHandlerFile,
+ AdminHandlerFile,
+ componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void mapBindingsWithStringKey() {
+ JavaFileObject mapModuleOneFile =
+ JavaFileObjects
+ .forSourceLines("test.MapModuleOne",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.mapkeys.StringKey;",
+ "",
+ "@Module",
+ "final class MapModuleOne {",
+ " @Provides(type = MAP) @StringKey(\"Admin\") Handler provideAdminHandler() {",
+ " return new AdminHandler();",
+ " }",
+ "}");
+ JavaFileObject mapModuleTwoFile =
+ JavaFileObjects
+ .forSourceLines("test.MapModuleTwo",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.mapkeys.StringKey;",
+ "",
+ "@Module",
+ "final class MapModuleTwo {",
+ " @Provides(type = MAP) @StringKey(\"Login\") Handler provideLoginHandler() {",
+ " 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 componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
+ "interface TestComponent {",
+ " Map<String, Provider<Handler>> dispatcher();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.internal.MapProviderFactory;",
+ "import java.util.Map;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Handler> mapOfStringAndProviderOfHandlerContribution1;",
+ " private Provider<Handler> mapOfStringAndProviderOfHandlerContribution2;",
+ " private Provider<Map<String, Provider<Handler>>>",
+ " mapOfStringAndProviderOfHandlerProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.mapOfStringAndProviderOfHandlerContribution1 =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(builder.mapModuleOne);",
+ " this.mapOfStringAndProviderOfHandlerContribution2 =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(builder.mapModuleTwo);",
+ " this.mapOfStringAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<String, Handler>builder(2)",
+ " .put(\"Admin\", mapOfStringAndProviderOfHandlerContribution1)",
+ " .put(\"Login\", mapOfStringAndProviderOfHandlerContribution2)",
+ " .build();",
+ " }",
+ "",
+ " @Override",
+ " public Map<String, Provider<Handler>> dispatcher() {",
+ " return mapOfStringAndProviderOfHandlerProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private MapModuleOne mapModuleOne;",
+ " private MapModuleTwo mapModuleTwo;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (mapModuleOne == null) {",
+ " this.mapModuleOne = new MapModuleOne();",
+ " }",
+ " if (mapModuleTwo == null) {",
+ " this.mapModuleTwo = new MapModuleTwo();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder mapModuleOne(MapModuleOne mapModuleOne) {",
+ " if (mapModuleOne == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleOne = mapModuleOne;",
+ " return this;",
+ " }",
+ "",
+ " public Builder mapModuleTwo(MapModuleTwo mapModuleTwo) {",
+ " if (mapModuleTwo == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleTwo = mapModuleTwo;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(mapModuleOneFile,
+ mapModuleTwoFile,
+ HandlerFile,
+ LoginHandlerFile,
+ AdminHandlerFile,
+ componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void mapBindingsWithWrappedKey() {
+ JavaFileObject mapModuleOneFile =
+ JavaFileObjects
+ .forSourceLines("test.MapModuleOne",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleOne {",
+ " @Provides(type = MAP)",
+ " @WrappedClassKey(Integer.class) Handler provideAdminHandler() {",
+ " return new AdminHandler();",
+ " }",
+ "}");
+ JavaFileObject mapModuleTwoFile =
+ JavaFileObjects
+ .forSourceLines("test.MapModuleTwo",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleTwo {",
+ " @Provides(type = MAP)",
+ " @WrappedClassKey(Long.class) Handler provideLoginHandler() {",
+ " return new LoginHandler();",
+ " }",
+ "}");
+ JavaFileObject wrappedClassKeyFile = JavaFileObjects.forSourceLines("test.WrappedClassKey",
+ "package test;",
+ "import dagger.MapKey;",
+ "import java.lang.annotation.Retention;",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "",
+ "@MapKey(unwrapValue = false)",
+ "@Retention(RUNTIME)",
+ "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 componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
+ "interface TestComponent {",
+ " Map<WrappedClassKey, Provider<Handler>> dispatcher();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.internal.MapProviderFactory;",
+ "import java.util.Map;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Handler> mapOfWrappedClassKeyAndProviderOfHandlerContribution1;",
+ " private Provider<Handler> mapOfWrappedClassKeyAndProviderOfHandlerContribution2;",
+ " private Provider<Map<WrappedClassKey, Provider<Handler>>>",
+ " mapOfWrappedClassKeyAndProviderOfHandlerProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.mapOfWrappedClassKeyAndProviderOfHandlerContribution1 =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(builder.mapModuleOne);",
+ " this.mapOfWrappedClassKeyAndProviderOfHandlerContribution2 =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(builder.mapModuleTwo);",
+ " this.mapOfWrappedClassKeyAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<WrappedClassKey, Handler>builder(2)",
+ " .put(WrappedClassKeyCreator.createWrappedClassKey(Integer.class),",
+ " mapOfWrappedClassKeyAndProviderOfHandlerContribution1)",
+ " .put(WrappedClassKeyCreator.createWrappedClassKey(Long.class),",
+ " mapOfWrappedClassKeyAndProviderOfHandlerContribution2)",
+ " .build();",
+ " }",
+ "",
+ " @Override",
+ " public Map<WrappedClassKey, Provider<Handler>> dispatcher() {",
+ " return mapOfWrappedClassKeyAndProviderOfHandlerProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private MapModuleOne mapModuleOne;",
+ " private MapModuleTwo mapModuleTwo;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (mapModuleOne == null) {",
+ " this.mapModuleOne = new MapModuleOne();",
+ " }",
+ " if (mapModuleTwo == null) {",
+ " this.mapModuleTwo = new MapModuleTwo();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder mapModuleOne(MapModuleOne mapModuleOne) {",
+ " if (mapModuleOne == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleOne = mapModuleOne;",
+ " return this;",
+ " }",
+ "",
+ " public Builder mapModuleTwo(MapModuleTwo mapModuleTwo) {",
+ " if (mapModuleTwo == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleTwo = mapModuleTwo;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(mapModuleOneFile,
+ mapModuleTwoFile,
+ wrappedClassKeyFile,
+ HandlerFile,
+ LoginHandlerFile,
+ AdminHandlerFile,
+ componentFile))
+ .processedWith(new ComponentProcessor(), new AutoAnnotationProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void mapBindingsWithNonProviderValue() {
+ JavaFileObject mapModuleOneFile = JavaFileObjects.forSourceLines("test.MapModuleOne",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleOne {",
+ " @Provides(type = MAP) @PathKey(PathEnum.ADMIN) Handler provideAdminHandler() {",
+ " return new AdminHandler();",
+ " }",
+ "}");
+ JavaFileObject mapModuleTwoFile = JavaFileObjects.forSourceLines("test.MapModuleTwo",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleTwo {",
+ " @Provides(type = MAP) @PathKey(PathEnum.LOGIN) Handler provideLoginHandler() {",
+ " return new LoginHandler();",
+ " }",
+ "}");
+ JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.PathKey",
+ "package test;",
+ "import dagger.MapKey;",
+ "import java.lang.annotation.Retention;",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "",
+ "@MapKey(unwrapValue = true)",
+ "@Retention(RUNTIME)",
+ "public @interface PathKey {",
+ " PathEnum value();",
+ "}");
+ JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
+ "package test;",
+ "",
+ "public enum PathEnum {",
+ " 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 componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
+ "interface TestComponent {",
+ " Map<PathEnum, Handler> dispatcher();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.internal.MapFactory;",
+ "import dagger.internal.MapProviderFactory;",
+ "import java.util.Map;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Handler> mapOfPathEnumAndProviderOfHandlerContribution1;",
+ " private Provider<Handler> mapOfPathEnumAndProviderOfHandlerContribution2;",
+ " private Provider<Map<PathEnum, Provider<Handler>>>",
+ " mapOfPathEnumAndProviderOfHandlerProvider;",
+ " private Provider<Map<PathEnum, Handler>> mapOfPathEnumAndHandlerProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.mapOfPathEnumAndProviderOfHandlerContribution1 =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(builder.mapModuleOne);",
+ " this.mapOfPathEnumAndProviderOfHandlerContribution2 =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(builder.mapModuleTwo);",
+ " this.mapOfPathEnumAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<PathEnum, Handler>builder(2)",
+ " .put(PathEnum.ADMIN,",
+ " mapOfPathEnumAndProviderOfHandlerContribution1)",
+ " .put(PathEnum.LOGIN,",
+ " mapOfPathEnumAndProviderOfHandlerContribution2)",
+ " .build();",
+ " this.mapOfPathEnumAndHandlerProvider =",
+ " MapFactory.create(mapOfPathEnumAndProviderOfHandlerProvider);",
+ " }",
+ "",
+ " @Override",
+ " public Map<PathEnum, Handler> dispatcher() {",
+ " return mapOfPathEnumAndHandlerProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private MapModuleOne mapModuleOne;",
+ " private MapModuleTwo mapModuleTwo;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (mapModuleOne == null) {",
+ " this.mapModuleOne = new MapModuleOne();",
+ " }",
+ " if (mapModuleTwo == null) {",
+ " this.mapModuleTwo = new MapModuleTwo();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder mapModuleOne(MapModuleOne mapModuleOne) {",
+ " if (mapModuleOne == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleOne = mapModuleOne;",
+ " return this;",
+ " }",
+ "",
+ " public Builder mapModuleTwo(MapModuleTwo mapModuleTwo) {",
+ " if (mapModuleTwo == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleTwo = mapModuleTwo;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(mapModuleOneFile,
+ mapModuleTwoFile,
+ enumKeyFile,
+ pathEnumFile,
+ HandlerFile,
+ LoginHandlerFile,
+ AdminHandlerFile,
+ componentFile)).
+ processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void injectMapWithoutMapBinding() {
+ JavaFileObject mapModuleFile = JavaFileObjects.forSourceLines("test.MapModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.HashMap;",
+ "import java.util.Map;",
+ "",
+ "@Module",
+ "final class MapModule {",
+ " @Provides Map<String, String> provideAMap() {",
+ " Map<String, String> map = new HashMap<String, String>();",
+ " map.put(\"Hello\", \"World\");",
+ " return map;",
+ " }",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "",
+ "@Component(modules = {MapModule.class})",
+ "interface TestComponent {",
+ " Map<String, String> dispatcher();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import java.util.Map;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Map<String, String>> provideAMapProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.provideAMapProvider = MapModule_ProvideAMapFactory.create(builder.mapModule);",
+ " }",
+ "",
+ " @Override",
+ " public Map<String, String> dispatcher() {",
+ " return provideAMapProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private MapModule mapModule;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (mapModule == null) {",
+ " this.mapModule = new MapModule();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder mapModule(MapModule mapModule) {",
+ " if (mapModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModule = mapModule;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(mapModuleFile,componentFile))
+ .processedWith(new ComponentProcessor()).compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void mapBindingsWithDuplicateKeys() {
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.MapModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.mapkeys.StringKey;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "@Module",
+ "final class MapModule {",
+ " @Provides(type = MAP) @StringKey(\"AKey\") Object provideObjectForAKey() {",
+ " return \"one\";",
+ " }",
+ "",
+ " @Provides(type = MAP) @StringKey(\"AKey\") Object provideObjectForAKeyAgain() {",
+ " return \"one again\";",
+ " }",
+ "}");
+ JavaFileObject componentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {MapModule.class})",
+ "interface TestComponent {",
+ " Map<String, Object> objects();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(module, componentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("The same map key is bound more than once")
+ .and()
+ .withErrorContaining("provideObjectForAKey()")
+ .and()
+ .withErrorContaining("provideObjectForAKeyAgain()")
+ .and()
+ .withErrorCount(1);
+ }
+
+ @Test
+ public void mapBindingsWithInconsistentKeyAnnotations() {
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.MapModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.mapkeys.StringKey;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "@Module",
+ "final class MapModule {",
+ " @Provides(type = MAP) @StringKey(\"AKey\") Object provideObjectForAKey() {",
+ " return \"one\";",
+ " }",
+ "",
+ " @Provides(type = MAP) @StringKeyTwo(\"BKey\") Object provideObjectForBKey() {",
+ " return \"two\";",
+ " }",
+ "}");
+ JavaFileObject stringKeyTwoFile =
+ JavaFileObjects.forSourceLines(
+ "test.StringKeyTwo",
+ "package test;",
+ "",
+ "import dagger.MapKey;",
+ "",
+ "@MapKey(unwrapValue = true)",
+ "public @interface StringKeyTwo {",
+ " String value();",
+ "}");
+ JavaFileObject componentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "",
+ "@Component(modules = {MapModule.class})",
+ "interface TestComponent {",
+ " Map<String, Object> objects();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(module, stringKeyTwoFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("uses more than one @MapKey annotation type")
+ .and()
+ .withErrorContaining("provideObjectForAKey()")
+ .and()
+ .withErrorContaining("provideObjectForBKey()")
+ .and()
+ .withErrorCount(1);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/MapKeyProcessorTest.java b/compiler/src/test/java/dagger/internal/codegen/MapKeyProcessorTest.java
new file mode 100644
index 000000000..bc8a2660e
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/MapKeyProcessorTest.java
@@ -0,0 +1,473 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.auto.value.processor.AutoAnnotationProcessor;
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+@RunWith(JUnit4.class)
+public class MapKeyProcessorTest {
+ @Test
+ public void mapKeyCreatorFile() {
+ JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.PathKey",
+ "package test;",
+ "import dagger.MapKey;",
+ "import java.lang.annotation.Retention;",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "",
+ "@MapKey(unwrapValue = false)",
+ "@Retention(RUNTIME)",
+ "public @interface PathKey {",
+ " PathEnum value();",
+ " String relativePath() default \"Defaultpath\";",
+ "}");
+ JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
+ "package test;",
+ "",
+ "public enum PathEnum {",
+ " ADMIN,",
+ " LOGIN;",
+ "}");
+ JavaFileObject generatedKeyCreator =
+ JavaFileObjects.forSourceLines(
+ "test.PathKeyCreator",
+ "package test;",
+ "",
+ "import com.google.auto.value.AutoAnnotation;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class PathKeyCreator {",
+ " @AutoAnnotation",
+ " public static PathKey createPathKey(PathEnum value, String relativePath) {",
+ " return new AutoAnnotation_PathKeyCreator_createPathKey(value, relativePath);",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(enumKeyFile, pathEnumFile))
+ .processedWith(new ComponentProcessor(), new AutoAnnotationProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedKeyCreator);
+ }
+
+ @Test
+ public void nestedMapKeyCreatorFile() {
+ JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.Container",
+ "package test;",
+ "import dagger.MapKey;",
+ "import java.lang.annotation.Retention;",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "",
+ "public interface Container {",
+ "@MapKey(unwrapValue = false)",
+ "@Retention(RUNTIME)",
+ "public @interface PathKey {",
+ " PathEnum value();",
+ " String relativePath() default \"Defaultpath\";",
+ "}",
+ "}");
+ JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
+ "package test;",
+ "",
+ "public enum PathEnum {",
+ " ADMIN,",
+ " LOGIN;",
+ "}");
+ JavaFileObject generatedKeyCreator =
+ JavaFileObjects.forSourceLines(
+ "test.Container$PathKeyCreator",
+ "package test;",
+ "",
+ "import com.google.auto.value.AutoAnnotation;",
+ "import javax.annotation.Generated;",
+ "import test.Container.PathKey",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class Container$PathKeyCreator {",
+ " @AutoAnnotation",
+ " public static PathKey createPathKey(PathEnum value, String relativePath) {",
+ " return new AutoAnnotation_Container$PathKeyCreator_createPathKey(",
+ " value, relativePath);",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(enumKeyFile, pathEnumFile))
+ .processedWith(new ComponentProcessor(), new AutoAnnotationProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedKeyCreator);
+ }
+
+ @Test
+ public void mapKeyComponentFileWithDisorderedKeyField() {
+ JavaFileObject mapModuleOneFile = JavaFileObjects.forSourceLines("test.MapModuleOne",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleOne {",
+ " @Provides(type = MAP) @PathKey(relativePath = \"AdminPath\", value = PathEnum.ADMIN)",
+ " Handler provideAdminHandler() {",
+ " return new AdminHandler();",
+ " }",
+ "}");
+ JavaFileObject mapModuleTwoFile =JavaFileObjects.forSourceLines("test.MapModuleTwo",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleTwo {",
+ " @Provides(type = MAP) @PathKey(value = PathEnum.LOGIN, relativePath = \"LoginPath\")",
+ " Handler provideLoginHandler() {",
+ " return new LoginHandler();",
+ " }",
+ "}");
+ JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.PathKey",
+ "package test;",
+ "import dagger.MapKey;",
+ "import java.lang.annotation.Retention;",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "",
+ "@MapKey(unwrapValue = false)",
+ "@Retention(RUNTIME)",
+ "public @interface PathKey {",
+ " PathEnum value();",
+ " String relativePath() default \"DefaultPath\";",
+ "}");
+ JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
+ "package test;",
+ "",
+ "public enum PathEnum {",
+ " 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 componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
+ "interface TestComponent {",
+ " Map<PathKey, Provider<Handler>> dispatcher();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.internal.MapProviderFactory;",
+ "import java.util.Map;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Handler> mapOfPathKeyAndProviderOfHandlerContribution1;",
+ " private Provider<Handler> mapOfPathKeyAndProviderOfHandlerContribution2;",
+ " private Provider<Map<PathKey, Provider<Handler>>>",
+ " mapOfPathKeyAndProviderOfHandlerProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.mapOfPathKeyAndProviderOfHandlerContribution1 =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(builder.mapModuleOne);",
+ " this.mapOfPathKeyAndProviderOfHandlerContribution2 =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(builder.mapModuleTwo);",
+ " this.mapOfPathKeyAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<PathKey, Handler>builder(2)",
+ " .put(PathKeyCreator.createPathKey(PathEnum.ADMIN, \"AdminPath\"),",
+ " mapOfPathKeyAndProviderOfHandlerContribution1)",
+ " .put(PathKeyCreator.createPathKey(PathEnum.LOGIN, \"LoginPath\"),",
+ " mapOfPathKeyAndProviderOfHandlerContribution2)",
+ " .build();",
+ " }",
+ "",
+ " @Override",
+ " public Map<PathKey, Provider<Handler>> dispatcher() {",
+ " return mapOfPathKeyAndProviderOfHandlerProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private MapModuleOne mapModuleOne;",
+ " private MapModuleTwo mapModuleTwo;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (mapModuleOne == null) {",
+ " this.mapModuleOne = new MapModuleOne();",
+ " }",
+ " if (mapModuleTwo == null) {",
+ " this.mapModuleTwo = new MapModuleTwo();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder mapModuleOne(MapModuleOne mapModuleOne) {",
+ " if (mapModuleOne == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleOne = mapModuleOne;",
+ " return this;",
+ " }",
+ "",
+ " public Builder mapModuleTwo(MapModuleTwo mapModuleTwo) {",
+ " if (mapModuleTwo == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleTwo = mapModuleTwo;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(
+ ImmutableList.of(
+ mapModuleOneFile,
+ mapModuleTwoFile,
+ enumKeyFile,
+ pathEnumFile,
+ handlerFile,
+ loginHandlerFile,
+ adminHandlerFile,
+ componentFile))
+ .processedWith(new ComponentProcessor(), new AutoAnnotationProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void mapKeyComponentFileWithDefaultField() {
+ JavaFileObject mapModuleOneFile = JavaFileObjects.forSourceLines("test.MapModuleOne",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleOne {",
+ " @Provides(type = MAP) @PathKey(value = PathEnum.ADMIN) Handler provideAdminHandler() {",
+ " return new AdminHandler();",
+ " }",
+ "}");
+ JavaFileObject mapModuleTwoFile =JavaFileObjects.forSourceLines("test.MapModuleTwo",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleTwo {",
+ " @Provides(type = MAP) @PathKey(value = PathEnum.LOGIN, relativePath = \"LoginPath\")",
+ " Handler provideLoginHandler() {",
+ " return new LoginHandler();",
+ " }",
+ "}");
+ JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.PathKey",
+ "package test;",
+ "import dagger.MapKey;",
+ "import java.lang.annotation.Retention;",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "",
+ "@MapKey(unwrapValue = false)",
+ "@Retention(RUNTIME)",
+ "public @interface PathKey {",
+ " PathEnum value();",
+ " String relativePath() default \"DefaultPath\";",
+ "}");
+ JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
+ "package test;",
+ "",
+ "public enum PathEnum {",
+ " 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 componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
+ "interface TestComponent {",
+ " Map<PathKey, Provider<Handler>> dispatcher();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.internal.MapProviderFactory;",
+ "import java.util.Map;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Handler> mapOfPathKeyAndProviderOfHandlerContribution1;",
+ " private Provider<Handler> mapOfPathKeyAndProviderOfHandlerContribution2;",
+ " private Provider<Map<PathKey, Provider<Handler>>>",
+ " mapOfPathKeyAndProviderOfHandlerProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.mapOfPathKeyAndProviderOfHandlerContribution1 =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(builder.mapModuleOne);",
+ " this.mapOfPathKeyAndProviderOfHandlerContribution2 =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(builder.mapModuleTwo);",
+ " this.mapOfPathKeyAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<PathKey, Handler>builder(2)",
+ " .put(PathKeyCreator.createPathKey(PathEnum.ADMIN, \"DefaultPath\"),",
+ " mapOfPathKeyAndProviderOfHandlerContribution1)",
+ " .put(PathKeyCreator.createPathKey(PathEnum.LOGIN, \"LoginPath\"),",
+ " mapOfPathKeyAndProviderOfHandlerContribution2)",
+ " .build();",
+ " }",
+ "",
+ " @Override",
+ " public Map<PathKey, Provider<Handler>> dispatcher() {",
+ " return mapOfPathKeyAndProviderOfHandlerProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private MapModuleOne mapModuleOne;",
+ " private MapModuleTwo mapModuleTwo;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (mapModuleOne == null) {",
+ " this.mapModuleOne = new MapModuleOne();",
+ " }",
+ " if (mapModuleTwo == null) {",
+ " this.mapModuleTwo = new MapModuleTwo();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder mapModuleOne(MapModuleOne mapModuleOne) {",
+ " if (mapModuleOne == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleOne = mapModuleOne;",
+ " return this;",
+ " }",
+ "",
+ " public Builder mapModuleTwo(MapModuleTwo mapModuleTwo) {",
+ " if (mapModuleTwo == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleTwo = mapModuleTwo;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(
+ ImmutableList.of(
+ mapModuleOneFile,
+ mapModuleTwoFile,
+ enumKeyFile,
+ pathEnumFile,
+ handlerFile,
+ loginHandlerFile,
+ adminHandlerFile,
+ componentFile))
+ .processedWith(new ComponentProcessor(), new AutoAnnotationProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedComponent);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/MembersInjectionTest.java b/compiler/src/test/java/dagger/internal/codegen/MembersInjectionTest.java
new file mode 100644
index 000000000..7925bd222
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/MembersInjectionTest.java
@@ -0,0 +1,875 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.testing.compile.JavaFileObjects;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Set;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.TypeElement;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+@RunWith(JUnit4.class)
+public class MembersInjectionTest {
+ @Test
+ public void parentClass_noInjectedMembers() {
+ JavaFileObject childFile = JavaFileObjects.forSourceLines("test.Child",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public final class Child extends Parent {",
+ " @Inject Child() {}",
+ "}");
+ JavaFileObject parentFile = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "public abstract class Parent {}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " Child child();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.MembersInjectors;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Child> childProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.childProvider =",
+ " Child_Factory.create((MembersInjector) MembersInjectors.noOp());",
+ " }",
+ "",
+ " @Override",
+ " public Child child() {",
+ " return childProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " return new DaggerTestComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(childFile, parentFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void parentClass_injectedMembersInSupertype() {
+ JavaFileObject childFile = JavaFileObjects.forSourceLines("test.Child",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public final class Child extends Parent {",
+ " @Inject Child() {}",
+ "}");
+ JavaFileObject parentFile = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public abstract class Parent {",
+ " @Inject Dep dep;",
+ "}");
+ JavaFileObject depFile = JavaFileObjects.forSourceLines("test.Dep",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class Dep {",
+ " @Inject Dep() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " Child child();",
+ "}");
+ JavaFileObject generatedComponent =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private MembersInjector<Child> childMembersInjector;",
+ " private Provider<Child> childProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.childMembersInjector = Child_MembersInjector.create(Dep_Factory.create());",
+ " this.childProvider = Child_Factory.create(childMembersInjector);",
+ " }",
+ "",
+ " @Override",
+ " public Child child() {",
+ " return childProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {}",
+ "",
+ " public TestComponent build() {",
+ " return new DaggerTestComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(childFile, parentFile, depFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedComponent);
+ }
+
+ @Test public void fieldAndMethodGenerics() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class GenericClass<A, B> {",
+ " @Inject A a;",
+ "",
+ " @Inject GenericClass() {}",
+ "",
+ " @Inject void register(B b) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.GenericClass_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class GenericClass_MembersInjector<A, B>",
+ " implements MembersInjector<GenericClass<A, B>> {",
+ " private final Provider<A> aProvider;",
+ " private final Provider<B> bProvider;",
+ "",
+ " public GenericClass_MembersInjector(Provider<A> aProvider, Provider<B> bProvider) {",
+ " assert aProvider != null;",
+ " this.aProvider = aProvider;",
+ " assert bProvider != null;",
+ " this.bProvider = bProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(GenericClass<A, B> instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.a = aProvider.get();",
+ " instance.register(bProvider.get());",
+ " }",
+ "",
+ " public static <A, B> MembersInjector<GenericClass<A, B>> create(",
+ " Provider<A> aProvider, Provider<B> bProvider) {",
+ " return new GenericClass_MembersInjector<A, B>(aProvider, bProvider);",
+ " }",
+ "",
+ " public static <A, B> void injectA(GenericClass<A, B> instance, Provider<A> aProvider) {",
+ " instance.a = aProvider.get();",
+ " }",
+ "",
+ " public static <A, B> void injectRegister(",
+ " GenericClass<A, B> instance, Provider<B> bProvider) {",
+ " instance.register(bProvider.get());",
+ " }",
+ "",
+ "}");
+ assertAbout(javaSource())
+ .that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expected);
+ }
+
+ @Test public void subclassedGenericMembersInjectors() {
+ JavaFileObject a = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A() {}",
+ "}");
+ JavaFileObject a2 = JavaFileObjects.forSourceLines("test.A2",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A2 {",
+ " @Inject A2() {}",
+ "}");
+ JavaFileObject parent = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Parent<X, Y> {",
+ " @Inject X x;",
+ " @Inject Y y;",
+ " @Inject A2 a2;",
+ "",
+ " @Inject Parent() {}",
+ "}");
+ JavaFileObject child = JavaFileObjects.forSourceLines("test.Child",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Child<T> extends Parent<T, A> {",
+ " @Inject A a;",
+ " @Inject T t;",
+ "",
+ " @Inject Child() {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.Child_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class Child_MembersInjector<T>",
+ " implements MembersInjector<Child<T>> {",
+ " private final Provider<T> tAndXProvider;",
+ " private final Provider<A> aAndYProvider;",
+ " private final Provider<A2> a2Provider;",
+ "",
+ " public Child_MembersInjector(",
+ " Provider<T> tAndXProvider, Provider<A> aAndYProvider, Provider<A2> a2Provider) {",
+ " assert tAndXProvider != null;",
+ " this.tAndXProvider = tAndXProvider;",
+ " assert aAndYProvider != null;",
+ " this.aAndYProvider = aAndYProvider;",
+ " assert a2Provider != null;",
+ " this.a2Provider = a2Provider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(Child<T> instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " ((test.Parent) instance).x = tAndXProvider.get();",
+ " ((test.Parent) instance).y = aAndYProvider.get();",
+ " ((test.Parent) instance).a2 = a2Provider.get();",
+ " instance.a = aAndYProvider.get();",
+ " instance.t = tAndXProvider.get();",
+ " }",
+ "",
+ " public static <T> MembersInjector<Child<T>> create(",
+ " Provider<T> tAndXProvider, Provider<A> aAndYProvider, Provider<A2> a2Provider) {",
+ " return new Child_MembersInjector<T>(tAndXProvider, aAndYProvider, a2Provider);",
+ " }",
+ "",
+ " public static <T> void injectA(Child<T> instance, Provider<A> aProvider) {",
+ " instance.a = aProvider.get();",
+ " }",
+ "",
+ " public static <T> void injectT(Child<T> instance, Provider<T> tProvider) {",
+ " instance.t = tProvider.get();",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(a, a2, parent, child))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expected);
+ }
+
+ @Test public void fieldInjection() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.FieldInjection",
+ "package test;",
+ "",
+ "import dagger.Lazy;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "class FieldInjection {",
+ " @Inject String string;",
+ " @Inject Lazy<String> lazyString;",
+ " @Inject Provider<String> stringProvider;",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.FieldInjection_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.DoubleCheckLazy;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class FieldInjection_MembersInjector",
+ " implements MembersInjector<FieldInjection> {",
+ " private final Provider<String> stringProvider;",
+ "",
+ " public FieldInjection_MembersInjector(Provider<String> stringProvider) {",
+ " assert stringProvider != null;",
+ " this.stringProvider = stringProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(FieldInjection instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.string = stringProvider.get();",
+ " instance.lazyString = DoubleCheckLazy.create(stringProvider);",
+ " instance.stringProvider = stringProvider;",
+ " }",
+ "",
+ " public static MembersInjector<FieldInjection> create(Provider<String> stringProvider) {",
+ " return new FieldInjection_MembersInjector(stringProvider);",
+ " }",
+ "",
+ " public static void injectString(",
+ " FieldInjection instance, Provider<String> stringProvider) {",
+ " instance.string = stringProvider.get();",
+ " }",
+ "",
+ " public static void injectLazyString(",
+ " FieldInjection instance, Provider<String> lazyStringProvider) {",
+ " instance.lazyString = DoubleCheckLazy.create(lazyStringProvider);",
+ " }",
+ "",
+ " public static void injectStringProvider(",
+ " FieldInjection instance, Provider<String> stringProvider) {",
+ " instance.stringProvider = stringProvider;",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expected);
+ }
+
+ @Test public void methodInjection() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.MethodInjection",
+ "package test;",
+ "",
+ "import dagger.Lazy;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "class MethodInjection {",
+ " @Inject void noArgs() {}",
+ " @Inject void oneArg(String string) {}",
+ " @Inject void manyArgs(",
+ " String string, Lazy<String> lazyString, Provider<String> stringProvider) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.MethodInjection_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.DoubleCheckLazy;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class MethodInjection_MembersInjector",
+ " implements MembersInjector<MethodInjection> {",
+ "",
+ " private final Provider<String> stringProvider;",
+ "",
+ " public MethodInjection_MembersInjector(Provider<String> stringProvider) {",
+ " assert stringProvider != null;",
+ " this.stringProvider = stringProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(MethodInjection instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.noArgs();",
+ " instance.oneArg(stringProvider.get());",
+ " instance.manyArgs(stringProvider.get(), DoubleCheckLazy.create(stringProvider),",
+ " stringProvider);",
+ " }",
+ "",
+ " public static MembersInjector<MethodInjection> create(",
+ " Provider<String> stringProvider) {",
+ " return new MethodInjection_MembersInjector(stringProvider);",
+ " }",
+ "",
+ " public static void injectNoArgs(MethodInjection instance) {",
+ " instance.noArgs();",
+ " }",
+ "",
+ " public static void injectOneArg(",
+ " MethodInjection instance, Provider<String> stringProvider) {",
+ " instance.oneArg(stringProvider.get());",
+ " }",
+ "",
+ " public static void injectManyArgs(",
+ " MethodInjection instance,",
+ " Provider<String> stringProvider,",
+ " Provider<String> lazyStringProvider,",
+ " Provider<String> stringProvider2) {",
+ " instance.manyArgs(",
+ " stringProvider.get(),",
+ " DoubleCheckLazy.create(lazyStringProvider),",
+ " stringProvider2);",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expected);
+ }
+
+ @Test
+ public void mixedMemberInjection() {
+ JavaFileObject file = JavaFileObjects.forSourceLines(
+ "test.MixedMemberInjection",
+ "package test;",
+ "",
+ "import dagger.Lazy;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "class MixedMemberInjection {",
+ " @Inject String string;",
+ " @Inject void setString(String s) {}",
+ " @Inject Object object;",
+ " @Inject void setObject(Object o) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.MixedMemberInjection_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class MixedMemberInjection_MembersInjector",
+ " implements MembersInjector<MixedMemberInjection> {",
+ "",
+ " private final Provider<String> stringAndSProvider;",
+ " private final Provider<Object> objectAndOProvider;",
+ "",
+ " public MixedMemberInjection_MembersInjector(",
+ " Provider<String> stringAndSProvider,",
+ " Provider<Object> objectAndOProvider) {",
+ " assert stringAndSProvider != null;",
+ " this.stringAndSProvider = stringAndSProvider;",
+ " assert objectAndOProvider != null;",
+ " this.objectAndOProvider = objectAndOProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(MixedMemberInjection instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.string = stringAndSProvider.get();",
+ " instance.object = objectAndOProvider.get();",
+ " instance.setString(stringAndSProvider.get());",
+ " instance.setObject(objectAndOProvider.get());",
+ " }",
+ "",
+ " public static MembersInjector<MixedMemberInjection> create(",
+ " Provider<String> stringAndSProvider,",
+ " Provider<Object> objectAndOProvider) {",
+ " return new MixedMemberInjection_MembersInjector(",
+ " stringAndSProvider, objectAndOProvider);",
+ " }",
+ " public static void injectString(",
+ " MixedMemberInjection instance, Provider<String> stringProvider) {",
+ " instance.string = stringProvider.get();",
+ " }",
+ "",
+ " public static void injectObject(",
+ " MixedMemberInjection instance, Provider<Object> objectProvider) {",
+ " instance.object = objectProvider.get();",
+ " }",
+ "",
+ " public static void injectSetString(",
+ " MixedMemberInjection instance, Provider<String> sProvider) {",
+ " instance.setString(sProvider.get());",
+ " }",
+ "",
+ " public static void injectSetObject(",
+ " MixedMemberInjection instance, Provider<Object> oProvider) {",
+ " instance.setObject(oProvider.get());",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expected);
+ }
+
+ @Test public void injectConstructorAndMembersInjection() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.AllInjections",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class AllInjections {",
+ " @Inject String s;",
+ " @Inject AllInjections(String s) {}",
+ " @Inject void s(String s) {}",
+ "}");
+ JavaFileObject expectedMembersInjector = JavaFileObjects.forSourceLines(
+ "test.AllInjections_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class AllInjections_MembersInjector ",
+ " implements MembersInjector<AllInjections> {",
+ "",
+ " private final Provider<String> sProvider;",
+ "",
+ " public AllInjections_MembersInjector(Provider<String> sProvider) {",
+ " assert sProvider != null;",
+ " this.sProvider = sProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(AllInjections instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.s = sProvider.get();",
+ " instance.s(sProvider.get());",
+ " }",
+ "",
+ " public static MembersInjector<AllInjections> create(Provider<String> sProvider) {",
+ " return new AllInjections_MembersInjector(sProvider);",
+ " }",
+ "",
+ " public static void injectS(AllInjections instance, Provider<String> sProvider) {",
+ " instance.s = sProvider.get();",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expectedMembersInjector);
+ }
+
+ @Test public void supertypeMembersInjection() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "class A {}");
+ JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class B extends A {",
+ " @Inject String s;",
+ "}");
+ JavaFileObject expectedMembersInjector = JavaFileObjects.forSourceLines(
+ "test.AllInjections_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class B_MembersInjector implements MembersInjector<B> {",
+ " private final Provider<String> sProvider;",
+ "",
+ " public B_MembersInjector(Provider<String> sProvider) {",
+ " assert sProvider != null;",
+ " this.sProvider = sProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(B instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.s = sProvider.get();",
+ " }",
+ "",
+ " public static MembersInjector<B> create(Provider<String> sProvider) {",
+ " return new B_MembersInjector(sProvider);",
+ " }",
+ " public static void injectS(B instance, Provider<String> sProvider) {",
+ " instance.s = sProvider.get();",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(aFile, bFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expectedMembersInjector);
+ }
+
+ @Test
+ public void simpleComponentWithNesting() {
+ JavaFileObject nestedTypesFile = JavaFileObjects.forSourceLines(
+ "test.OuterType",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Inject;",
+ "",
+ "final class OuterType {",
+ " static class A {",
+ " @Inject A() {}",
+ " }",
+ " static class B {",
+ " @Inject A a;",
+ " }",
+ " @Component interface SimpleComponent {",
+ " A a();",
+ " void inject(B b);",
+ " }",
+ "}");
+ JavaFileObject bMembersInjector = JavaFileObjects.forSourceLines(
+ "test.OuterType$B_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import test.OuterType.A;",
+ "import test.OuterType.B;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class OuterType$B_MembersInjector implements MembersInjector<B> {",
+ " private final Provider<A> aProvider;",
+ "",
+ " public OuterType$B_MembersInjector(Provider<A> aProvider) {",
+ " assert aProvider != null;",
+ " this.aProvider = aProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(B instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.a = aProvider.get();",
+ " }",
+ "",
+ " public static MembersInjector<B> create(Provider<A> aProvider) {",
+ " return new OuterType$B_MembersInjector(aProvider);",
+ " }",
+ "",
+ " public static void injectA(B instance, Provider<A> aProvider) {",
+ " instance.a = aProvider.get();",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(nestedTypesFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(bMembersInjector);
+ }
+
+ @Test
+ public void componentWithNestingAndGeneratedType() {
+ JavaFileObject nestedTypesFile =
+ JavaFileObjects.forSourceLines(
+ "test.OuterType",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Inject;",
+ "",
+ "final class OuterType {",
+ " @Inject GeneratedType generated;",
+ " static class A {",
+ " @Inject A() {}",
+ " }",
+ " static class B {",
+ " @Inject A a;",
+ " }",
+ " @Component interface SimpleComponent {",
+ " A a();",
+ " void inject(B b);",
+ " }",
+ "}");
+ JavaFileObject bMembersInjector =
+ JavaFileObjects.forSourceLines(
+ "test.OuterType$B_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import test.OuterType.A;",
+ "import test.OuterType.B;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class OuterType$B_MembersInjector implements MembersInjector<B> {",
+ " private final Provider<A> aProvider;",
+ "",
+ " public OuterType$B_MembersInjector(Provider<A> aProvider) {",
+ " assert aProvider != null;",
+ " this.aProvider = aProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(B instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.a = aProvider.get();",
+ " }",
+ "",
+ " public static MembersInjector<B> create(Provider<A> aProvider) {",
+ " return new OuterType$B_MembersInjector(aProvider);",
+ " }",
+ "",
+ " public static void injectA(B instance, Provider<A> aProvider) {",
+ " instance.a = aProvider.get();",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(nestedTypesFile)
+ .processedWith(
+ new ComponentProcessor(),
+ new AbstractProcessor() {
+ private boolean done;
+
+ @Override
+ public Set<String> getSupportedAnnotationTypes() {
+ return ImmutableSet.of("*");
+ }
+
+ @Override
+ public boolean process(
+ Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (!done) {
+ done = true;
+ try (Writer writer =
+ processingEnv
+ .getFiler()
+ .createSourceFile("test.GeneratedType")
+ .openWriter()) {
+ writer.write(
+ Joiner.on('\n')
+ .join(
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class GeneratedType {",
+ " @Inject GeneratedType() {}",
+ "}"));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return false;
+ }
+ })
+ .compilesWithoutError()
+ .and()
+ .generatesSources(bMembersInjector);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/MethodSignatureFormatterTest.java b/compiler/src/test/java/dagger/internal/codegen/MethodSignatureFormatterTest.java
new file mode 100644
index 000000000..45791c75c
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/MethodSignatureFormatterTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.testing.compile.CompilationRule;
+import dagger.internal.codegen.MethodSignatureFormatterTest.OuterClass.InnerClass;
+import javax.inject.Singleton;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+@RunWith(JUnit4.class)
+public class MethodSignatureFormatterTest {
+ @Rule public CompilationRule compilationRule = new CompilationRule();
+
+ static class OuterClass {
+ @interface Foo {
+ Class<?> bar();
+ }
+
+ static class InnerClass {
+ @Foo(bar = String.class)
+ @Singleton
+ String foo(@SuppressWarnings("unused") int a, ImmutableList<Boolean> blah) { return "foo"; }
+ }
+ }
+
+ @Test public void methodSignatureTest() {
+ Elements elements = compilationRule.getElements();
+ TypeElement inner = elements.getTypeElement(InnerClass.class.getCanonicalName());
+ ExecutableElement method = Iterables.getOnlyElement(methodsIn(inner.getEnclosedElements()));
+ String formatted = new MethodSignatureFormatter(compilationRule.getTypes()).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.
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/MissingBindingSuggestionsTest.java b/compiler/src/test/java/dagger/internal/codegen/MissingBindingSuggestionsTest.java
new file mode 100644
index 000000000..0ae01b40c
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/MissingBindingSuggestionsTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import java.util.Arrays;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+@RunWith(JUnit4.class)
+public class MissingBindingSuggestionsTest {
+ private static JavaFileObject injectable(String className, String constructorParams) {
+ return JavaFileObjects.forSourceLines("test." + className,
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class " + className +" {",
+ " @Inject " + className + "(" + constructorParams + ") {}",
+ "}");
+ }
+
+ private static JavaFileObject emptyInterface(String interfaceName) {
+ return JavaFileObjects.forSourceLines("test." + interfaceName,
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "interface " + interfaceName +" {}");
+ }
+
+ @Test public void suggestsBindingInSeparateComponent() {
+ JavaFileObject fooComponent = JavaFileObjects.forSourceLines("test.FooComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface FooComponent {",
+ " Foo getFoo();",
+ "}");
+ JavaFileObject barModule = JavaFileObjects.forSourceLines("test.BarModule",
+ "package test;",
+ "",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "final class BarModule {",
+ " @Provides Bar provideBar() {return null;}",
+ "}");
+ JavaFileObject barComponent = JavaFileObjects.forSourceLines("test.BarComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = {BarModule.class})",
+ "interface BarComponent {",
+ " Bar getBar();",
+ "}");
+ JavaFileObject foo = injectable("Foo", "Bar bar");
+ JavaFileObject bar = emptyInterface("Bar");
+
+ JavaFileObject topComponent = JavaFileObjects.forSourceLines("test.TopComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TopComponent {",
+ " FooComponent getFoo();",
+ " BarComponent getBar(BarModule barModule);",
+ "}");
+
+ assertAbout(javaSources())
+ .that(ImmutableList.of(
+ fooComponent, barComponent, topComponent, foo, bar, barModule))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("A binding with matching key exists in component: test.BarComponent");
+ }
+
+ @Test public void suggestsBindingInNestedSubcomponent() {
+ JavaFileObject fooComponent = JavaFileObjects.forSourceLines("test.FooComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface FooComponent {",
+ " Foo getFoo();",
+ "}");
+ JavaFileObject barComponent = JavaFileObjects.forSourceLines("test.BarComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent()",
+ "interface BarComponent {",
+ " BazComponent getBaz();",
+ "}");
+ JavaFileObject bazModule = JavaFileObjects.forSourceLines("test.BazModule",
+ "package test;",
+ "",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "final class BazModule {",
+ " @Provides Baz provideBaz() {return null;}",
+ "}");
+ JavaFileObject bazComponent = JavaFileObjects.forSourceLines("test.BazComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = {BazModule.class})",
+ "interface BazComponent {",
+ " Baz getBaz();",
+ "}");
+ JavaFileObject foo = injectable("Foo", "Baz baz");
+ JavaFileObject baz = emptyInterface("Baz");
+
+ JavaFileObject topComponent = JavaFileObjects.forSourceLines("test.TopComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TopComponent {",
+ " FooComponent getFoo();",
+ " BarComponent getBar();",
+ "}");
+
+ assertAbout(javaSources())
+ .that(ImmutableList.of(
+ fooComponent, barComponent, bazComponent, topComponent, foo, baz, bazModule))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("A binding with matching key exists in component: test.BazComponent");
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ModuleFactoryGeneratorTest.java b/compiler/src/test/java/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
new file mode 100644
index 000000000..72248e0c7
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
@@ -0,0 +1,1070 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import dagger.internal.codegen.writer.StringLiteral;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_ABSTRACT;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_MUST_RETURN_A_VALUE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_NOT_IN_MODULE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_PRIVATE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_SET_VALUES_RAW_SET;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_TYPE_PARAMETER;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_SAME_NAME;
+import static dagger.internal.codegen.ErrorMessages.MODULES_WITH_TYPE_PARAMS_MUST_BE_ABSTRACT;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_METHOD_RETURN_TYPE;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_METHOD_SET_VALUES_RETURN_SET;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS;
+
+@RunWith(JUnit4.class)
+public class ModuleFactoryGeneratorTest {
+
+ private final JavaFileObject NULLABLE = JavaFileObjects.forSourceLines("test.Nullable",
+ "package test;",
+ "public @interface Nullable {}");
+
+ private static final StringLiteral NPE_LITERAL =
+ StringLiteral.forValue(ErrorMessages.CANNOT_RETURN_NULL_FROM_NON_NULLABLE_PROVIDES_METHOD);
+
+ // TODO(gak): add tests for invalid combinations of scope and qualifier annotations like we have
+ // for @Inject
+
+ private String formatErrorMessage(String msg) {
+ return String.format(msg, "Provides");
+ }
+
+ private String formatModuleErrorMessage(String msg) {
+ return String.format(msg, "Provides", "Module");
+ }
+
+ @Test public void providesMethodNotInModule() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Provides;",
+ "",
+ "final class TestModule {",
+ " @Provides String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatModuleErrorMessage(BINDING_METHOD_NOT_IN_MODULE));
+ }
+
+ @Test public void providesMethodAbstract() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "abstract class TestModule {",
+ " @Provides abstract String provideString();",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_ABSTRACT));
+ }
+
+ @Test public void providesMethodPrivate() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides private String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_PRIVATE));
+ }
+
+ @Test public void providesMethodReturnVoid() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides void provideNothing() {}",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_MUST_RETURN_A_VALUE));
+ }
+
+ @Test public void providesMethodWithTypeParameter() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides <T> String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_TYPE_PARAMETER));
+ }
+
+ @Test public void providesMethodSetValuesWildcard() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET_VALUES;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides(type = SET_VALUES) Set<?> provideWildcard() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PROVIDES_METHOD_RETURN_TYPE);
+ }
+
+ @Test public void providesMethodSetValuesRawSet() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET_VALUES;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides(type = SET_VALUES) Set provideSomething() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_SET_VALUES_RAW_SET));
+ }
+
+ @Test public void providesMethodSetValuesNotASet() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET_VALUES;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "import java.util.List;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides(type = SET_VALUES) List<String> provideStrings() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PROVIDES_METHOD_SET_VALUES_RETURN_SET);
+ }
+
+ @Test public void modulesWithTypeParamsMustBeAbstract() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule<A> {}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MODULES_WITH_TYPE_PARAMS_MUST_BE_ABSTRACT);
+ }
+
+ @Test public void provideOverriddenByNoProvide() {
+ JavaFileObject parent = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class Parent {",
+ " @Provides String foo() { return null; }",
+ "}");
+ JavaFileObject child = JavaFileObjects.forSourceLines("test.Child",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "class Child extends Parent{",
+ " String foo() { return null; }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(parent, child))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(ErrorMessages.METHOD_OVERRIDES_PROVIDES_METHOD,
+ "Provides", "@Provides String test.Parent.foo()"));
+ }
+
+ @Test public void provideOverriddenByProvide() {
+ JavaFileObject parent = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class Parent {",
+ " @Provides String foo() { return null; }",
+ "}");
+ JavaFileObject child = JavaFileObjects.forSourceLines("test.Child",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class Child extends Parent{",
+ " @Provides String foo() { return null; }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(parent, child))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(ErrorMessages.PROVIDES_METHOD_OVERRIDES_ANOTHER,
+ "Provides", "@Provides String test.Parent.foo()"));
+ }
+
+ @Test public void providesOverridesNonProvides() {
+ JavaFileObject parent = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "class Parent {",
+ " String foo() { return null; }",
+ "}");
+ JavaFileObject child = JavaFileObjects.forSourceLines("test.Child",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class Child extends Parent{",
+ " @Provides String foo() { return null; }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(parent, child))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(ErrorMessages.PROVIDES_METHOD_OVERRIDES_ANOTHER,
+ "Provides", "String test.Parent.foo()"));
+ }
+
+ @Test public void validatesIncludedModules() {
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = Void.class)",
+ "class TestModule {}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(module))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(
+ ErrorMessages.REFERENCED_MODULE_NOT_ANNOTATED, "java.lang.Void", "@Module"));
+ }
+
+ @Test public void referencedModulesMustNotBeAbstract() {
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = AbstractModule.class)",
+ "class TestModule {}");
+ JavaFileObject abstractModule = JavaFileObjects.forSourceLines("test.AbstractModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "abstract class AbstractModule {}");
+ assertAbout(javaSources()).that(ImmutableList.of(module, abstractModule))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(ErrorMessages.REFERENCED_MODULES_MUST_NOT_BE_ABSTRACT,
+ "test.AbstractModule"));
+ }
+
+ @Test public void singleProvidesMethodNoArgs() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines("TestModule_ProvideStringFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProvideStringFactory implements Factory<String> {",
+ " private final TestModule module;",
+ "",
+ " public TestModule_ProvideStringFactory(TestModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override public String get() {",
+ " String provided = module.provideString();",
+ " if (provided == null) {",
+ " throw new NullPointerException(" + NPE_LITERAL + ");",
+ " }",
+ " return provided;",
+ " }",
+ "",
+ " public static Factory<String> create(TestModule module) {",
+ " return new TestModule_ProvideStringFactory(module);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(factoryFile);
+ }
+
+ @Test public void singleProvidesMethodNoArgs_disableNullable() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines("TestModule_ProvideStringFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProvideStringFactory implements Factory<String> {",
+ " private final TestModule module;",
+ "",
+ " public TestModule_ProvideStringFactory(TestModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override public String get() {",
+ " return module.provideString();",
+ " }",
+ "",
+ " public static Factory<String> create(TestModule module) {",
+ " return new TestModule_ProvideStringFactory(module);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .withCompilerOptions("-Adagger.nullableValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(factoryFile);
+ }
+
+ @Test public void nullableProvides() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides @Nullable String provideString() { return null; }",
+ "}");
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines("TestModule_ProvideStringFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProvideStringFactory implements Factory<String> {",
+ " private final TestModule module;",
+ "",
+ " public TestModule_ProvideStringFactory(TestModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override",
+ " @Nullable",
+ " public String get() {",
+ " return module.provideString();",
+ " }",
+ "",
+ " public static Factory<String> create(TestModule module) {",
+ " return new TestModule_ProvideStringFactory(module);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(moduleFile, NULLABLE))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(factoryFile);
+ }
+
+ private static final JavaFileObject QUALIFIER_A =
+ JavaFileObjects.forSourceLines("test.QualifierA",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier @interface QualifierA {}");
+ private static final JavaFileObject QUALIFIER_B =
+ JavaFileObjects.forSourceLines("test.QualifierB",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier @interface QualifierB {}");
+
+ @Test public void multipleProvidesMethods() {
+ JavaFileObject classXFile = JavaFileObjects.forSourceLines("test.X",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class X {",
+ " @Inject public String s;",
+ "}");
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "import java.util.Arrays;",
+ "import java.util.List;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides List<Object> provideObjects(",
+ " @QualifierA Object a, @QualifierB Object b, MembersInjector<X> x) {",
+ " return Arrays.asList(a, b);",
+ " }",
+ "",
+ " @Provides @QualifierA Object provideAObject() {",
+ " return new Object();",
+ " }",
+ "",
+ " @Provides @QualifierB Object provideBObject() {",
+ " return new Object();",
+ " }",
+ "}");
+ JavaFileObject listFactoryFile = JavaFileObjects.forSourceLines(
+ "TestModule_ProvideObjectsFactory",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.Factory;",
+ "import java.util.List;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProvideObjectsFactory implements Factory<List<Object>> {",
+ " private final TestModule module;",
+ " private final Provider<Object> aProvider;",
+ " private final Provider<Object> bProvider;",
+ " private final MembersInjector<X> xMembersInjector;",
+ "",
+ " public TestModule_ProvideObjectsFactory(",
+ " TestModule module,",
+ " Provider<Object> aProvider,",
+ " Provider<Object> bProvider,",
+ " MembersInjector<X> xMembersInjector) {",
+ " assert module != null;",
+ " this.module = module;",
+ " assert aProvider != null;",
+ " this.aProvider = aProvider;",
+ " assert bProvider != null;",
+ " this.bProvider = bProvider;",
+ " assert xMembersInjector != null;",
+ " this.xMembersInjector = xMembersInjector;",
+ " }",
+ "",
+ " @Override public List<Object> get() {",
+ " List<Object> provided =",
+ " module.provideObjects(aProvider.get(), bProvider.get(), xMembersInjector);",
+ " if (provided == null) {",
+ " throw new NullPointerException(" + NPE_LITERAL + ");",
+ " }",
+ " return provided;",
+ " }",
+ "",
+ " public static Factory<List<Object>> create(",
+ " TestModule module,",
+ " Provider<Object> aProvider,",
+ " Provider<Object> bProvider,",
+ " MembersInjector<X> xMembersInjector) {",
+ " return new TestModule_ProvideObjectsFactory(",
+ " module, aProvider, bProvider, xMembersInjector);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(
+ ImmutableList.of(classXFile, moduleFile, QUALIFIER_A, QUALIFIER_B))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(listFactoryFile);
+ }
+
+ @Test public void providesSetElement() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET;",
+ "",
+ "import java.util.logging.Logger;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides(type = SET) String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines("TestModule_ProvideStringFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import java.util.Collections;",
+ "import java.util.Set;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProvideStringFactory implements Factory<Set<String>> {",
+ " private final TestModule module;",
+ "",
+ " public TestModule_ProvideStringFactory(TestModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override public Set<String> get() {",
+ " return Collections.<String>singleton(module.provideString());",
+ " }",
+ "",
+ " public static Factory<Set<String>> create(TestModule module) {",
+ " return new TestModule_ProvideStringFactory(module);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(factoryFile);
+ }
+
+ @Test public void providesSetElementWildcard() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET;",
+ "",
+ "import java.util.logging.Logger;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.ArrayList;",
+ "import java.util.List;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides(type = SET) List<List<?>> provideWildcardList() {",
+ " return new ArrayList<>();",
+ " }",
+ "}");
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines(
+ "TestModule_ProvideWildcardListFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import java.util.Collections;",
+ "import java.util.List;",
+ "import java.util.Set;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProvideWildcardListFactory implements "
+ + "Factory<Set<List<List<?>>>> {",
+ " private final TestModule module;",
+ "",
+ " public TestModule_ProvideWildcardListFactory(TestModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override public Set<List<List<?>>> get() {",
+ " return Collections.<List<List<?>>>singleton(module.provideWildcardList());",
+ " }",
+ "",
+ " public static Factory<Set<List<List<?>>>> create(TestModule module) {",
+ " return new TestModule_ProvideWildcardListFactory(module);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(factoryFile);
+ }
+
+ @Test public void providesSetValues() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET_VALUES;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides(type = SET_VALUES) Set<String> provideStrings() {",
+ " return null;",
+ " }",
+ "}");
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines("TestModule_ProvideStringsFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import java.util.Set;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProvideStringsFactory implements Factory<Set<String>> {",
+ " private final TestModule module;",
+ "",
+ " public TestModule_ProvideStringsFactory(TestModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override public Set<String> get() {",
+ " Set<String> provided = module.provideStrings();",
+ " if (provided == null) {",
+ " throw new NullPointerException(" + NPE_LITERAL + ");",
+ " }",
+ " return provided;",
+ " }",
+ "",
+ " public static Factory<Set<String>> create(TestModule module) {",
+ " return new TestModule_ProvideStringsFactory(module);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(factoryFile);
+ }
+
+ @Test public void multipleProvidesMethodsWithSameName() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides Object provide(int i) {",
+ " return i;",
+ " }",
+ "",
+ " @Provides String provide() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_WITH_SAME_NAME)).in(moduleFile).onLine(8)
+ .and().withErrorContaining(formatErrorMessage(BINDING_METHOD_WITH_SAME_NAME))
+ .in(moduleFile).onLine(12);
+ }
+
+ @Test
+ public void providedTypes() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.io.Closeable;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides String string() {",
+ " return null;",
+ " }",
+ "",
+ " @Provides Set<String> strings() {",
+ " return null;",
+ " }",
+ "",
+ " @Provides Set<? extends Closeable> closeables() {",
+ " return null;",
+ " }",
+ "",
+ " @Provides String[] stringArray() {",
+ " return null;",
+ " }",
+ "",
+ " @Provides int integer() {",
+ " return 0;",
+ " }",
+ "",
+ " @Provides int[] integers() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @Test
+ public void privateModule() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.Enclosing",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "final class Enclosing {",
+ " @Module private static final class PrivateModule {",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("Modules cannot be private.")
+ .in(moduleFile).onLine(6);
+ }
+
+ @Test
+ public void enclosedInPrivateModule() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.Enclosing",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "final class Enclosing {",
+ " private static final class PrivateEnclosing {",
+ " @Module static final class TestModule {",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("Modules cannot be enclosed in private types.")
+ .in(moduleFile).onLine(7);
+ }
+
+ @Test
+ public void publicModuleNonPublicIncludes() {
+ JavaFileObject publicModuleFile = JavaFileObjects.forSourceLines("test.PublicModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = {",
+ " NonPublicModule1.class, OtherPublicModule.class, NonPublicModule2.class",
+ "})",
+ "public final class PublicModule {",
+ "}");
+ JavaFileObject nonPublicModule1File = JavaFileObjects.forSourceLines("test.NonPublicModule1",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class NonPublicModule1 {",
+ "}");
+ JavaFileObject nonPublicModule2File = JavaFileObjects.forSourceLines("test.NonPublicModule2",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class NonPublicModule2 {",
+ "}");
+ JavaFileObject otherPublicModuleFile = JavaFileObjects.forSourceLines("test.OtherPublicModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "public final class OtherPublicModule {",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(
+ publicModuleFile, nonPublicModule1File, nonPublicModule2File, otherPublicModuleFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("This module is public, but it includes non-public "
+ + "(or effectively non-public) modules. "
+ + "Either reduce the visibility of this module or make "
+ + "test.NonPublicModule1 and test.NonPublicModule2 public.")
+ .in(publicModuleFile).onLine(8);
+ }
+
+ @Test
+ public void genericSubclassedModule() {
+ JavaFileObject parent = JavaFileObjects.forSourceLines("test.ParentModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.List;",
+ "import java.util.ArrayList;",
+ "",
+ "@Module",
+ "abstract class ParentModule<A extends CharSequence,",
+ " B,",
+ " C extends Number & Comparable<C>> {",
+ " @Provides List<B> provideListB(B b) {",
+ " List<B> list = new ArrayList<B>();",
+ " list.add(b);",
+ " return list;",
+ " }",
+ "}");
+ JavaFileObject numberChild = JavaFileObjects.forSourceLines("test.ChildNumberModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class ChildNumberModule extends ParentModule<String, Number, Double> {",
+ " @Provides Number provideNumber() { return 1; }",
+ "}");
+ JavaFileObject integerChild = JavaFileObjects.forSourceLines("test.ChildIntegerModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class ChildIntegerModule extends ParentModule<StringBuilder, Integer, Float> {",
+ " @Provides Integer provideInteger() { return 2; }",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.C",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.List;",
+ "",
+ "@Component(modules={ChildNumberModule.class, ChildIntegerModule.class})",
+ "interface C {",
+ " List<Number> numberList();",
+ " List<Integer> integerList();",
+ "}");
+ JavaFileObject listBFactory = JavaFileObjects.forSourceLines(
+ "test.ParentModule_ProvidesListBFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import java.util.List;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class ParentModule_ProvideListBFactory<A extends CharSequence,",
+ " B, C extends Number & Comparable<C>> implements Factory<List<B>> {",
+ " private final ParentModule<A, B, C> module;",
+ " private final Provider<B> bProvider;",
+ "",
+ " public ParentModule_ProvideListBFactory(",
+ " ParentModule<A, B, C> module, Provider<B> bProvider) {",
+ " assert module != null;",
+ " this.module = module;",
+ " assert bProvider != null;",
+ " this.bProvider = bProvider;",
+ " }",
+ "",
+ " @Override",
+ " public List<B> get() { ",
+ " List<B> provided = module.provideListB(bProvider.get());",
+ " if (provided == null) {",
+ " throw new NullPointerException(" + NPE_LITERAL + ");",
+ " }",
+ " return provided;",
+ " }",
+ "",
+ " public static <A extends CharSequence, B, C extends Number & Comparable<C>>",
+ " Factory<List<B>> create(ParentModule<A, B, C> module, Provider<B> bProvider) {",
+ " return new ParentModule_ProvideListBFactory<A, B, C>(module, bProvider);",
+ " }",
+ "}");
+ JavaFileObject numberFactory = JavaFileObjects.forSourceLines(
+ "test.ChildNumberModule_ProvideNumberFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class ChildNumberModule_ProvideNumberFactory implements Factory<Number> {",
+ " private final ChildNumberModule module;",
+ "",
+ " public ChildNumberModule_ProvideNumberFactory(ChildNumberModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override",
+ " public Number get() { ",
+ " Number provided = module.provideNumber();",
+ " if (provided == null) {",
+ " throw new NullPointerException(" + NPE_LITERAL + ");",
+ " }",
+ " return provided;",
+ " }",
+ "",
+ " public static Factory<Number> create(ChildNumberModule module) {",
+ " return new ChildNumberModule_ProvideNumberFactory(module);",
+ " }",
+ "}");
+ JavaFileObject integerFactory = JavaFileObjects.forSourceLines(
+ "test.ChildIntegerModule_ProvideIntegerFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class ChildIntegerModule_ProvideIntegerFactory",
+ " implements Factory<Integer> {",
+ " private final ChildIntegerModule module;",
+ "",
+ " public ChildIntegerModule_ProvideIntegerFactory(ChildIntegerModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override",
+ " public Integer get() { ",
+ " Integer provided = module.provideInteger();",
+ " if (provided == null) {",
+ " throw new NullPointerException(" + NPE_LITERAL + ");",
+ " }",
+ " return provided;",
+ " }",
+ "",
+ " public static Factory<Integer> create(ChildIntegerModule module) {",
+ " return new ChildIntegerModule_ProvideIntegerFactory(module);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(parent, numberChild, integerChild, component))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(listBFactory, numberFactory, integerFactory);
+ }
+
+ @Test public void providesMethodMultipleQualifiers() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "import javax.annotation.Nullable;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides @QualifierA @QualifierB String provideString() {",
+ " return \"foo\";",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(moduleFile, QUALIFIER_A, QUALIFIER_B))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/MultipleRequestTest.java b/compiler/src/test/java/dagger/internal/codegen/MultipleRequestTest.java
new file mode 100644
index 000000000..27e720d01
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/MultipleRequestTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assert_;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+@RunWith(JUnit4.class)
+public class MultipleRequestTest {
+ private static final JavaFileObject DEP_FILE = JavaFileObjects.forSourceLines("test.Dep",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Dep {",
+ " @Inject Dep() {}",
+ "}");
+
+ @Test public void multipleRequests_constructor() {
+ assert_().about(javaSources())
+ .that(ImmutableList.of(
+ DEP_FILE,
+ JavaFileObjects.forSourceLines("test.ConstructorInjectsMultiple",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class ConstructorInjectsMultiple {",
+ " @Inject ConstructorInjectsMultiple(Dep d1, Dep d2) {}",
+ "}"),
+ JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " ConstructorInjectsMultiple get();",
+ "}")))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @Test public void multipleRequests_field() {
+ assert_().about(javaSources())
+ .that(ImmutableList.of(
+ DEP_FILE,
+ JavaFileObjects.forSourceLines("test.FieldInjectsMultiple",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class FieldInjectsMultiple {",
+ " @Inject Dep d1;",
+ " @Inject Dep d2;",
+ " @Inject FieldInjectsMultiple() {}",
+ "}"),
+ JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " FieldInjectsMultiple get();",
+ "}")))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @Test public void multipleRequests_providesMethod() {
+ assert_().about(javaSources())
+ .that(ImmutableList.of(
+ DEP_FILE,
+ JavaFileObjects.forSourceLines("test.FieldInjectsMultiple",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class SimpleModule {",
+ " @Provides Object provide(Dep d1, Dep d2) {",
+ " return null;",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = SimpleModule.class)",
+ "interface SimpleComponent {",
+ " Object get();",
+ "}")))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/PackageProxyTest.java b/compiler/src/test/java/dagger/internal/codegen/PackageProxyTest.java
new file mode 100644
index 000000000..8df80d19b
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/PackageProxyTest.java
@@ -0,0 +1,242 @@
+package dagger.internal.codegen;
+
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assert_;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+@RunWith(JUnit4.class)
+public class PackageProxyTest {
+ @Test public void basicPackageProxy() {
+ JavaFileObject noDepClassFile = JavaFileObjects.forSourceLines("foreign.NoDepClass",
+ "package foreign;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public final class NoDepClass {",
+ " @Inject NoDepClass() {}",
+ "}");
+ JavaFileObject publicClassFile = JavaFileObjects.forSourceLines("foreign.PublicClass",
+ "package foreign;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public final class PublicClass {",
+ " @Inject PublicClass(NonPublicClass1 dep1, NonPublicClass2 dep2, NoDepClass dep3) {}",
+ "}");
+ JavaFileObject nonPublicClass1File = JavaFileObjects.forSourceLines("foreign.NonPublicClass1",
+ "package foreign;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class NonPublicClass1 {",
+ " @Inject NonPublicClass1(NoDepClass dep) {}",
+ "}");
+ JavaFileObject nonPublicClass2File = JavaFileObjects.forSourceLines("foreign.NonPublicClass2",
+ "package foreign;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class NonPublicClass2 {",
+ " @Inject NonPublicClass2(NoDepClass dep) {}",
+ "}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import foreign.PublicClass;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " PublicClass publicClass();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import foreign.DaggerTestComponent_PackageProxy;",
+ "import foreign.NoDepClass_Factory;",
+ "import foreign.NonPublicClass1_Factory;",
+ "import foreign.NonPublicClass2_Factory;",
+ "import foreign.PublicClass;",
+ "import foreign.PublicClass_Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private final DaggerTestComponent_PackageProxy foreign_Proxy =",
+ " new DaggerTestComponent_PackageProxy();",
+ " private Provider<PublicClass> publicClassProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.foreign_Proxy.nonPublicClass1Provider =",
+ " NonPublicClass1_Factory.create(NoDepClass_Factory.create());",
+ " this.foreign_Proxy.nonPublicClass2Provider =",
+ " NonPublicClass2_Factory.create(NoDepClass_Factory.create());",
+ " this.publicClassProvider = PublicClass_Factory.create(",
+ " foreign_Proxy.nonPublicClass1Provider,",
+ " foreign_Proxy.nonPublicClass2Provider,",
+ " NoDepClass_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public PublicClass publicClass() {",
+ " return publicClassProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " return new DaggerTestComponent(this);",
+ " }",
+ " }",
+ "}");
+ assert_().about(javaSources())
+ .that(ImmutableList.of(
+ noDepClassFile,
+ publicClassFile,
+ nonPublicClass1File,
+ nonPublicClass2File,
+ componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void memberInjectionPackageProxy() {
+ JavaFileObject noDepClassFile = JavaFileObjects.forSourceLines("test.NoDepClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public final class NoDepClass {",
+ " @Inject NoDepClass() {}",
+ "}");
+ JavaFileObject aClassFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import foreign.B;",
+ "import javax.inject.Inject;",
+ "",
+ "final class A extends B {",
+ " @Inject NoDepClass dep;",
+ "}");
+ JavaFileObject bClassFile = JavaFileObjects.forSourceLines("foreign.B",
+ "package foreign;",
+ "",
+ "import test.NoDepClass;",
+ "import javax.inject.Inject;",
+ "",
+ "public class B extends C {",
+ " @Inject NoDepClass dep;",
+ "}");
+ JavaFileObject cClassFile = JavaFileObjects.forSourceLines("foreign.C",
+ "package foreign;",
+ "",
+ "import test.D;",
+ "import test.NoDepClass;",
+ "import javax.inject.Inject;",
+ "",
+ "class C extends D {",
+ " @Inject NoDepClass dep;",
+ "}");
+ JavaFileObject dClassFile = JavaFileObjects.forSourceLines("test.D",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public class D {",
+ " @Inject NoDepClass dep;",
+ "}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " void injectA(A a);",
+ "}");
+ JavaFileObject generatedComponent =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private MembersInjector<A> aMembersInjector;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.aMembersInjector = A_MembersInjector.create(NoDepClass_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public void injectA(A a) {",
+ " aMembersInjector.injectMembers(a);",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " return new DaggerTestComponent(this);",
+ " }",
+ " }",
+ "}");
+ assert_().about(javaSources())
+ .that(ImmutableList.of(
+ noDepClassFile,
+ aClassFile,
+ bClassFile,
+ cClassFile,
+ dClassFile,
+ componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ProducerModuleFactoryGeneratorTest.java b/compiler/src/test/java/dagger/internal/codegen/ProducerModuleFactoryGeneratorTest.java
new file mode 100644
index 000000000..0041f5d89
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ProducerModuleFactoryGeneratorTest.java
@@ -0,0 +1,564 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// TODO(beder): Merge the error-handling tests with the ModuleFactoryGeneratorTest.
+package dagger.internal.codegen;
+
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_ABSTRACT;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_MUST_RETURN_A_VALUE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_NOT_IN_MODULE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_PRIVATE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_SET_VALUES_RAW_SET;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_TYPE_PARAMETER;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_SAME_NAME;
+import static dagger.internal.codegen.ErrorMessages.PRODUCES_METHOD_RAW_FUTURE;
+import static dagger.internal.codegen.ErrorMessages.PRODUCES_METHOD_RETURN_TYPE;
+import static dagger.internal.codegen.ErrorMessages.PRODUCES_METHOD_SET_VALUES_RETURN_SET;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS;
+
+@RunWith(JUnit4.class)
+public class ProducerModuleFactoryGeneratorTest {
+ private String formatErrorMessage(String msg) {
+ return String.format(msg, "Produces");
+ }
+
+ private String formatModuleErrorMessage(String msg) {
+ return String.format(msg, "Produces", "ProducerModule");
+ }
+
+ @Test public void producesMethodNotInModule() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.producers.Produces;",
+ "",
+ "final class TestModule {",
+ " @Produces String produceString() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatModuleErrorMessage(BINDING_METHOD_NOT_IN_MODULE));
+ }
+
+ @Test public void producesMethodAbstract() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "abstract class TestModule {",
+ " @Produces abstract String produceString();",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_ABSTRACT));
+ }
+
+ @Test public void producesMethodPrivate() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces private String produceString() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_PRIVATE));
+ }
+
+ @Test public void producesMethodReturnVoid() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces void produceNothing() {}",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_MUST_RETURN_A_VALUE));
+ }
+
+ @Test public void producesMethodReturnRawFuture() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces ListenableFuture produceRaw() {}",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRODUCES_METHOD_RAW_FUTURE);
+ }
+
+ @Test public void producesMethodReturnWildcardFuture() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces ListenableFuture<?> produceRaw() {}",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRODUCES_METHOD_RETURN_TYPE);
+ }
+
+ @Test public void producesMethodWithTypeParameter() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces <T> String produceString() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_TYPE_PARAMETER));
+ }
+
+ @Test public void producesMethodSetValuesWildcard() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.producers.Produces.Type.SET_VALUES;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "import java.util.Set;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces(type = SET_VALUES) Set<?> produceWildcard() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRODUCES_METHOD_RETURN_TYPE);
+ }
+
+ @Test public void producesMethodSetValuesRawSet() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.producers.Produces.Type.SET_VALUES;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "import java.util.Set;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces(type = SET_VALUES) Set produceSomething() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_SET_VALUES_RAW_SET));
+ }
+
+ @Test public void producesMethodSetValuesNotASet() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.producers.Produces.Type.SET_VALUES;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "import java.util.List;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces(type = SET_VALUES) List<String> produceStrings() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRODUCES_METHOD_SET_VALUES_RETURN_SET);
+ }
+
+ @Test public void producesMethodSetValuesWildcardInFuture() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.producers.Produces.Type.SET_VALUES;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "import java.util.Set;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces(type = SET_VALUES) ListenableFuture<Set<?>> produceWildcard() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRODUCES_METHOD_RETURN_TYPE);
+ }
+
+ @Test public void producesMethodSetValuesFutureRawSet() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.producers.Produces.Type.SET_VALUES;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "import java.util.Set;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces(type = SET_VALUES) ListenableFuture<Set> produceSomething() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_SET_VALUES_RAW_SET));
+ }
+
+ @Test public void producesMethodSetValuesFutureNotASet() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.producers.Produces.Type.SET_VALUES;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "import java.util.List;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces(type = SET_VALUES) ListenableFuture<List<String>> produceStrings() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRODUCES_METHOD_SET_VALUES_RETURN_SET);
+ }
+
+ @Test public void multipleProducesMethodsWithSameName() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces Object produce(int i) {",
+ " return i;",
+ " }",
+ "",
+ " @Produces String produce() {",
+ " return \"\";",
+ " }",
+ "}");
+ String errorMessage = String.format(BINDING_METHOD_WITH_SAME_NAME, "Produces");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage).in(moduleFile).onLine(8)
+ .and().withErrorContaining(errorMessage).in(moduleFile).onLine(12);
+ }
+
+ @Test
+ public void privateModule() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.Enclosing",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "",
+ "final class Enclosing {",
+ " @ProducerModule private static final class PrivateModule {",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("Modules cannot be private.")
+ .in(moduleFile).onLine(6);
+ }
+
+ @Test
+ public void enclosedInPrivateModule() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.Enclosing",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "",
+ "final class Enclosing {",
+ " private static final class PrivateEnclosing {",
+ " @ProducerModule static final class TestModule {",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("Modules cannot be enclosed in private types.")
+ .in(moduleFile).onLine(7);
+ }
+
+ @Test
+ public void includesNonModule() {
+ JavaFileObject xFile =
+ JavaFileObjects.forSourceLines("test.X", "package test;", "", "public final class X {}");
+ JavaFileObject moduleFile =
+ JavaFileObjects.forSourceLines(
+ "test.FooModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "",
+ "@ProducerModule(includes = X.class)",
+ "public final class FooModule {",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(xFile, moduleFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(
+ ErrorMessages.REFERENCED_MODULE_NOT_ANNOTATED,
+ "X",
+ "one of @Module, @ProducerModule"));
+ }
+
+ @Test
+ public void publicModuleNonPublicIncludes() {
+ JavaFileObject publicModuleFile = JavaFileObjects.forSourceLines("test.PublicModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "",
+ "@ProducerModule(includes = {",
+ " NonPublicModule1.class, OtherPublicModule.class, NonPublicModule2.class",
+ "})",
+ "public final class PublicModule {",
+ "}");
+ JavaFileObject nonPublicModule1File = JavaFileObjects.forSourceLines("test.NonPublicModule1",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "",
+ "@ProducerModule",
+ "final class NonPublicModule1 {",
+ "}");
+ JavaFileObject nonPublicModule2File = JavaFileObjects.forSourceLines("test.NonPublicModule2",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "",
+ "@ProducerModule",
+ "final class NonPublicModule2 {",
+ "}");
+ JavaFileObject otherPublicModuleFile = JavaFileObjects.forSourceLines("test.OtherPublicModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "",
+ "@ProducerModule",
+ "public final class OtherPublicModule {",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(
+ publicModuleFile, nonPublicModule1File, nonPublicModule2File, otherPublicModuleFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("This module is public, but it includes non-public "
+ + "(or effectively non-public) modules. "
+ + "Either reduce the visibility of this module or make "
+ + "test.NonPublicModule1 and test.NonPublicModule2 public.")
+ .in(publicModuleFile).onLine(8);
+ }
+
+ @Test public void singleProducesMethodNoArgsFuture() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces ListenableFuture<String> produceString() {",
+ " return null;",
+ " }",
+ "}");
+ JavaFileObject factoryFile =
+ JavaFileObjects.forSourceLines(
+ "TestModule_ProduceStringFactory",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.Futures;",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.internal.AbstractProducer;",
+ "import dagger.producers.internal.Producers;",
+ "import dagger.producers.monitoring.ProducerToken;",
+ "import dagger.producers.monitoring.ProductionComponentMonitor;",
+ "import java.util.concurrent.Callable;",
+ "import java.util.concurrent.Executor;",
+ "import javax.annotation.Generated;",
+ "import javax.annotation.Nullable;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProduceStringFactory extends AbstractProducer<String> {",
+ " private final TestModule module;",
+ " private final Executor executor;",
+ "",
+ " public TestModule_ProduceStringFactory(",
+ " @Nullable ProductionComponentMonitor componentMonitor,",
+ " TestModule module,",
+ " Executor executor) {",
+ " super(",
+ " Producers.producerMonitorFor(",
+ " componentMonitor,",
+ " ProducerToken.create(TestModule_ProduceStringFactory.class)));",
+ " assert module != null;",
+ " this.module = module;",
+ " assert executor != null;",
+ " this.executor = executor;",
+ " }",
+ "",
+ " @Override protected ListenableFuture<String> compute() {",
+ " ListenableFuture<ListenableFuture<String>> future = Producers.submitToExecutor(",
+ " new Callable<ListenableFuture<String>>() {",
+ " @Override public ListenableFuture<String> call() {",
+ " if (monitor != null) {",
+ " monitor.methodStarting();",
+ " }",
+ " try {",
+ " return module.produceString();",
+ " } finally {",
+ " if (monitor != null) {",
+ " monitor.methodFinished();",
+ " }",
+ " }",
+ " }",
+ " }, executor);",
+ " return Futures.dereference(future);",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(factoryFile);
+ }
+
+ private static final JavaFileObject QUALIFIER_A =
+ JavaFileObjects.forSourceLines("test.QualifierA",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier @interface QualifierA {}");
+ private static final JavaFileObject QUALIFIER_B =
+ JavaFileObjects.forSourceLines("test.QualifierB",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier @interface QualifierB {}");
+
+ @Test public void producesMethodMultipleQualifiers() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces @QualifierA @QualifierB abstract String produceString() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(moduleFile, QUALIFIER_A, QUALIFIER_B))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ProductionComponentProcessorTest.java b/compiler/src/test/java/dagger/internal/codegen/ProductionComponentProcessorTest.java
new file mode 100644
index 000000000..92bbb752c
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ProductionComponentProcessorTest.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+
+@RunWith(JUnit4.class)
+public class ProductionComponentProcessorTest {
+ @Test public void componentOnConcreteClass() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "@ProductionComponent",
+ "final class NotAComponent {}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("interface");
+ }
+
+ @Test public void componentOnEnum() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "@ProductionComponent",
+ "enum NotAComponent {",
+ " INSTANCE",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("interface");
+ }
+
+ @Test public void componentOnAnnotation() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "@ProductionComponent",
+ "@interface NotAComponent {}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("interface");
+ }
+
+ @Test public void nonModuleModule() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "@ProductionComponent(modules = Object.class)",
+ "interface NotAComponent {}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("is not annotated with @Module or @ProducerModule");
+ }
+
+ @Test public void simpleComponent() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "import dagger.producers.ProductionComponent;",
+ "import javax.inject.Inject;",
+ "",
+ "final class TestClass {",
+ " static final class C {",
+ " @Inject C() {}",
+ " }",
+ "",
+ " interface A {}",
+ " interface B {}",
+ "",
+ " @Module",
+ " static final class BModule {",
+ " @Provides B b(C c) {",
+ " return null;",
+ " }",
+ " }",
+ "",
+ " @ProducerModule",
+ " static final class AModule {",
+ " @Produces ListenableFuture<A> a(B b) {",
+ " return null;",
+ " }",
+ " }",
+ "",
+ " @ProductionComponent(modules = {AModule.class, BModule.class})",
+ " interface SimpleComponent {",
+ " ListenableFuture<A> a();",
+ " }",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestClass_SimpleComponent",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.Producer;",
+ "import dagger.producers.internal.Producers;",
+ "import java.util.concurrent.Executor;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import test.TestClass.A;",
+ "import test.TestClass.AModule;",
+ "import test.TestClass.B;",
+ "import test.TestClass.BModule;",
+ "import test.TestClass.SimpleComponent;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestClass_SimpleComponent implements SimpleComponent {",
+ " private Provider<B> bProvider;",
+ " private Producer<A> aProducer;",
+ "",
+ " private DaggerTestClass_SimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.bProvider = TestClass$BModule_BFactory.create(",
+ " builder.bModule, TestClass$C_Factory.create());",
+ " this.aProducer = new TestClass$AModule_AFactory(",
+ " null,",
+ " builder.aModule,",
+ " builder.executor,",
+ " Producers.producerFromProvider(bProvider));",
+ " }",
+ "",
+ " @Override",
+ " public ListenableFuture<A> a() {",
+ " return aProducer.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private BModule bModule;",
+ " private AModule aModule;",
+ " private Executor executor;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " if (bModule == null) {",
+ " this.bModule = new BModule();",
+ " }",
+ " if (aModule == null) {",
+ " this.aModule = new AModule();",
+ " }",
+ " if (executor == null) {",
+ " throw new IllegalStateException(Executor.class.getCanonicalName()",
+ " + \" must be set\");",
+ " }",
+ " return new DaggerTestClass_SimpleComponent(this);",
+ " }",
+ "",
+ " public Builder aModule(AModule aModule) {",
+ " if (aModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.aModule = aModule;",
+ " return this;",
+ " }",
+ "",
+ " public Builder bModule(BModule bModule) {",
+ " if (bModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.bModule = bModule;",
+ " return this;",
+ " }",
+ "",
+ " public Builder executor(Executor executor) {",
+ " if (executor == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.executor = executor;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ProductionGraphValidationTest.java b/compiler/src/test/java/dagger/internal/codegen/ProductionGraphValidationTest.java
new file mode 100644
index 000000000..9f577b722
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ProductionGraphValidationTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.testing.compile.JavaFileObjects;
+import java.util.Arrays;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+/**
+ * Unit tests for {@link BindingGraphValidator} that exercise producer-specific logic.
+ */
+@RunWith(JUnit4.class)
+public class ProductionGraphValidationTest {
+ @Test public void componentWithUnprovidedInput() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.MyComponent",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "@ProductionComponent(modules = FooModule.class)",
+ "interface MyComponent {",
+ " ListenableFuture<Foo> getFoo();",
+ "}");
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.FooModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "class Foo {}",
+ "class Bar {}",
+ "",
+ "@ProducerModule",
+ "class FooModule {",
+ " @Produces Foo foo(Bar bar) {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(Arrays.asList(module, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("test.Bar cannot be provided without an @Inject constructor or from "
+ + "an @Provides- or @Produces-annotated method.")
+ .in(component).onLine(8);
+ }
+
+ @Test public void componentProductionWithNoDependencyChain() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "final class TestClass {",
+ " interface A {}",
+ "",
+ " @ProductionComponent()",
+ " interface AComponent {",
+ " ListenableFuture<A> getA();",
+ " }",
+ "}");
+ String expectedError =
+ "test.TestClass.A cannot be provided without an @Provides- or @Produces-annotated method.";
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(11);
+ }
+
+ @Test public void provisionDependsOnProduction() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "final class TestClass {",
+ " interface A {}",
+ " interface B {}",
+ "",
+ " @Module",
+ " final class AModule {",
+ " @Provides A a(B b) {",
+ " return null;",
+ " }",
+ " }",
+ "",
+ " @ProducerModule",
+ " final class BModule {",
+ " @Produces ListenableFuture<B> b() {",
+ " return null;",
+ " }",
+ " }",
+ "",
+ " @ProductionComponent(modules = {AModule.class, BModule.class})",
+ " interface AComponent {",
+ " ListenableFuture<A> getA();",
+ " }",
+ "}");
+ String expectedError =
+ "test.TestClass.A is a provision, which cannot depend on a production.";
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(30);
+ }
+
+ @Test public void provisionEntryPointDependsOnProduction() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "final class TestClass {",
+ " interface A {}",
+ "",
+ " @ProducerModule",
+ " final class AModule {",
+ " @Produces ListenableFuture<A> a() {",
+ " return null;",
+ " }",
+ " }",
+ "",
+ " @ProductionComponent(modules = AModule.class)",
+ " interface AComponent {",
+ " A getA();",
+ " }",
+ "}");
+ String expectedError =
+ "test.TestClass.A is a provision entry-point, which cannot depend on a production.";
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(20);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/RepeatedModuleValidationTest.java b/compiler/src/test/java/dagger/internal/codegen/RepeatedModuleValidationTest.java
new file mode 100644
index 000000000..6bf0c9ee0
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/RepeatedModuleValidationTest.java
@@ -0,0 +1,121 @@
+package dagger.internal.codegen;
+
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+@RunWith(JUnit4.class)
+public class RepeatedModuleValidationTest {
+ private static final JavaFileObject MODULE_FILE =
+ JavaFileObjects.forSourceLines(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class TestModule {}");
+
+ @Test
+ public void moduleRepeatedInSubcomponentFactoryMethod() {
+ JavaFileObject subcomponentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestSubcomponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = TestModule.class)",
+ "interface TestSubcomponent {",
+ "}");
+ JavaFileObject componentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " TestSubcomponent newTestSubcomponent(TestModule module);",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(MODULE_FILE, subcomponentFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("This module is present in test.TestComponent.")
+ .in(componentFile)
+ .onLine(7)
+ .atColumn(51);
+ }
+
+ @Test
+ public void moduleRepeatedInSubcomponentBuilderMethod() {
+ JavaFileObject subcomponentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestSubcomponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = TestModule.class)",
+ "interface TestSubcomponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " Builder testModule(TestModule testModule);",
+ " TestSubcomponent build();",
+ " }",
+ "}");
+ JavaFileObject componentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " TestSubcomponent.Builder newTestSubcomponentBuilder();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(MODULE_FILE, subcomponentFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ // TODO(gak): assert about the warning when we have that ability
+ }
+
+ @Test
+ public void moduleRepeatedButNotPassed() {
+ JavaFileObject subcomponentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestSubcomponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = TestModule.class)",
+ "interface TestSubcomponent {",
+ "}");
+ JavaFileObject componentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " TestSubcomponent newTestSubcomponent();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(MODULE_FILE, subcomponentFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/SubcomponentBuilderValidationTest.java b/compiler/src/test/java/dagger/internal/codegen/SubcomponentBuilderValidationTest.java
new file mode 100644
index 000000000..6311a90ca
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/SubcomponentBuilderValidationTest.java
@@ -0,0 +1,742 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+/** Tests for {@link dagger.Subcomponent.Builder} validation. */
+@RunWith(JUnit4.class)
+public class SubcomponentBuilderValidationTest {
+
+ private static final ErrorMessages.SubcomponentBuilderMessages MSGS =
+ new ErrorMessages.SubcomponentBuilderMessages();
+
+ @Test
+ public void testRefSubcomponentAndSubBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent child();",
+ " ChildComponent.Builder builder();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {",
+ " @Subcomponent.Builder",
+ " static interface Builder {",
+ " ChildComponent build();",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(MSGS.moreThanOneRefToSubcomponent(),
+ "test.ChildComponent", "[child(), builder()]"))
+ .in(componentFile);
+ }
+
+ @Test
+ public void testRefSubBuilderTwiceFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent.Builder builder1();",
+ " ChildComponent.Builder builder2();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {",
+ " @Subcomponent.Builder",
+ " static interface Builder {",
+ " ChildComponent build();",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(MSGS.moreThanOneRefToSubcomponent(),
+ "test.ChildComponent", "[builder1(), builder2()]"))
+ .in(componentFile);
+ }
+
+ @Test
+ public void testMoreThanOneBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent.Builder1 build();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {",
+ " @Subcomponent.Builder",
+ " static interface Builder1 {",
+ " ChildComponent build();",
+ " }",
+ "",
+ " @Subcomponent.Builder",
+ " static interface Builder2 {",
+ " ChildComponent build();",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(MSGS.moreThanOne(),
+ "[test.ChildComponent.Builder1, test.ChildComponent.Builder2]"))
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testBuilderGenericsFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent.Builder1 build();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder<T> {",
+ " ChildComponent build();",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.generics())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testBuilderNotInComponentFails() {
+ JavaFileObject builder = JavaFileObjects.forSourceLines("test.Builder",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent.Builder",
+ "interface Builder {}");
+ assertAbout(javaSource()).that(builder)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeInComponent())
+ .in(builder);
+ }
+
+ @Test
+ public void testBuilderMissingBuildMethodFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent.Builder1 build();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.missingBuildMethod())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testPrivateBuilderFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " private interface Builder {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.isPrivate())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testNonStaticBuilderFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " abstract class Builder {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeStatic())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testNonAbstractBuilderFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " static class Builder {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeAbstract())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testBuilderOneCxtorWithArgsFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " static abstract class Builder {",
+ " Builder(String unused) {}",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.cxtorOnlyOneAndNoArgs())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testBuilderMoreThanOneCxtorFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " static abstract class Builder {",
+ " Builder() {}",
+ " Builder(String unused) {}",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.cxtorOnlyOneAndNoArgs())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testBuilderEnumFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " enum Builder {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeClassOrInterface())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testBuilderBuildReturnsWrongTypeFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " String build();",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.buildMustReturnComponentType())
+ .in(childComponentFile).onLine(9);
+ }
+
+ @Test
+ public void testInheritedBuilderBuildReturnsWrongTypeFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " interface Parent {",
+ " String build();",
+ " }",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedBuildMustReturnComponentType(), "build"))
+ .in(childComponentFile).onLine(12);
+ }
+
+ @Test
+ public void testTwoBuildMethodsFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " ChildComponent build();",
+ " ChildComponent create();",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(MSGS.twoBuildMethods(), "build()"))
+ .in(childComponentFile).onLine(10);
+ }
+
+ @Test
+ public void testInheritedTwoBuildMethodsFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " interface Parent {",
+ " ChildComponent build();",
+ " ChildComponent create();",
+ " }",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedTwoBuildMethods(), "create()", "build()"))
+ .in(childComponentFile).onLine(13);
+ }
+
+ @Test
+ public void testMoreThanOneArgFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " ChildComponent build();",
+ " Builder set(String s, Integer i);",
+ " Builder set(Number n, Double d);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.methodsMustTakeOneArg())
+ .in(childComponentFile).onLine(10)
+ .and().withErrorContaining(MSGS.methodsMustTakeOneArg())
+ .in(childComponentFile).onLine(11);
+ }
+
+ @Test
+ public void testInheritedMoreThanOneArgFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " interface Parent {",
+ " ChildComponent build();",
+ " Builder set1(String s, Integer i);",
+ " }",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedMethodsMustTakeOneArg(),
+ "set1(java.lang.String,java.lang.Integer)"))
+ .in(childComponentFile).onLine(13);
+ }
+
+ @Test
+ public void testSetterReturningNonVoidOrBuilderFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " ChildComponent build();",
+ " String set(Integer i);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.methodsMustReturnVoidOrBuilder())
+ .in(childComponentFile).onLine(10);
+ }
+
+ @Test
+ public void testInheritedSetterReturningNonVoidOrBuilderFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " interface Parent {",
+ " ChildComponent build();",
+ " String set(Integer i);",
+ " }",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedMethodsMustReturnVoidOrBuilder(),
+ "set(java.lang.Integer)"))
+ .in(childComponentFile).onLine(13);
+ }
+
+ @Test
+ public void testGenericsOnSetterMethodFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " ChildComponent build();",
+ " <T> Builder set(T t);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.methodsMayNotHaveTypeParameters())
+ .in(childComponentFile).onLine(10);
+ }
+
+ @Test
+ public void testGenericsOnInheritedSetterMethodFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " interface Parent {",
+ " ChildComponent build();",
+ " <T> Builder set(T t);",
+ " }",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedMethodsMayNotHaveTypeParameters(), "<T>set(T)"))
+ .in(childComponentFile).onLine(13);
+ }
+
+ @Test
+ public void testMultipleSettersPerTypeFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " ChildComponent build();",
+ " void set1(String s);",
+ " void set2(String s);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.manyMethodsForType(),
+ "java.lang.String", "[set1(java.lang.String), set2(java.lang.String)]"))
+ .in(childComponentFile).onLine(8);
+ }
+
+ @Test
+ public void testMultipleSettersPerTypeIncludingResolvedGenericsFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " interface Parent<T> {",
+ " void set1(T t);",
+ " }",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder extends Parent<String> {",
+ " ChildComponent build();",
+ " void set2(String s);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.manyMethodsForType(),
+ "java.lang.String", "[set1(T), set2(java.lang.String)]"))
+ .in(childComponentFile).onLine(12);
+ }
+
+ @Test
+ public void testExtraSettersFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent.Builder build();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " ChildComponent build();",
+ " void set1(String s);",
+ " void set2(Integer s);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.extraSetters(),
+ "[void test.ChildComponent.Builder.set1(String),"
+ + " void test.ChildComponent.Builder.set2(Integer)]"))
+ .in(childComponentFile).onLine(8);
+
+ }
+
+ @Test
+ public void testMissingSettersFail() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " TestModule(String unused) {}",
+ " @Provides String s() { return null; }",
+ "}");
+ JavaFileObject module2File = JavaFileObjects.forSourceLines("test.Test2Module",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class Test2Module {",
+ " @Provides Integer i() { return null; }",
+ "}");
+ JavaFileObject module3File = JavaFileObjects.forSourceLines("test.Test3Module",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class Test3Module {",
+ " Test3Module(String unused) {}",
+ " @Provides Double d() { return null; }",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent.Builder build();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = {TestModule.class, Test2Module.class, Test3Module.class})",
+ "interface ChildComponent {",
+ " String string();",
+ " Integer integer();",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " ChildComponent create();",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(moduleFile,
+ module2File,
+ module3File,
+ componentFile,
+ childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ // Ignores Test2Module because we can construct it ourselves.
+ // TODO(sameb): Ignore Test3Module because it's not used within transitive dependencies.
+ String.format(MSGS.missingSetters(), "[test.TestModule, test.Test3Module]"))
+ .in(childComponentFile).onLine(11);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/SubcomponentValidationTest.java b/compiler/src/test/java/dagger/internal/codegen/SubcomponentValidationTest.java
new file mode 100644
index 000000000..05ef5f37a
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/SubcomponentValidationTest.java
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+@RunWith(JUnit4.class)
+public final class SubcomponentValidationTest {
+ @Test public void factoryMethod_missingModulesWithParameters() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " ChildComponent newChildComponent();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = ModuleWithParameters.class)",
+ "interface ChildComponent {}");
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.ModuleWithParameters",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class ModuleWithParameters {",
+ " ModuleWithParameters(Object whatever) {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile, moduleFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ "test.ChildComponent requires modules which have no visible default constructors. "
+ + "Add the following modules as parameters to this method: "
+ + "test.ModuleWithParameters")
+ .in(componentFile).onLine(7);
+ }
+
+ @Test public void factoryMethod_nonModuleParameter() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " ChildComponent newChildComponent(String someRandomString);",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ "Subcomponent factory methods may only accept modules, but java.lang.String is not.")
+ .in(componentFile).onLine(7).atColumn(43);
+ }
+
+ @Test public void factoryMethod_duplicateParameter() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class TestModule {}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " ChildComponent newChildComponent(TestModule testModule1, TestModule testModule2);",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = TestModule.class)",
+ "interface ChildComponent {}");
+ assertAbout(javaSources()).that(ImmutableList.of(moduleFile, componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ "A module may only occur once an an argument in a Subcomponent factory method, "
+ + "but test.TestModule was already passed.")
+ .in(componentFile).onLine(7).atColumn(71);
+ }
+
+ @Test public void factoryMethod_superflouousModule() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class TestModule {}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " ChildComponent newChildComponent(TestModule testModule);",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {}");
+ assertAbout(javaSources()).that(ImmutableList.of(moduleFile, componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ "test.TestModule is present as an argument to the test.ChildComponent factory method, but "
+ + "is not one of the modules used to implement the subcomponent.")
+ .in(componentFile).onLine(7);
+ }
+
+ @Test public void missingBinding() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides String provideString(int i) {",
+ " return Integer.toString(i);",
+ " }",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " ChildComponent newChildComponent();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = TestModule.class)",
+ "interface ChildComponent {",
+ " String getString();",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(moduleFile, componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ "java.lang.Integer cannot be provided without an @Inject constructor or from an "
+ + "@Provides-annotated method");
+ }
+
+ @Test public void subcomponentOnConcreteType() {
+ JavaFileObject subcomponentFile = JavaFileObjects.forSourceLines("test.NotASubcomponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "final class NotASubcomponent {}");
+ assertAbout(javaSources()).that(ImmutableList.of(subcomponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("interface");
+ }
+
+ @Test public void scopeMismatch() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Component",
+ "@Singleton",
+ "interface ParentComponent {",
+ " ChildComponent childComponent();",
+ "}");
+ JavaFileObject subcomponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = ChildModule.class)",
+ "interface ChildComponent {",
+ " Object getObject();",
+ "}");
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.ChildModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Module",
+ "final class ChildModule {",
+ " @Provides @Singleton Object provideObject() { return null; }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, subcomponentFile, moduleFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("@Singleton");
+ }
+
+ @Test
+ public void delegateFactoryNotCreatedForSubcomponentWhenProviderExistsInParent() {
+ JavaFileObject parentComponentFile =
+ JavaFileObjects.forSourceLines(
+ "test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent childComponent();",
+ " Dep1 getDep1();",
+ " Dep2 getDep2();",
+ "}");
+ JavaFileObject childComponentFile =
+ JavaFileObjects.forSourceLines(
+ "test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = ChildModule.class)",
+ "interface ChildComponent {",
+ " Object getObject();",
+ "}");
+ JavaFileObject childModuleFile =
+ JavaFileObjects.forSourceLines(
+ "test.ChildModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class ChildModule {",
+ " @Provides Object provideObject(A a) { return null; }",
+ "}");
+ JavaFileObject aFile =
+ JavaFileObjects.forSourceLines(
+ "test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject public A(NeedsDep1 a, Dep1 b, Dep2 c) { }",
+ " @Inject public void methodA() { }",
+ "}");
+ JavaFileObject needsDep1File =
+ JavaFileObjects.forSourceLines(
+ "test.NeedsDep1",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class NeedsDep1 {",
+ " @Inject public NeedsDep1(Dep1 d) { }",
+ "}");
+ JavaFileObject dep1File =
+ JavaFileObjects.forSourceLines(
+ "test.Dep1",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class Dep1 {",
+ " @Inject public Dep1() { }",
+ " @Inject public void dep1Method() { }",
+ "}");
+ JavaFileObject dep2File =
+ JavaFileObjects.forSourceLines(
+ "test.Dep2",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class Dep2 {",
+ " @Inject public Dep2() { }",
+ " @Inject public void dep2Method() { }",
+ "}");
+
+ JavaFileObject componentGeneratedFile =
+ JavaFileObjects.forSourceLines(
+ "DaggerParentComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerParentComponent implements ParentComponent {",
+ " private MembersInjector<Dep1> dep1MembersInjector;",
+ " private Provider<Dep1> dep1Provider;",
+ " private MembersInjector<Dep2> dep2MembersInjector;",
+ " private Provider<Dep2> dep2Provider;",
+ "",
+ " private DaggerParentComponent(Builder builder) { ",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() { ",
+ " return new Builder();",
+ " }",
+ "",
+ " public static ParentComponent create() { ",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) { ",
+ " this.dep1MembersInjector = Dep1_MembersInjector.create();",
+ " this.dep1Provider = Dep1_Factory.create(dep1MembersInjector);",
+ " this.dep2MembersInjector = Dep2_MembersInjector.create();",
+ " this.dep2Provider = Dep2_Factory.create(dep2MembersInjector);",
+ " }",
+ "",
+ " @Override",
+ " public Dep1 getDep1() { ",
+ " return dep1Provider.get();",
+ " }",
+ "",
+ " @Override",
+ " public Dep2 getDep2() { ",
+ " return dep2Provider.get();",
+ " }",
+ "",
+ " @Override",
+ " public ChildComponent childComponent() { ",
+ " return new ChildComponentImpl();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() { ",
+ " }",
+ " ",
+ " public ParentComponent build() { ",
+ " return new DaggerParentComponent(this);",
+ " }",
+ " }",
+ "",
+ " private final class ChildComponentImpl implements ChildComponent {",
+ " private final ChildModule childModule;",
+ " private MembersInjector<A> aMembersInjector;",
+ " private Provider<NeedsDep1> needsDep1Provider;",
+ " private Provider<A> aProvider;",
+ " private Provider<Object> provideObjectProvider;",
+ " private MembersInjector<Dep1> dep1MembersInjector;",
+ " private MembersInjector<Dep2> dep2MembersInjector;",
+ " ",
+ " private ChildComponentImpl() { ",
+ " this.childModule = new ChildModule();",
+ " initialize();",
+ " }",
+ " ",
+ " private void initialize() { ",
+ " this.aMembersInjector = A_MembersInjector.create();",
+ " this.needsDep1Provider = NeedsDep1_Factory.create(",
+ " DaggerParentComponent.this.dep1Provider);",
+ " this.aProvider = A_Factory.create(",
+ " aMembersInjector,",
+ " needsDep1Provider,",
+ " DaggerParentComponent.this.dep1Provider,",
+ " DaggerParentComponent.this.dep2Provider);",
+ " this.provideObjectProvider = ChildModule_ProvideObjectFactory.create(",
+ " childModule, aProvider);",
+ " this.dep1MembersInjector = Dep1_MembersInjector.create();",
+ " this.dep2MembersInjector = Dep2_MembersInjector.create();",
+ " }",
+ " ",
+ " @Override",
+ " public Object getObject() { ",
+ " return provideObjectProvider.get();",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(
+ ImmutableList.of(
+ parentComponentFile,
+ childComponentFile,
+ childModuleFile,
+ aFile,
+ needsDep1File,
+ dep1File,
+ dep2File))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(componentGeneratedFile);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ValidationReportTest.java b/compiler/src/test/java/dagger/internal/codegen/ValidationReportTest.java
new file mode 100644
index 000000000..d7f445125
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ValidationReportTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.google.testing.compile.JavaFileObjects;
+import dagger.internal.codegen.ValidationReport.Builder;
+import java.util.Set;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.TypeElement;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+
+@RunWith(JUnit4.class)
+public class ValidationReportTest {
+ private static final JavaFileObject TEST_CLASS_FILE =
+ JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "final class TestClass {}");
+
+ @Test
+ public void basicReport() {
+ assertAbout(javaSource())
+ .that(TEST_CLASS_FILE)
+ .processedWith(
+ new SimpleTestProcessor() {
+ @Override
+ void test() {
+ Builder<TypeElement> reportBuilder =
+ ValidationReport.about(getTypeElement("test.TestClass"));
+ reportBuilder.addError("simple error");
+ reportBuilder.build().printMessagesTo(processingEnv.getMessager());
+ }
+ })
+ .failsToCompile()
+ .withErrorContaining("simple error")
+ .in(TEST_CLASS_FILE)
+ .onLine(3);
+ }
+
+ @Test
+ public void messageOnDifferentElement() {
+ assertAbout(javaSource())
+ .that(TEST_CLASS_FILE)
+ .processedWith(
+ 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());
+ }
+ })
+ .failsToCompile()
+ .withErrorContaining("[java.lang.String] simple error")
+ .in(TEST_CLASS_FILE)
+ .onLine(3);
+ }
+
+ @Test
+ public void subreport() {
+ assertAbout(javaSource())
+ .that(TEST_CLASS_FILE)
+ .processedWith(
+ 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());
+ }
+ })
+ .failsToCompile()
+ .withErrorContaining("simple error")
+ .in(TEST_CLASS_FILE)
+ .onLine(3);
+ }
+
+ private static abstract class SimpleTestProcessor extends AbstractProcessor {
+ @Override
+ public Set<String> getSupportedAnnotationTypes() {
+ return ImmutableSet.of("*");
+ }
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ test();
+ return false;
+ }
+
+ protected final TypeElement getTypeElement(Class<?> clazz) {
+ return getTypeElement(clazz.getCanonicalName());
+ }
+
+ protected final TypeElement getTypeElement(String canonicalName) {
+ return processingEnv.getElementUtils().getTypeElement(canonicalName);
+ }
+
+ abstract void test();
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/writer/ClassNameTest.java b/compiler/src/test/java/dagger/internal/codegen/writer/ClassNameTest.java
new file mode 100644
index 000000000..eff01b849
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/writer/ClassNameTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.CompilationRule;
+import dagger.internal.codegen.writer.ClassNameTest.OuterClass.InnerClass;
+import java.util.Map;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+@RunWith(JUnit4.class)
+public class ClassNameTest {
+ @Rule public CompilationRule compilationRule = new CompilationRule();
+
+ @Test public void bestGuessForString_simpleClass() {
+ assertThat(ClassName.bestGuessFromString(String.class.getName()))
+ .isEqualTo(ClassName.create("java.lang", "String"));
+ }
+
+ static class OuterClass {
+ static class InnerClass {}
+ }
+
+ @Test public void bestGuessForString_nestedClass() {
+ assertThat(ClassName.bestGuessFromString(Map.Entry.class.getCanonicalName()))
+ .isEqualTo(ClassName.create("java.util", ImmutableList.of("Map"), "Entry"));
+ assertThat(ClassName.bestGuessFromString(OuterClass.InnerClass.class.getCanonicalName()))
+ .isEqualTo(
+ ClassName.create("dagger.internal.codegen.writer",
+ ImmutableList.of("ClassNameTest", "OuterClass"), "InnerClass"));
+ }
+
+ @Test public void bestGuessForString_defaultPackage() {
+ assertThat(ClassName.bestGuessFromString("SomeClass"))
+ .isEqualTo(ClassName.create("", "SomeClass"));
+ assertThat(ClassName.bestGuessFromString("SomeClass.Nested"))
+ .isEqualTo(ClassName.create("", ImmutableList.of("SomeClass"), "Nested"));
+ assertThat(ClassName.bestGuessFromString("SomeClass.Nested.EvenMore"))
+ .isEqualTo(ClassName.create("", ImmutableList.of("SomeClass", "Nested"), "EvenMore"));
+ }
+
+ @Test public void bestGuessForString_confusingInput() {
+ try {
+ ClassName.bestGuessFromString("com.test.$");
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ try {
+ ClassName.bestGuessFromString("com.test.LooksLikeAClass.pkg");
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ try {
+ ClassName.bestGuessFromString("!@#$gibberish%^&*");
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ @Test public void classNameFromTypeElement() {
+ Elements elements = compilationRule.getElements();
+ TypeElement element = elements.getTypeElement(Object.class.getCanonicalName());
+ assertThat(ClassName.fromTypeElement(element).canonicalName())
+ .isEqualTo("java.lang.Object");
+ }
+
+ @Test public void peerNamed_topLevelClass() {
+ Elements elements = compilationRule.getElements();
+ TypeElement element = elements.getTypeElement(ClassNameTest.class.getCanonicalName());
+ ClassName className = ClassName.fromTypeElement(element);
+ ClassName peerName = className.peerNamed("Foo");
+ assertThat(peerName.canonicalName())
+ .isEqualTo("dagger.internal.codegen.writer.Foo");
+ }
+
+ @Test public void peerNamed_nestedClass() {
+ Elements elements = compilationRule.getElements();
+ TypeElement element = elements.getTypeElement(OuterClass.class.getCanonicalName());
+ ClassName className = ClassName.fromTypeElement(element);
+ ClassName peerName = className.peerNamed("Foo");
+ assertThat(peerName.canonicalName())
+ .isEqualTo("dagger.internal.codegen.writer.ClassNameTest.Foo");
+ }
+
+ @Test public void peerNamed_deeplyNestedClass() {
+ Elements elements = compilationRule.getElements();
+ TypeElement element = elements.getTypeElement(InnerClass.class.getCanonicalName());
+ ClassName className = ClassName.fromTypeElement(element);
+ ClassName peerName = className.peerNamed("Foo");
+ assertThat(peerName.canonicalName())
+ .isEqualTo("dagger.internal.codegen.writer.ClassNameTest.OuterClass.Foo");
+ }
+
+ @Test public void fromClass_NonNestedClass() {
+ ClassName className = ClassName.fromClass(ClassNameTest.class);
+ assertThat(className.canonicalName()).isEqualTo(
+ "dagger.internal.codegen.writer.ClassNameTest");
+ }
+
+ @Test public void fromClass_NestedClass() {
+ ClassName className = ClassName.fromClass(InnerClass.class);
+ assertThat(className.canonicalName()).isEqualTo(
+ "dagger.internal.codegen.writer.ClassNameTest.OuterClass.InnerClass");
+ }
+
+ @Test public void fromClass_classFileName() {
+ ClassName className = ClassName.fromClass(InnerClass.class);
+ assertThat(className.classFileName('_')).isEqualTo("ClassNameTest_OuterClass_InnerClass");
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/writer/JavaWriterTest.java b/compiler/src/test/java/dagger/internal/codegen/writer/JavaWriterTest.java
new file mode 100644
index 000000000..e775f7487
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/writer/JavaWriterTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class JavaWriterTest {
+ @Test public void referencedAndDeclaredSimpleName() {
+ JavaWriter javaWriter = JavaWriter.inPackage("test");
+ ClassWriter topClass = javaWriter.addClass("Top");
+ topClass.addNestedClass("Middle").addNestedClass("Bottom");
+ topClass.addField(ClassName.create("some.other.pkg", "Bottom"), "field");
+ assertThat(topClass.toString()).doesNotContain("import some.other.pkg.Bottom;");
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/writer/TypeNamesTest.java b/compiler/src/test/java/dagger/internal/codegen/writer/TypeNamesTest.java
new file mode 100644
index 000000000..ec82e9605
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/writer/TypeNamesTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.writer;
+
+import com.google.testing.compile.CompilationRule;
+import java.nio.charset.Charset;
+import java.util.Set;
+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 org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class TypeNamesTest {
+ @Rule public final CompilationRule compilation = new CompilationRule();
+
+ private TypeElement getElement(Class<?> clazz) {
+ return compilation.getElements().getTypeElement(clazz.getCanonicalName());
+ }
+
+ private TypeMirror getType(Class<?> clazz) {
+ return getElement(clazz).asType();
+ }
+
+ @Test
+ public void forTypeMirror_basicTypes() {
+ assertThat(TypeNames.forTypeMirror(getType(Object.class)))
+ .isEqualTo(ClassName.fromClass(Object.class));
+ assertThat(TypeNames.forTypeMirror(getType(Charset.class)))
+ .isEqualTo(ClassName.fromClass(Charset.class));
+ assertThat(TypeNames.forTypeMirror(getType(TypeNamesTest.class)))
+ .isEqualTo(ClassName.fromClass(TypeNamesTest.class));
+ }
+
+ @Test
+ public void forTypeMirror_parameterizedType() {
+ DeclaredType setType =
+ compilation.getTypes().getDeclaredType(getElement(Set.class), getType(Object.class));
+ assertThat(TypeNames.forTypeMirror(setType))
+ .isEqualTo(ParameterizedTypeName.create(Set.class, ClassName.fromClass(Object.class)));
+ }
+
+ @Test
+ public void forTypeMirror_typeVariables() {
+ TypeMirror setType = getType(Set.class);
+ assertThat(TypeNames.forTypeMirror(setType))
+ .isEqualTo(ParameterizedTypeName.create(Set.class, TypeVariableName.named("E")));
+ }
+
+ @Test
+ public void forTypeMirror_primitive() {
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.BOOLEAN)))
+ .isEqualTo(PrimitiveName.BOOLEAN);
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.BYTE)))
+ .isEqualTo(PrimitiveName.BYTE);
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.SHORT)))
+ .isEqualTo(PrimitiveName.SHORT);
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.INT)))
+ .isEqualTo(PrimitiveName.INT);
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.LONG)))
+ .isEqualTo(PrimitiveName.LONG);
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.CHAR)))
+ .isEqualTo(PrimitiveName.CHAR);
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.FLOAT)))
+ .isEqualTo(PrimitiveName.FLOAT);
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.DOUBLE)))
+ .isEqualTo(PrimitiveName.DOUBLE);
+ }
+
+ @Test
+ public void forTypeMirror_arrays() {
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getArrayType(getType(Object.class))))
+ .isEqualTo(new ArrayTypeName(ClassName.fromClass(Object.class)));
+ }
+
+ @Test
+ public void forTypeMirror_void() {
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getNoType(TypeKind.VOID)))
+ .isEqualTo(VoidName.VOID);
+ }
+
+ @Test
+ public void forTypeMirror_null() {
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getNullType()))
+ .isEqualTo(NullName.NULL);
+ }
+}
diff --git a/compiler/src/test/java/dagger/tests/integration/operation/PrimitiveInjectionTest.java b/compiler/src/test/java/dagger/tests/integration/operation/PrimitiveInjectionTest.java
new file mode 100644
index 000000000..40545039c
--- /dev/null
+++ b/compiler/src/test/java/dagger/tests/integration/operation/PrimitiveInjectionTest.java
@@ -0,0 +1,142 @@
+/**
+ * Copyright (C) 2013 Google, Inc.
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.tests.integration.operation;
+
+import com.google.testing.compile.JavaFileObjects;
+import dagger.internal.codegen.ComponentProcessor;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assert_;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static java.util.Arrays.asList;
+
+@RunWith(JUnit4.class)
+public final class PrimitiveInjectionTest {
+
+ // TODO(cgruber): Use @test.ForTest to qualify primitives once qualifier equivalence is working.
+ /*
+ JavaFileObject annotation = JavaFileObjects.forSourceLines("test.ForTest",
+ "package test;",
+ "import javax.inject.Qualifier;",
+ "@Qualifier",
+ "public @interface ForTest {",
+ "}");
+ */
+
+ // TODO(cgruber): Expand test to support more primitive types when b/15512877 is fixed.
+ JavaFileObject primitiveInjectable = JavaFileObjects.forSourceLines("test.PrimitiveInjectable",
+ "package test;",
+ "import javax.inject.Inject;",
+ "class PrimitiveInjectable {",
+ " @Inject PrimitiveInjectable(int ignored) {}",
+ "}");
+
+ JavaFileObject primitiveModule = JavaFileObjects.forSourceLines("test.PrimitiveModule",
+ "package test;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "@Module",
+ "class PrimitiveModule {",
+ " @Provides int primitiveInt() { return Integer.MAX_VALUE; }",
+ "}");
+
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.PrimitiveComponent",
+ "package test;",
+ "import dagger.Component;",
+ "import dagger.Provides;",
+ "@Component(modules = PrimitiveModule.class)",
+ "interface PrimitiveComponent {",
+ " int primitiveInt();",
+ " PrimitiveInjectable primitiveInjectable();",
+ "}");
+
+ JavaFileObject expectedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerPrimitiveComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerPrimitiveComponent implements PrimitiveComponent {",
+ " private Provider<Integer> primitiveIntProvider;",
+ " private Provider<PrimitiveInjectable> primitiveInjectableProvider;",
+ "",
+ " private DaggerPrimitiveComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static PrimitiveComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " private void initialize(final Builder builder) {",
+ " this.primitiveIntProvider =",
+ " PrimitiveModule_PrimitiveIntFactory.create(builder.primitiveModule);",
+ " this.primitiveInjectableProvider =",
+ " PrimitiveInjectable_Factory.create(primitiveIntProvider);",
+ " }",
+ "",
+ " @Override",
+ " public int primitiveInt() {",
+ " return primitiveIntProvider.get();",
+ " }",
+ "",
+ " @Override",
+ " public PrimitiveInjectable primitiveInjectable() {",
+ " return primitiveInjectableProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private PrimitiveModule primitiveModule;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public PrimitiveComponent build() {",
+ " if (primitiveModule == null) {",
+ " this.primitiveModule = new PrimitiveModule();",
+ " }",
+ " return new DaggerPrimitiveComponent(this);",
+ " }",
+ "",
+ " public Builder primitiveModule(PrimitiveModule primitiveModule) {",
+ " if (primitiveModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.primitiveModule = primitiveModule;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+
+ @Test public void primitiveArrayTypesAllInjected() {
+ assert_().about(javaSources())
+ .that(asList(component, primitiveInjectable, primitiveModule))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expectedComponent);
+ }
+}
diff --git a/core/pom.xml b/core/pom.xml
new file mode 100644
index 000000000..eab9dd8b5
--- /dev/null
+++ b/core/pom.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2012 Square, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-parent</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>dagger</artifactId>
+ <name>Dagger</name>
+
+ <properties>
+ <!-- Runtime must remain Java6 to support android. -->
+ <java.version>1.6</java.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>javax.inject</groupId>
+ <artifactId>javax.inject</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>animal-sniffer-maven-plugin</artifactId>
+ <version>1.8</version><!-- 1.9+ requires JDK7 on the build machine -->
+ <executions>
+ <execution>
+ <id>sniff-api</id>
+ <goals><goal>check</goal></goals>
+ </execution>
+ </executions>
+ <configuration>
+ <signature>
+ <groupId>org.codehaus.mojo.signature</groupId>
+ <artifactId>java16</artifactId>
+ <version>1.0</version>
+ </signature>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <excludePackageNames>dagger.internal:dagger.internal.*</excludePackageNames>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/core/src/main/java/dagger/Component.java b/core/src/main/java/dagger/Component.java
new file mode 100644
index 000000000..7d724017e
--- /dev/null
+++ b/core/src/main/java/dagger/Component.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Qualifier;
+import javax.inject.Scope;
+import javax.inject.Singleton;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotates an interface or abstract class for which a fully-formed, dependency-injected
+ * implementation is to be generated from a set of {@linkplain #modules}. The generated class will
+ * have the name of the type annotated with {@code @Component} prepended with {@code Dagger}. For
+ * example, {@code @Component interface MyComponent {...}} will produce an implementation named
+ * {@code DaggerMyComponent}.
+ *
+ * <a name="component-methods">
+ * <h2>Component methods</h2>
+ * </a>
+ *
+ * <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">
+ * <h3>Provision methods</h3>
+ * </a>
+ *
+ * <p>Provision methods have no parameters and return an {@link Inject injected} or
+ * {@link Provides provided} type. Each method may have a {@link Qualifier} annotation as well. The
+ * following are all valid provision method declarations: <pre><code>
+ * SomeType getSomeType();
+ * {@literal Set<SomeType>} getSomeTypes();
+ * {@literal @PortNumber} int getPortNumber();
+ * </code></pre>
+ *
+ * <p>Provision methods, like typical {@link Inject injection} sites, may use {@link Provider} or
+ * {@link Lazy} to more explicitly control provision requests. A {@link Provider} allows the user
+ * of the component to request provision any number of times by calling {@link Provider#get}. A
+ * {@link Lazy} will only ever request a single provision, but will defer it until the first call to
+ * {@link Lazy#get}. The following provision methods all request provision of the same type, but
+ * each implies different semantics: <pre><code>
+ * SomeType getSomeType();
+ * {@literal Provider<SomeType>} getSomeTypeProvider();
+ * {@literal Lazy<SomeType>} getLazySomeType();
+ * </code></pre>
+ *
+ * <a name="members-injection-methods">
+ * <h3>Members-injection methods</h3>
+ * </a>
+ *
+ * <p>Members-injection methods have a single parameter and inject dependencies into each of the
+ * {@link Inject}-annotated fields and methods of the passed instance. A members-injection method
+ * may be void or return its single parameter as a convenience for chaining. The following are all
+ * valid members-injection method declarations: <pre><code>
+ * void injectSomeType(SomeType someType);
+ * SomeType injectAndReturnSomeType(SomeType someType);
+ * </code></pre>
+ *
+ * <p>A method with no parameters that returns a {@link MembersInjector} is equivalent to a members
+ * injection method. Calling {@link MembersInjector#injectMembers} on the returned object will
+ * perform the same work as a members injection method. For example: <pre><code>
+ * {@literal MembersInjector<SomeType>} getSomeTypeMembersInjector();
+ * </code></pre>
+ *
+ * <h4>A note about covariance</h4>
+ *
+ * <p>While a members-injection method for a type will accept instances of its subtypes, only
+ * {@link Inject}-annotated members of the parameter type and its supertypes will be injected;
+ * members of subtypes will not. For example, given the following types, only {@code a} and
+ * {@code b} will be injected into an instance of {@code Child} when it is passed to the
+ * members-injection method {@code injectSelf(Self instance)}: <pre><code>
+ * class Parent {
+ * {@literal @}Inject A a;
+ * }
+ *
+ * class Self extends Parent {
+ * {@literal @}Inject B b;
+ * }
+ *
+ * class Child extends Self {
+ * {@literal @}Inject C c;
+ * }
+ * </code></pre>
+ *
+ * <a name="instantiation">
+ * <h2>Instantiation</h2>
+ * </a>
+ *
+ * <p>Component implementations are primarily instantiated via a generated
+ * <a href="http://en.wikipedia.org/wiki/Builder_pattern">builder</a>. An instance of the builder
+ * is obtained using the {@code builder()} method on the component implementation.
+ * If a nested {@code @Component.Builder} type exists in the component, the {@code builder()}
+ * method will return a generated implementation of that type. If no nested
+ * {@code @Component.Builder} exists, the returned builder has a method to set each of the
+ * {@linkplain #modules} and component {@linkplain #dependencies} named with the
+ * <a href="http://en.wikipedia.org/wiki/CamelCase">lower camel case</a> version of the module
+ * or dependency type. Each component dependency and module without a visible default constructor
+ * must be set explicitly, but any module with a default or no-args constructor accessible to the
+ * component implementation may be elided. This is an example usage of a component 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();
+ * }
+ * </code></pre>
+ *
+ * <p>In the case that a component has no component dependencies and only no-arg modules, the
+ * generated component will also have a factory method {@code create()}.
+ * {@code SomeComponent.create()} and {@code SomeComponent.builder().build()} are both valid and
+ * equivalent.
+ *
+ * <a name="scope">
+ * <h2>Scope</h2>
+ * </a>
+ *
+ * <p>Each Dagger component can be associated with a scope by annotating it with the
+ * {@linkplain Scope scope annotation}. The component implementation ensures that there is only one
+ * provision of each scoped binding per instance of the component. If the component declares a
+ * scope, it may only contain unscoped bindings or bindings of that scope anywhere in the graph. For
+ * example: <pre><code>
+ * {@literal @}Singleton {@literal @}Component
+ * interface MyApplicationComponent {
+ * // this component can only inject types using unscoped or {@literal @}Singleton bindings
+ * }
+ * </code></pre>
+ *
+ * <p>In order to get the proper behavior associated with a scope annotation, it is the caller's
+ * responsibility to instantiate new component instances when appropriate. A {@link Singleton}
+ * component, for instance, should only be instantiated once per application, while a
+ * {@code RequestScoped} component should be instantiated once per request. Because components are
+ * self-contained implementations, exiting a scope is as simple as dropping all references to the
+ * component instance.
+ *
+ * <a name="component-relationships">
+ * <h2>Component relationships</h2>
+ * </a>
+ *
+ * <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">
+ * <h3>Subcomponents</h3>
+ * </a>
+ *
+ * <p>The simplest way to relate two components is by declaring a {@link Subcomponent}. A
+ * subcomponent behaves exactly like a component, but has its implementation generated within
+ * a parent component or subcomponent. That relationship allows the subcomponent implementation to
+ * inherit the <em>entire</em> binding graph from its parent when it is declared. For that reason,
+ * a subcomponent isn't evaluated for completeness until it is associated with a parent.
+ *
+ * <p>Subcomponents are declared via a factory method on a parent component or subcomponent. The
+ * method may have any name, but must return the subcomponent. The factory method's parameters may
+ * be any number of the subcomponent's modules, but must at least include those without visible
+ * no-arg constructors. The following is an example of a factory method that creates a
+ * request-scoped subcomponent from a singleton-scoped parent: <pre><code>
+ * {@literal @}Singleton {@literal @}Component
+ * interface ApplicationComponent {
+ * // component methods...
+ *
+ * RequestComponent newRequestComponent(RequestModule requestModule);
+ * }
+ * </code></pre>
+ *
+ * <a name="component-dependencies">
+ * <h3>Component dependencies</h3>
+ * </a>
+ *
+ * <p>While subcomponents are the simplest way to compose subgraphs of bindings, subcomponents are
+ * tightly coupled with the parents; they may use any binding defined by their ancestor component
+ * and subcomponents. As an alternative, components can use bindings only from another
+ * <em>component interface</em> by declaring a {@linkplain #dependencies component dependency}. When
+ * a type is used as a component dependency, each <a href="#provision-methods">provision method</a>
+ * on the dependency is bound as a provider. Note that <em>only</em> the bindings exposed as
+ * provision methods are available through component dependencies.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@Retention(RUNTIME) // Allows runtimes to have specialized behavior interoperating with Dagger.
+@Target(TYPE)
+@Documented
+public @interface Component {
+ /**
+ * A list of classes annotated with {@link Module} whose bindings are used to generate the
+ * component implementation. Note that through the use of {@link Module#includes} the full set of
+ * modules used to implement the component may include more modules that just those listed here.
+ */
+ Class<?>[] modules() default {};
+
+ /**
+ * A list of types that are to be used as <a href="#component-dependencies">component
+ * dependencies</a>.
+ */
+ Class<?>[] dependencies() default {};
+
+ /**
+ * A builder for a component. Components may have a single nested static abstract class or
+ * interface annotated with {@code @Component.Builder}. If they do, then the component's
+ * generated builder will match the API in the type. Builders must follow some rules:
+ * <ul>
+ * <li> A single abstract method with no arguments must exist, and must return the component.
+ * (This is typically the {@code build()} method.)
+ * <li> All other abstract methods must take a single argument and must return void,
+ * the Builder type, or a supertype of the builder.
+ * <li> Each component dependency <b>must</b> have an abstract setter method.
+ * <li> Each module dependency that Dagger can't instantiate itself (e.g, the module
+ * doesn't have a visible no-args constructor) <b>must</b> have an abstract setter method.
+ * Other module dependencies (ones that Dagger can instantiate) are allowed, but not required.
+ * <li> Non-abstract methods are allowed, but ignored as far as validation and builder generation
+ * are concerned.
+ * </ul>
+ *
+ * For example, this could be a valid Component with a Builder: <pre><code>
+ * {@literal @}Component(modules = {BackendModule.class, FrontendModule.class})
+ * interface MyComponent {
+ * MyWidget myWidget();
+ *
+ * {@literal @}Component.Builder
+ * interface Builder {
+ * MyComponent build();
+ * Builder backendModule(BackendModule bm);
+ * Builder frontendModule(FrontendModule fm);
+ * }
+ * }</code></pre>
+ */
+ @Target(TYPE)
+ @Documented
+ @interface Builder {}
+}
diff --git a/core/src/main/java/dagger/Lazy.java b/core/src/main/java/dagger/Lazy.java
new file mode 100644
index 000000000..e04cc03e3
--- /dev/null
+++ b/core/src/main/java/dagger/Lazy.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2012 Google, Inc.
+ * Copyright (C) 2012 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+/**
+ * A handle to a lazily-computed value. Each {@code Lazy} computes its value on
+ * the first call to {@code get()} and remembers that same value for all
+ * subsequent calls to {@code get()}.
+ *
+ * <p>{@code null} is not a supported value. Implementations of {@code Lazy}
+ * are expected to throw {@link NullPointerException} if the computed value is
+ * {@code null}.
+ *
+ * <h2>Example</h2>
+ * The differences between <strong>direct injection</strong>, <strong>provider
+ * injection</strong> and <strong>lazy injection</strong> are best demonstrated
+ * with an example. Start with a module that computes a different integer for
+ * each use:<pre><code>
+ * {@literal @Module}
+ * final class CounterModule {
+ * int next = 100;
+ *
+ * {@literal @Provides} Integer provideInteger() {
+ * System.out.println("computing...");
+ * return next++;
+ * }
+ * }
+ * </code></pre>
+ *
+ * <h3>Direct Injection</h3>
+ * This class injects that integer and prints it 3 times:<pre><code>
+ * final class DirectCounter {
+ * {@literal @Inject} Integer value;
+ *
+ * void print() {
+ * System.out.println("printing...");
+ * System.out.println(value);
+ * System.out.println(value);
+ * System.out.println(value);
+ * }
+ * }
+ * </code></pre>
+ * Injecting a {@code DirectCounter} and invoking {@code print()} reveals that
+ * the value is computed <i>before</i> it is required:<pre><code>
+ * computing...
+ * printing...
+ * 100
+ * 100
+ * 100
+ * </code></pre>
+ *
+ * <h3>Provider Injection</h3>
+ * This class injects a {@linkplain javax.inject.Provider provider} for the
+ * integer. It calls {@code Provider.get()} 3 times and prints each result:
+ * <pre><code>
+ * final class ProviderCounter {
+ * {@literal @Inject Provider<Integer> provider;}
+ *
+ * void print() {
+ * System.out.println("printing...");
+ * System.out.println(provider.get());
+ * System.out.println(provider.get());
+ * System.out.println(provider.get());
+ * }
+ * }
+ * </code></pre>
+ * Injecting a {@code ProviderCounter} and invoking {@code print()} shows that
+ * a new value is computed each time {@code Provider.get()} is used:<pre><code>
+ * printing...
+ * computing...
+ * 100
+ * computing...
+ * 101
+ * computing...
+ * 102
+ * </code></pre>
+ *
+ * <h3>Lazy Injection</h3>
+ * This class injects a {@code Lazy} for the integer. Like the provider above,
+ * it calls {@code Lazy.get()} 3 times and prints each result:<pre><code>
+ * final class LazyCounter {
+ * {@literal @Inject Lazy<Integer> lazy;}
+ *
+ * void print() {
+ * System.out.println("printing...");
+ * System.out.println(lazy.get());
+ * System.out.println(lazy.get());
+ * System.out.println(lazy.get());
+ * }
+ * }
+ * </code></pre>
+ * Injecting a {@code LazyCounter} and invoking {@code print()} shows that a new
+ * value is computed immediately before it is needed. The same value is returned
+ * for all subsequent uses:<pre><code>
+ * printing...
+ * computing...
+ * 100
+ * 100
+ * 100
+ * </code></pre>
+ *
+ * <h3>Lazy != Singleton</h3>
+ * Note that each injected {@code Lazy} is independent, and remembers its value
+ * in isolation of other {@code Lazy} instances. In this example, two {@code
+ * LazyCounter} objects are created and {@code print()} is called on each:
+ * <pre><code>
+ * final class LazyCounters {
+ * {@literal @Inject} LazyCounter counter1;
+ * {@literal @Inject} LazyCounter counter2;
+ *
+ * void print() {
+ * counter1.print();
+ * counter2.print();
+ * }
+ * }
+ * </code></pre>
+ * The output demonstrates that each {@code Lazy} works independently:
+ * <pre><code>
+ * printing...
+ * computing...
+ * 100
+ * 100
+ * 100
+ * printing...
+ * computing...
+ * 101
+ * 101
+ * 101
+ * </code></pre>
+ * Use {@link javax.inject.Singleton @Singleton} to share one instance among all
+ * clients, and {@code Lazy} for lazy computation in a single client.
+ */
+public interface Lazy<T> {
+ /**
+ * Return the underlying value, computing the value if necessary. All calls to
+ * the same {@code Lazy} instance will return the same result.
+ *
+ * @throws NullPointerException if the computed value is {@code null}.
+ */
+ T get();
+}
diff --git a/core/src/main/java/dagger/MapKey.java b/core/src/main/java/dagger/MapKey.java
new file mode 100644
index 000000000..106c00183
--- /dev/null
+++ b/core/src/main/java/dagger/MapKey.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import dagger.internal.Beta;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.util.Map;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Identifies annotation types that are used to associate keys with values returned by
+ * {@linkplain Provides provider methods} in order to compose a {@linkplain Provides.Type#MAP map}.
+ *
+ * <p>Every provider method annotated with {@code @Provides(type = MAP)} must also have an
+ * annotation that identifies the key for that map entry. That annotation's type must be annotated
+ * with {@code @MapKey}.
+ *
+ * <p>Typically, the key annotation has a single member, whose value is used as the map key.
+ *
+ * <p>For example, to add an entry to a {@code Map<SomeEnum, Integer>} with key
+ * {@code SomeEnum.FOO}, you could use an annotation called {@code @SomeEnumKey}:
+ *
+ * <pre><code>
+ * {@literal @}MapKey
+ * {@literal @}interface SomeEnumKey {
+ * SomeEnum value();
+ * }
+ *
+ * {@literal @}Module
+ * class SomeModule {
+ * {@literal @}Provides(type = MAP)
+ * {@literal @}SomeEnumKey(SomeEnum.FOO)
+ * Integer provideFooValue() {
+ * return 2;
+ * }
+ * }
+ *
+ * class SomeInjectedType {
+ * {@literal @}Inject
+ * SomeInjectedType(Map<SomeEnum, Integer> map) {
+ * assert map.get(SomeEnum.FOO) == 2;
+ * }
+ * }
+ * </code></pre>
+ *
+ * <p>If {@code unwrapValue} is true, the annotation's single member can be any type except an
+ * array.
+ *
+ * <p>See {@link dagger.mapkeys} for standard unwrapped map key annotations for keys that are boxed
+ * primitives, strings, or classes.
+ *
+ * <h2>Annotations as keys</h2>
+ *
+ * <p>If {@link #unwrapValue} is false, then the annotation itself is used as the map key. For
+ * example, to add an entry to a {@code Map<MyMapKey, Integer>} map:
+ *
+ * <pre><code>
+ * {@literal @}MapKey(unwrapValue = false)
+ * {@literal @}interface MyMapKey {
+ * String someString();
+ * MyEnum someEnum();
+ * }
+ *
+ * {@literal @}Module
+ * class SomeModule {
+ * {@literal @}Provides(type = MAP)
+ * {@literal @}MyMapKey(someString = "foo", someEnum = BAR)
+ * Integer provideFooBarValue() {
+ * return 2;
+ * }
+ * }
+ *
+ * class SomeInjectedType {
+ * {@literal @}Inject
+ * SomeInjectedType(Map<MyMapKey, Integer> map) {
+ * assert map.get(new MyMapKeyImpl("foo", MyEnum.BAR)) == 2;
+ * }
+ * }
+ * </code></pre>
+ *
+ * <p>(Note that there must be a class {@code MyMapKeyImpl} that implements {@code MyMapKey} in
+ * order to call {@link Map#get(Object)} on the provided map.)
+ *
+ */
+@Documented
+@Target(ANNOTATION_TYPE)
+@Retention(RUNTIME)
+@Beta
+public @interface MapKey {
+ /**
+ * True to use the value of the single member of the annotated annotation as the map key; false
+ * to use the annotation instance as the map key.
+ *
+ * <p>If true, the single member must not be an array.
+ */
+ boolean unwrapValue() default true;
+}
diff --git a/core/src/main/java/dagger/MembersInjector.java b/core/src/main/java/dagger/MembersInjector.java
new file mode 100644
index 000000000..d0de7f396
--- /dev/null
+++ b/core/src/main/java/dagger/MembersInjector.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 Square, Inc.
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+/**
+ * Injects dependencies into the fields and methods on instances of type {@code T}. Ignores the
+ * presence or absence of an injectable constructor.
+ *
+ * @param <T> type to inject members of
+ *
+ * @author Bob Lee
+ * @author Jesse Wilson
+ * @since 2.0 (since 1.0 without the provision that {@link #injectMembers} cannot accept
+ * {@code null})
+ */
+public interface MembersInjector<T> {
+
+ /**
+ * Injects dependencies into the fields and methods of {@code instance}. Ignores the presence or
+ * absence of an injectable constructor.
+ *
+ * <p>Whenever the object graph creates an instance, it performs this injection automatically
+ * (after first performing constructor injection), so if you're able to let the object graph
+ * create all your objects for you, you'll never need to use this method.
+ *
+ * @param instance into which members are to be injected
+ * @throws NullPointerException if {@code instance} is {@code null}
+ */
+ void injectMembers(T instance);
+}
diff --git a/core/src/main/java/dagger/Module.java b/core/src/main/java/dagger/Module.java
new file mode 100644
index 000000000..05f0f3a6a
--- /dev/null
+++ b/core/src/main/java/dagger/Module.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates a class that contributes to the object graph.
+ */
+@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.
+ */
+ Class<?>[] includes() default {};
+}
diff --git a/core/src/main/java/dagger/Provides.java b/core/src/main/java/dagger/Provides.java
new file mode 100644
index 000000000..741a54a2d
--- /dev/null
+++ b/core/src/main/java/dagger/Provides.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 Google Inc.
+ * Copyright (C) 2012 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import dagger.internal.Beta;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotates methods of a module to create a provider method binding. The
+ * method's return type is bound to its returned value. The object graph will
+ * pass dependencies to the method as parameters.
+ *
+ * @author Bob Lee
+ */
+@Documented @Target(METHOD) @Retention(RUNTIME)
+public @interface Provides {
+ /** The type of binding into which the return type of the annotated method contributes. */
+ enum Type {
+ /**
+ * The method is the only one which can produce the value for the specified return type. This
+ * is the default behavior.
+ */
+ UNIQUE,
+
+ /**
+ * The method's return type forms the generic type argument of a {@code Set<T>}, and the
+ * returned value is contributed to the set. The object graph will pass dependencies to the
+ * method as parameters. The {@code Set<T>} produced from the accumulation of values will be
+ * immutable.
+ *
+ */
+ SET,
+
+ /**
+ * Like {@link #SET}, except the method's return type is {@code Set<T>}, where any values are
+ * contributed to the set. An example use is to provide a default empty set binding, which is
+ * otherwise not possible using {@link #SET}.
+ *
+ */
+ SET_VALUES,
+
+ /**
+ * The method's return type forms the type argument for the value of a
+ * {@code Map<K, Provider<V>>}, and the combination of the annotated key and the returned value
+ * is contributed to the map as a key/value pair. The {@code Map<K, Provider<V>>} produced from
+ * the accumulation of values will be immutable.
+ *
+ */
+ @Beta
+ MAP;
+ }
+
+ Type type() default Type.UNIQUE;
+}
diff --git a/core/src/main/java/dagger/Subcomponent.java b/core/src/main/java/dagger/Subcomponent.java
new file mode 100644
index 000000000..0ef47011f
--- /dev/null
+++ b/core/src/main/java/dagger/Subcomponent.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+/**
+ * A subcomponent that inherits the bindings from a parent {@link Component} or
+ * {@link Subcomponent}. The details of how to associate a subcomponent with a parent are described
+ * in the documentation for {@link Component}.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@Target(TYPE)
+@Documented
+public @interface Subcomponent {
+ /**
+ * A list of classes annotated with {@link Module} whose bindings are used to generate the
+ * subcomponent implementation. Note that through the use of {@link Module#includes} the full set
+ * of modules used to implement the subcomponent may include more modules that just those listed
+ * here.
+ */
+ Class<?>[] modules() default {};
+
+ /**
+ * A builder for a subcomponent. This follows all the rules of {@link Component.Builder}, except
+ * it must appear in classes annotated with {@link Subcomponent} instead of {@code Component}.
+ * Components can have methods that return a {@link Subcomponent.Builder}-annotated type,
+ * allowing the user to set modules on the subcomponent using their defined API.
+ */
+ @Target(TYPE)
+ @Documented
+ @interface Builder {}
+}
diff --git a/core/src/main/java/dagger/internal/Beta.java b/core/src/main/java/dagger/internal/Beta.java
new file mode 100644
index 000000000..a0a82c659
--- /dev/null
+++ b/core/src/main/java/dagger/internal/Beta.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Signifies that a public API (public class, method or field) is subject to
+ * incompatible changes, or even removal, in a future release. An API bearing
+ * this annotation is exempt from any compatibility guarantees made by its
+ * containing library. Note that the presence of this annotation implies nothing
+ * about the quality or performance of the API in question, only the fact that
+ * it is not "API-frozen."
+ */
+@Documented
+@Retention(SOURCE)
+public @interface Beta {}
diff --git a/core/src/main/java/dagger/internal/Collections.java b/core/src/main/java/dagger/internal/Collections.java
new file mode 100644
index 000000000..55f26ebab
--- /dev/null
+++ b/core/src/main/java/dagger/internal/Collections.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+
+final class Collections {
+ /**
+ * The maximum value for a signed 32-bit integer that is equal to a power of 2.
+ */
+ private static final int MAX_POWER_OF_TWO = 1 << (Integer.SIZE - 2);
+
+ private Collections() {
+ }
+
+ /**
+ * Creates a {@link LinkedHashSet} instance, with a high enough "initial capacity" that it
+ * <em>should</em> hold {@code expectedSize} elements without growth.
+ */
+ static <E> LinkedHashSet<E> newLinkedHashSetWithExpectedSize(int expectedSize) {
+ return new LinkedHashSet<E>(calculateInitialCapacity(expectedSize));
+ }
+
+ /**
+ * Creates a {@link LinkedHashMap} instance, with a high enough "initial capacity" that it
+ * <em>should</em> hold {@code expectedSize} elements without growth.
+ */
+ static <K, V> LinkedHashMap<K, V> newLinkedHashMapWithExpectedSize(int expectedSize) {
+ return new LinkedHashMap<K, V>(calculateInitialCapacity(expectedSize));
+ }
+
+ private static int calculateInitialCapacity(int expectedSize) {
+ if (expectedSize < 3) {
+ return expectedSize + 1;
+ }
+ if (expectedSize < MAX_POWER_OF_TWO) {
+ // This is the calculation used in JDK8 to resize when a putAll
+ // happens; it seems to be the most conservative calculation we
+ // can make. 0.75 is the default load factor.
+ return (int) (expectedSize / 0.75F + 1.0F);
+ }
+ return Integer.MAX_VALUE; // any large value
+ }
+}
diff --git a/core/src/main/java/dagger/internal/DelegateFactory.java b/core/src/main/java/dagger/internal/DelegateFactory.java
new file mode 100644
index 000000000..d1e864d17
--- /dev/null
+++ b/core/src/main/java/dagger/internal/DelegateFactory.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 javax.inject.Provider;
+
+/**
+ * A DelegateFactory that is used to stitch Provider/Lazy indirection based dependency cycles.
+ *
+ * @since 2.0.1
+ */
+public final class DelegateFactory<T> implements Factory<T> {
+ private Provider<T> delegate;
+
+ @Override
+ public T get() {
+ if (delegate == null) {
+ throw new IllegalStateException();
+ }
+ return delegate.get();
+ }
+
+ public void setDelegatedProvider(Provider<T> delegate) {
+ if (delegate == null) {
+ throw new IllegalArgumentException();
+ }
+ if (this.delegate != null) {
+ throw new IllegalStateException();
+ }
+ this.delegate = delegate;
+ }
+}
+
diff --git a/core/src/main/java/dagger/internal/DoubleCheckLazy.java b/core/src/main/java/dagger/internal/DoubleCheckLazy.java
new file mode 100644
index 000000000..d0f102896
--- /dev/null
+++ b/core/src/main/java/dagger/internal/DoubleCheckLazy.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 dagger.Lazy;
+import javax.inject.Provider;
+
+/**
+ * A basic {@link Lazy} implementation that memoizes the value returned from a {@link Provider}
+ * using the double-check idiom described in Effective Java 2: Item 71.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+// TODO(gak): Unify the duplicated code between this and ScopedProvider.
+public final class DoubleCheckLazy<T> implements Lazy<T> {
+ private static final Object UNINITIALIZED = new Object();
+
+ private final Provider<T> provider;
+ private volatile Object instance = UNINITIALIZED;
+
+ private DoubleCheckLazy(Provider<T> provider) {
+ assert provider != null;
+ this.provider = provider;
+ }
+
+ @SuppressWarnings("unchecked") // cast only happens when result comes from the factory
+ @Override
+ public T get() {
+ // to suppress it.
+ Object result = instance;
+ if (result == UNINITIALIZED) {
+ synchronized (this) {
+ result = instance;
+ if (result == UNINITIALIZED) {
+ instance = result = provider.get();
+ }
+ }
+ }
+ return (T) result;
+ }
+
+ public static <T> Lazy<T> create(Provider<T> provider) {
+ if (provider == null) {
+ throw new NullPointerException();
+ }
+ if (provider instanceof Lazy) {
+ @SuppressWarnings("unchecked")
+ final Lazy<T> lazy = (Lazy<T>) provider;
+ // Avoids memoizing a value that is already memoized.
+ // NOTE: There is a pathological case where Provider<P> may implement Lazy<L>, but P and L
+ // are different types using covariant return on get(). Right now this is used with
+ // ScopedProvider<T> exclusively, which is implemented such that P and L are always the same
+ // so it will be fine for that case.
+ return lazy;
+ }
+ return new DoubleCheckLazy<T>(provider);
+ }
+}
diff --git a/core/src/main/java/dagger/internal/Factory.java b/core/src/main/java/dagger/internal/Factory.java
new file mode 100644
index 000000000..3e2774cec
--- /dev/null
+++ b/core/src/main/java/dagger/internal/Factory.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Scope;
+
+/**
+ * An {@linkplain Scope unscoped} {@link Provider}. While a {@link Provider} <i>may<i> apply
+ * scoping semantics while providing an instance, a factory implementation is guaranteed to exercise
+ * the binding logic ({@link Inject} constructors, {@link Provides} methods) upon each call to
+ * {@link #get}.
+ *
+ * <p>Note that while subsequent calls to {@link #get} will create new instances for bindings such
+ * as those created by {@link Inject} constructors, a new instance is not guaranteed by all
+ * bindings. For example, {@link Provides} methods may be implemented in ways that return the same
+ * instance for each call.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+public interface Factory<T> extends Provider<T> {
+}
diff --git a/core/src/main/java/dagger/internal/InstanceFactory.java b/core/src/main/java/dagger/internal/InstanceFactory.java
new file mode 100644
index 000000000..59b1fcb8b
--- /dev/null
+++ b/core/src/main/java/dagger/internal/InstanceFactory.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+/**
+ * A {@link Factory} implementation that returns a single instance for all invocations of
+ * {@link #get}.
+ *
+ * <p>Note that while this is a {@link Factory} implementation, and thus unscoped, each call to
+ * {@link #get} will always return the same instance. As such, any scoping applied to this factory
+ * is redundant and unnecessary. However, using this with the {@link ScopedProvider} is valid and
+ * may be desired for testing or contractual guarantees.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+public final class InstanceFactory<T> implements Factory<T> {
+ public static <T> Factory<T> create(T instance) {
+ if (instance == null) {
+ throw new NullPointerException();
+ }
+ return new InstanceFactory<T>(instance);
+ }
+
+ private final T instance;
+
+ private InstanceFactory(T instance) {
+ this.instance = instance;
+ }
+
+ @Override
+ public T get() {
+ return instance;
+ }
+}
diff --git a/core/src/main/java/dagger/internal/MapFactory.java b/core/src/main/java/dagger/internal/MapFactory.java
new file mode 100644
index 000000000..4dac1262b
--- /dev/null
+++ b/core/src/main/java/dagger/internal/MapFactory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 java.util.Map;
+import java.util.Map.Entry;
+import javax.inject.Provider;
+
+import static dagger.internal.Collections.newLinkedHashMapWithExpectedSize;
+import static java.util.Collections.unmodifiableMap;
+
+/**
+ * A {@link Factory} implementation used to implement {@link Map} bindings. This factory returns a
+ * {@code Map<K, V>} when calling {@link #get} (as specified by {@link Factory}).
+ *
+ * @author Chenying Hou
+ * @since 2.0
+ *
+ */
+public final class MapFactory<K, V> implements Factory<Map<K, V>> {
+ private final Map<K, Provider<V>> contributingMap;
+
+ private MapFactory(Map<K, Provider<V>> map) {
+ this.contributingMap = unmodifiableMap(map);
+ }
+
+ /**
+ * Returns a new MapFactory.
+ */
+ public static <K, V> MapFactory<K, V> create(Provider<Map<K, Provider<V>>> mapProviderFactory) {
+ Map<K, Provider<V>> map = mapProviderFactory.get();
+ return new MapFactory<K, V>(map);
+ }
+
+ /**
+ * Returns a {@code Map<K, V>} whose iteration order is that of the elements
+ * given by each of the providers, which are invoked in the order given at creation.
+ */
+ @Override
+ public Map<K, V> get() {
+ Map<K, V> result = newLinkedHashMapWithExpectedSize(contributingMap.size());
+ for (Entry<K, Provider<V>> entry: contributingMap.entrySet()) {
+ result.put(entry.getKey(), entry.getValue().get());
+ }
+ return unmodifiableMap(result);
+ }
+}
diff --git a/core/src/main/java/dagger/internal/MapProviderFactory.java b/core/src/main/java/dagger/internal/MapProviderFactory.java
new file mode 100644
index 000000000..00c0fd33a
--- /dev/null
+++ b/core/src/main/java/dagger/internal/MapProviderFactory.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 java.util.LinkedHashMap;
+import java.util.Map;
+import javax.inject.Provider;
+
+import static dagger.internal.Collections.newLinkedHashMapWithExpectedSize;
+import static java.util.Collections.unmodifiableMap;
+
+/**
+ * A {@link Factory} implementation used to implement {@link Map} bindings. This factory returns a
+ * {@code Map<K, Provider<V>>} when calling {@link #get} (as specified by {@link Factory}).
+ *
+ * @author Chenying Hou
+ * @since 2.0
+ *
+ */
+public final class MapProviderFactory<K, V> implements Factory<Map<K, Provider<V>>> {
+ private final Map<K, Provider<V>> contributingMap;
+
+ /**
+ * Returns a new {@link Builder}
+ */
+ public static <K, V> Builder<K, V> builder(int size) {
+ return new Builder<K, V>(size);
+ }
+
+ private MapProviderFactory(LinkedHashMap<K, Provider<V>> contributingMap) {
+ this.contributingMap = unmodifiableMap(contributingMap);
+ }
+
+ /**
+ * Returns a {@code Map<K, Provider<V>>} whose iteration order is that of the elements
+ * given by each of the providers, which are invoked in the order given at creation.
+ *
+ */
+ @Override
+ public Map<K, Provider<V>> get() {
+ return this.contributingMap;
+ }
+
+ /**
+ * A builder to help build the {@link MapProviderFactory}
+ */
+ public static final class Builder<K, V> {
+ private final LinkedHashMap<K, Provider<V>> mapBuilder;
+
+ private Builder(int size) {
+ // TODO(user): consider which way to initialize mapBuilder is better
+ this.mapBuilder = newLinkedHashMapWithExpectedSize(size);
+ }
+
+ /**
+ * Returns a new {@link MapProviderFactory}
+ */
+ public MapProviderFactory<K, V> build() {
+ return new MapProviderFactory<K, V>(this.mapBuilder);
+ }
+
+ /**
+ * Associate k with providerOfValue in {@code Builder}
+ */
+ public Builder<K, V> put(K key, Provider<V> providerOfValue) {
+ if (key == null) {
+ throw new NullPointerException("The key is null");
+ }
+ if (providerOfValue == null) {
+ throw new NullPointerException("The provider of the value is null");
+ }
+
+ this.mapBuilder.put(key, providerOfValue);
+ return this;
+ }
+ }
+}
diff --git a/core/src/main/java/dagger/internal/MembersInjectors.java b/core/src/main/java/dagger/internal/MembersInjectors.java
new file mode 100644
index 000000000..ee4c7b4cf
--- /dev/null
+++ b/core/src/main/java/dagger/internal/MembersInjectors.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 dagger.MembersInjector;
+import javax.inject.Inject;
+
+/**
+ * Basic {@link MembersInjector} implementations used by the framework.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+public final class MembersInjectors {
+ /**
+ * Returns a {@link MembersInjector} implementation that injects no members
+ *
+ * <p>Note that there is no verification that the type being injected does not have {@link Inject}
+ * members, so care should be taken to ensure appropriate use.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> MembersInjector<T> noOp() {
+ return (MembersInjector<T>) NoOpMembersInjector.INSTANCE;
+ }
+
+ private static enum NoOpMembersInjector implements MembersInjector<Object> {
+ INSTANCE;
+
+ @Override public void injectMembers(Object instance) {
+ if (instance == null) {
+ throw new NullPointerException();
+ }
+ }
+ }
+
+ /**
+ * Returns a {@link MembersInjector} that delegates to the {@link MembersInjector} of its
+ * supertype. This is useful for cases where a type is known not to have its own {@link Inject}
+ * members, but must still inject members on its supertype(s).
+ *
+ * <p>Note that there is no verification that the type being injected does not have {@link Inject}
+ * members, so care should be taken to ensure appropriate use.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> MembersInjector<T> delegatingTo(MembersInjector<? super T> delegate) {
+ return (MembersInjector<T>) delegate;
+ }
+
+ private MembersInjectors() {}
+}
diff --git a/core/src/main/java/dagger/internal/ScopedProvider.java b/core/src/main/java/dagger/internal/ScopedProvider.java
new file mode 100644
index 000000000..b25db380a
--- /dev/null
+++ b/core/src/main/java/dagger/internal/ScopedProvider.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 dagger.Lazy;
+import javax.inject.Provider;
+
+/**
+ * A {@link Provider} implementation that memoizes the result of a {@link Factory} instance.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+public final class ScopedProvider<T> implements Provider<T>, Lazy<T> {
+ private static final Object UNINITIALIZED = new Object();
+
+ private final Factory<T> factory;
+ private volatile Object instance = UNINITIALIZED;
+
+ private ScopedProvider(Factory<T> factory) {
+ assert factory != null;
+ this.factory = factory;
+ }
+
+ @SuppressWarnings("unchecked") // cast only happens when result comes from the factory
+ @Override
+ public T get() {
+ // double-check idiom from EJ2: Item 71
+ Object result = instance;
+ if (result == UNINITIALIZED) {
+ synchronized (this) {
+ result = instance;
+ if (result == UNINITIALIZED) {
+ instance = result = factory.get();
+ }
+ }
+ }
+ return (T) result;
+ }
+
+ /** Returns a new scoped provider for the given factory. */
+ public static <T> Provider<T> create(Factory<T> factory) {
+ if (factory == null) {
+ throw new NullPointerException();
+ }
+ return new ScopedProvider<T>(factory);
+ }
+}
diff --git a/core/src/main/java/dagger/internal/SetFactory.java b/core/src/main/java/dagger/internal/SetFactory.java
new file mode 100644
index 000000000..9b73e79db
--- /dev/null
+++ b/core/src/main/java/dagger/internal/SetFactory.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.inject.Provider;
+
+import static dagger.internal.Collections.newLinkedHashSetWithExpectedSize;
+import static java.util.Collections.unmodifiableSet;
+
+/**
+ * A {@link Factory} implementation used to implement {@link Set} bindings. This factory always
+ * returns a new {@link Set} instance for each call to {@link #get} (as required by {@link Factory})
+ * whose elements are populated by subsequent calls to their {@link Provider#get} methods.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+public final class SetFactory<T> implements Factory<Set<T>> {
+ /**
+ * A message for NPEs that trigger on bad argument lists.
+ */
+ private static final String ARGUMENTS_MUST_BE_NON_NULL =
+ "SetFactory.create() requires its arguments to be non-null";
+
+ /**
+ * Returns the supplied factory. If there's just one factory, there's no need to wrap it or its
+ * result.
+ */
+ public static <T> Factory<Set<T>> create(Factory<Set<T>> factory) {
+ assert factory != null : ARGUMENTS_MUST_BE_NON_NULL;
+ return factory;
+ }
+
+ /**
+ * Returns a new factory that creates {@link Set} instances that form the union of the given
+ * {@link Provider} instances. Callers must not modify the providers array after invoking this
+ * method; no copy is made.
+ */
+ public static <T> Factory<Set<T>> create(
+ @SuppressWarnings("unchecked") Provider<Set<T>>... providers) {
+ assert providers != null : ARGUMENTS_MUST_BE_NON_NULL;
+
+ List<Provider<Set<T>>> contributingProviders = Arrays.asList(providers);
+
+ assert !contributingProviders.contains(null)
+ : "Codegen error? Null within provider list.";
+ assert !hasDuplicates(contributingProviders)
+ : "Codegen error? Duplicates in the provider list";
+
+ return new SetFactory<T>(contributingProviders);
+ }
+
+ /**
+ * Returns true if at least one pair of items in (@code original) are equals.
+ */
+ private static boolean hasDuplicates(List<? extends Object> original) {
+ Set<Object> asSet = new HashSet<Object>(original);
+ return original.size() != asSet.size();
+ }
+
+ private final List<Provider<Set<T>>> contributingProviders;
+
+ private SetFactory(List<Provider<Set<T>>> contributingProviders) {
+ this.contributingProviders = contributingProviders;
+ }
+
+ /**
+ * Returns a {@link Set} whose iteration order is that of the elements given by each of the
+ * providers, which are invoked in the order given at creation.
+ *
+ * @throws NullPointerException if any of the delegate {@link Set} instances or elements therein
+ * are {@code null}
+ */
+ @Override
+ public Set<T> get() {
+ int size = 0;
+
+ // Profiling revealed that this method was a CPU-consuming hotspot in some applications, so
+ // these loops were changed to use c-style for. Versus enhanced for-each loops, C-style for is
+ // faster for ArrayLists, at least through Java 8.
+
+ List<Set<T>> providedSets = new ArrayList<Set<T>>(contributingProviders.size());
+ for (int i = 0, c = contributingProviders.size(); i < c; i++) {
+ Provider<Set<T>> provider = contributingProviders.get(i);
+ Set<T> providedSet = provider.get();
+ if (providedSet == null) {
+ throw new NullPointerException(provider + " returned null");
+ }
+ providedSets.add(providedSet);
+ size += providedSet.size();
+ }
+
+ Set<T> result = newLinkedHashSetWithExpectedSize(size);
+ for (int i = 0, c = providedSets.size(); i < c; i++) {
+ for (T element : providedSets.get(i)) {
+ if (element == null) {
+ throw new NullPointerException("a null element was provided");
+ }
+ result.add(element);
+ }
+ }
+ return unmodifiableSet(result);
+ }
+}
diff --git a/core/src/main/java/dagger/mapkeys/ClassKey.java b/core/src/main/java/dagger/mapkeys/ClassKey.java
new file mode 100644
index 000000000..21497c681
--- /dev/null
+++ b/core/src/main/java/dagger/mapkeys/ClassKey.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.mapkeys;
+
+import dagger.MapKey;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+
+/**
+ * A {@link MapKey} annotation for maps with {@code Class<?>} keys.
+ *
+ * <p>If your map's keys can be constrained, consider using a custom annotation instead, with a
+ * member whose type is {@code Class<? extends Something>}.
+ */
+@Documented
+@Target(METHOD)
+@MapKey
+public @interface ClassKey {
+ Class<?> value();
+} \ No newline at end of file
diff --git a/core/src/main/java/dagger/mapkeys/IntKey.java b/core/src/main/java/dagger/mapkeys/IntKey.java
new file mode 100644
index 000000000..011b49fe8
--- /dev/null
+++ b/core/src/main/java/dagger/mapkeys/IntKey.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.mapkeys;
+
+import dagger.MapKey;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+
+/** A {@link MapKey} annotation for maps with {@code int} keys. */
+@Documented
+@Target(METHOD)
+@MapKey
+public @interface IntKey {
+ int value();
+} \ No newline at end of file
diff --git a/core/src/main/java/dagger/mapkeys/LongKey.java b/core/src/main/java/dagger/mapkeys/LongKey.java
new file mode 100644
index 000000000..183b74d02
--- /dev/null
+++ b/core/src/main/java/dagger/mapkeys/LongKey.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.mapkeys;
+
+import dagger.MapKey;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+
+/** A {@link MapKey} annotation for maps with {@code long} keys. */
+@Documented
+@Target(METHOD)
+@MapKey
+public @interface LongKey {
+ long value();
+} \ No newline at end of file
diff --git a/core/src/main/java/dagger/mapkeys/StringKey.java b/core/src/main/java/dagger/mapkeys/StringKey.java
new file mode 100644
index 000000000..7455a9bc5
--- /dev/null
+++ b/core/src/main/java/dagger/mapkeys/StringKey.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.mapkeys;
+
+import dagger.MapKey;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+
+/** A {@link MapKey} annotation for maps with {@link String} keys. */
+@Documented
+@Target(METHOD)
+@MapKey
+public @interface StringKey {
+ String value();
+} \ No newline at end of file
diff --git a/core/src/main/java/dagger/package-info.java b/core/src/main/java/dagger/package-info.java
new file mode 100644
index 000000000..e5cc67f39
--- /dev/null
+++ b/core/src/main/java/dagger/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 public API for the <a href="http://google.github.io/dagger/">Dagger
+ * 2</a> dependency injection framework. By building upon
+ * <a href="https://jcp.org/en/jsr/detail?id=330">JSR 330</a>, Dagger 2 provides an
+ * annotation-driven API for dependency injection whose implementation is entirely generated at
+ * compile time by <a href="http://en.wikipedia.org/wiki/Java_annotation#Processing">annotation
+ * processors</a>.
+ *
+ * <p>The entry point into the API is the {@link Component}, which annotates abstract types for
+ * Dagger 2 to implement. The dependency graph is configured using using annotations such as
+ * {@link Module}, {@link Provides} and {@link javax.inject.Inject}.
+ *
+ * <p>{@code dagger.internal.codegen.ComponentProcessor} is the processor responsible for generating
+ * the implementation. Dagger uses the annotation procesor
+ * {@linkplain java.util.ServiceLoader service loader} to automatically configure the processor, so
+ * explict build configuration shouldn't be necessary.
+ */
+package dagger;
diff --git a/core/src/test/java/dagger/internal/DoubleCheckLazyTest.java b/core/src/test/java/dagger/internal/DoubleCheckLazyTest.java
new file mode 100644
index 000000000..579e0405f
--- /dev/null
+++ b/core/src/test/java/dagger/internal/DoubleCheckLazyTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.Uninterruptibles;
+import dagger.Lazy;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.inject.Provider;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assert_;
+import static org.junit.Assert.fail;
+
+@RunWith(JUnit4.class)
+public class DoubleCheckLazyTest {
+ @Test public void get() throws Exception {
+ int numThreads = 10;
+ ExecutorService executor = Executors.newFixedThreadPool(numThreads);
+
+ final CountDownLatch latch = new CountDownLatch(numThreads);
+ LatchedProvider provider = new LatchedProvider(latch);
+ final Lazy<Object> lazy = DoubleCheckLazy.create(provider);
+
+ List<Callable<Object>> tasks = Lists.newArrayListWithCapacity(numThreads);
+ for (int i = 0; i < numThreads; i++) {
+ tasks.add(new Callable<Object>() {
+ @Override public Object call() throws Exception {
+ latch.countDown();
+ return lazy.get();
+ }
+ });
+ }
+
+ List<Future<Object>> futures = executor.invokeAll(tasks);
+
+ assert_().that(provider.provisions.get()).isEqualTo(1);
+ Set<Object> results = Sets.newIdentityHashSet();
+ for (Future<Object> future : futures) {
+ results.add(future.get());
+ }
+ assert_().that(results.size()).isEqualTo(1);
+ }
+
+ // TODO(gak): reenable this test once we can ensure that factories are no longer providing null
+ @Ignore @Test public void get_null() {
+ Lazy<Object> lazy = DoubleCheckLazy.create(new Provider<Object> () {
+ @Override public Object get() {
+ return null;
+ }
+ });
+ try {
+ lazy.get();
+ fail();
+ } catch (NullPointerException expected) {}
+ }
+
+ private static class LatchedProvider implements Provider<Object> {
+ final AtomicInteger provisions;
+ final CountDownLatch latch;
+
+ LatchedProvider(CountDownLatch latch) {
+ this.latch = latch;
+ this.provisions = new AtomicInteger();
+ }
+
+ @Override
+ public Object get() {
+ if (latch != null) {
+ Uninterruptibles.awaitUninterruptibly(latch);
+ }
+ provisions.incrementAndGet();
+ return new Object();
+ }
+ }
+}
diff --git a/core/src/test/java/dagger/internal/InstanceFactoryTest.java b/core/src/test/java/dagger/internal/InstanceFactoryTest.java
new file mode 100644
index 000000000..acaf20d79
--- /dev/null
+++ b/core/src/test/java/dagger/internal/InstanceFactoryTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assert_;
+
+@RunWith(JUnit4.class)
+public final class InstanceFactoryTest {
+ @Rule public final ExpectedException thrown = ExpectedException.none();
+
+ @Test public void instanceFactory() {
+ Object instance = new Object();
+ Factory<Object> factory = InstanceFactory.create(instance);
+ assert_().that(factory.get()).isEqualTo(instance);
+ assert_().that(factory.get()).isEqualTo(instance);
+ assert_().that(factory.get()).isEqualTo(instance);
+ }
+
+ @Test public void create_throwsNullPointerException() {
+ thrown.expect(NullPointerException.class);
+ InstanceFactory.create(null);
+ }
+}
diff --git a/core/src/test/java/dagger/internal/MapProviderFactoryTest.java b/core/src/test/java/dagger/internal/MapProviderFactoryTest.java
new file mode 100644
index 000000000..b4496e926
--- /dev/null
+++ b/core/src/test/java/dagger/internal/MapProviderFactoryTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.inject.Provider;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assert_;
+
+@RunWith(JUnit4.class)
+@SuppressWarnings("unchecked")
+public class MapProviderFactoryTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void nullKey() {
+ thrown.expect(NullPointerException.class);
+ MapProviderFactory.<String, Integer>builder(1).put(null, incrementingIntegerProvider(1));
+ }
+
+ @Test
+ public void nullValue() {
+ thrown.expect(NullPointerException.class);
+ MapProviderFactory.<String, Integer>builder(1).put("Hello", null);
+ }
+
+ @Test
+ public void iterationOrder() {
+ Provider<Integer> p1 = incrementingIntegerProvider(10);
+ Provider<Integer> p2 = incrementingIntegerProvider(20);
+ Provider<Integer> p3 = incrementingIntegerProvider(30);
+ Provider<Integer> p4 = incrementingIntegerProvider(40);
+ Provider<Integer> p5 = incrementingIntegerProvider(50);
+
+ Factory<Map<String, Provider<Integer>>> factory = MapProviderFactory
+ .<String, Integer>builder(4)
+ .put("two", p2)
+ .put("one", p1)
+ .put("three", p3)
+ .put("one", p5)
+ .put("four", p4)
+ .build();
+
+ Map<String, Provider<Integer>> expectedMap = new LinkedHashMap<String, Provider<Integer>>();
+ expectedMap.put("two", p2);
+ expectedMap.put("one", p1);
+ expectedMap.put("three", p3);
+ expectedMap.put("one", p5);
+ expectedMap.put("four", p4);
+ assert_()
+ .that(factory.get().entrySet())
+ .containsExactlyElementsIn(expectedMap.entrySet())
+ .inOrder();
+ }
+
+ private static Provider<Integer> incrementingIntegerProvider(int seed) {
+ final AtomicInteger value = new AtomicInteger(seed);
+ return new Provider<Integer>() {
+ @Override
+ public Integer get() {
+ return value.getAndIncrement();
+ }
+ };
+ }
+}
diff --git a/core/src/test/java/dagger/internal/ScopedProviderTest.java b/core/src/test/java/dagger/internal/ScopedProviderTest.java
new file mode 100644
index 000000000..84b02c510
--- /dev/null
+++ b/core/src/test/java/dagger/internal/ScopedProviderTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 javax.inject.Provider;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assert_;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests {@link ScopedProvider}.
+ */
+@RunWith(JUnit4.class)
+public class ScopedProviderTest {
+ @Test public void create_nullPointerException() {
+ try {
+ ScopedProvider.create(null);
+ fail();
+ } catch (NullPointerException expected) { }
+ }
+
+ // TODO(gak): reenable this test once we can ensure that factories are no longer providing null
+ @Ignore @Test public void get_nullPointerException() {
+ Provider<Object> scopedProvider = ScopedProvider.create(new Factory<Object>() {
+ @Override public Object get() {
+ return null;
+ }
+ });
+ try {
+ scopedProvider.get();
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ @Test public void get() {
+ Provider<Integer> scopedProvider = ScopedProvider.create(new Factory<Integer>() {
+ int i = 0;
+
+ @Override public Integer get() {
+ return i++;
+ }
+ });
+ assert_().that(scopedProvider.get()).isEqualTo(0);
+ assert_().that(scopedProvider.get()).isEqualTo(0);
+ assert_().that(scopedProvider.get()).isEqualTo(0);
+ }
+}
diff --git a/core/src/test/java/dagger/internal/SetFactoryTest.java b/core/src/test/java/dagger/internal/SetFactoryTest.java
new file mode 100644
index 000000000..04b982281
--- /dev/null
+++ b/core/src/test/java/dagger/internal/SetFactoryTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.google.common.collect.ContiguousSet;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Range;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.inject.Provider;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.collect.DiscreteDomain.integers;
+import static com.google.common.truth.Truth.assert_;
+
+@RunWith(JUnit4.class)
+@SuppressWarnings("unchecked")
+public class SetFactoryTest {
+ @Rule public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void providerReturnsNullSet() {
+ Factory<Set<Integer>> factory = SetFactory.create(new Provider<Set<Integer>>() {
+ @Override
+ public Set<Integer> get() {
+ return null;
+ }
+ }, incrementingIntegerProvider(0));
+ thrown.expect(NullPointerException.class);
+ factory.get();
+ }
+
+ @Test
+ public void providerReturnsNullSet_single() {
+ Factory<Set<Integer>> factory = SetFactory.create(new Provider<Set<Integer>>() {
+ @Override
+ public Set<Integer> get() {
+ return null;
+ }
+ });
+ thrown.expect(NullPointerException.class);
+ factory.get();
+ }
+
+ @Test
+ public void providerReturnsSetWithNullElement() {
+ Factory<Set<Integer>> factory = SetFactory.create(new Provider<Set<Integer>>() {
+ @Override
+ public Set<Integer> get() {
+ LinkedHashSet<Integer> result = new LinkedHashSet<Integer>();
+ result.add(1);
+ result.add(null);
+ result.add(3);
+ return result;
+ }
+ });
+ thrown.expect(NullPointerException.class);
+ factory.get();
+ }
+
+ @Test
+ public void providerReturnsSetWithNullElement_single() {
+ Factory<Set<Integer>> factory = SetFactory.create(new Provider<Set<Integer>>() {
+ @Override
+ public Set<Integer> get() {
+ LinkedHashSet<Integer> result = new LinkedHashSet<Integer>();
+ result.add(1);
+ result.add(null);
+ result.add(3);
+ return result;
+ }
+ }, incrementingIntegerProvider(0));
+ thrown.expect(NullPointerException.class);
+ factory.get();
+ }
+
+ @Test
+ public void invokesProvidersEverytTime() {
+ Factory<Set<Integer>> factory = SetFactory.create(
+ incrementingIntegerProvider(0),
+ incrementingIntegerProvider(10),
+ incrementingIntegerProvider(20));
+ assert_().that(factory.get()).containsExactly(0, 10, 20);
+ assert_().that(factory.get()).containsExactly(1, 11, 21);
+ assert_().that(factory.get()).containsExactly(2, 12, 22);
+ }
+
+ @Test
+ public void iterationOrder() {
+ Factory<Set<Integer>> factory = SetFactory.create(
+ integerSetProvider(Range.closed(5, 9)),
+ integerSetProvider(Range.closed(3, 6)),
+ integerSetProvider(Range.closed(0, 5)));
+ assert_().that(factory.get()).containsExactly(5, 6, 7, 8, 9, 3, 4, 0, 1, 2).inOrder();
+ }
+
+ private static Provider<Set<Integer>> incrementingIntegerProvider(int seed) {
+ final AtomicInteger value = new AtomicInteger(seed);
+ return new Provider<Set<Integer>>() {
+ @Override
+ public Set<Integer> get() {
+ return ImmutableSet.of(value.getAndIncrement());
+ }
+ };
+ }
+
+ private static Provider<Set<Integer>> integerSetProvider(Range<Integer> range) {
+ final ContiguousSet<Integer> set = ContiguousSet.create(range, integers());
+ return new Provider<Set<Integer>>() {
+ @Override
+ public Set<Integer> get() {
+ return set;
+ }
+ };
+ }
+}
diff --git a/deploy_website.sh b/deploy_website.sh
new file mode 100755
index 000000000..1fde1bd57
--- /dev/null
+++ b/deploy_website.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+#
+# Deploys the current Dagger website to the gh-pages branch of the GitHub
+# repository. To test the site locally before deploying run `jekyll --server`
+# in the website/ directory.
+
+set -ex
+
+REPO="git@github.com:square/dagger.git"
+GROUP_ID="com.squareup.dagger"
+ARTIFACT_ID="dagger"
+
+DIR=temp-dagger-clone
+
+# Delete any existing temporary website clone
+rm -rf $DIR
+
+# Clone the current repo into temp folder
+git clone $REPO $DIR
+
+# Move working directory into temp folder
+cd $DIR
+
+# Checkout and track the gh-pages branch
+git checkout -t origin/gh-pages
+
+# Delete everything
+rm -rf *
+
+# Copy website files from real repo
+cp -R ../website/* .
+
+# Download the latest javadoc
+curl -L "http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=$GROUP_ID&a=$ARTIFACT_ID&v=LATEST&c=javadoc" > javadoc.zip
+mkdir javadoc
+unzip javadoc.zip -d javadoc
+rm javadoc.zip
+
+# Stage all files in git and create a commit
+git add .
+git add -u
+git commit -m "Website at $(date)"
+
+# Push the new files up to GitHub
+git push origin gh-pages
+
+# Delete our temp folder
+cd ..
+rm -rf $DIR
diff --git a/examples/android-activity-graphs/AndroidManifest.xml b/examples/android-activity-graphs/AndroidManifest.xml
new file mode 100644
index 000000000..234406dfa
--- /dev/null
+++ b/examples/android-activity-graphs/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1"
+ android:versionName="1.0.0"
+ package="com.example.dagger.activitygraphs">
+
+ <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="17"/>
+
+ <application
+ android:label="app_name"
+ android:name=".DemoApplication">
+ <activity
+ android:label="app_name"
+ android:name=".ui.HomeActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/examples/android-activity-graphs/README.md b/examples/android-activity-graphs/README.md
new file mode 100644
index 000000000..ac3680bb5
--- /dev/null
+++ b/examples/android-activity-graphs/README.md
@@ -0,0 +1,24 @@
+Example: Android Activity Graphs
+================================
+
+Building on top of the simple Android example, this example demonstrates how it is possible to
+create child graphs for each activity which extend from the global graph.
+
+Some of the advantages of the activity scope:
+
+ * Provides the ability to inject objects which require the activity to be constructed.
+ * Allows for the use of singletons on a per-activity basis. This is a great way to manage a
+ resource that is shared by a bunch of fragments in an activity.
+ * Keeps the global object graph clear of things that can be used only by activities.
+
+While this example only shows the presence of an activity scope, you should be able to see the
+potential for other useful scopes that can be used. For example, having a dedicated object graph
+for the current user session is a great way to manage data that is tied to the currently logged-in
+user.
+
+_Note: The app does not actually do anything when it is run. It is only to show how you can
+ structure Dagger within an Android app_
+
+_Note: The app is in transition to Dagger 2 and may not reflect recommended patterns. Before
+ we release Dagger 2.0 it will, but until this note is removed, please do not rely on this
+ example as a strong recommendation._
diff --git a/examples/android-activity-graphs/pom.xml b/examples/android-activity-graphs/pom.xml
new file mode 100644
index 000000000..53de228ff
--- /dev/null
+++ b/examples/android-activity-graphs/pom.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2013 Square, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>com.google.dagger.example</groupId>
+ <artifactId>dagger-example-parent</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>android-activity-graphs</artifactId>
+ <name>Examples: Android - Activity Graphs</name>
+ <packaging>apk</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-compiler</artifactId>
+ <version>${project.version}</version>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.android</groupId>
+ <artifactId>android</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.android</groupId>
+ <artifactId>support-v4</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.jayway.maven.plugins.android.generation2</groupId>
+ <artifactId>android-maven-plugin</artifactId>
+ <extensions>true</extensions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/AbstractActivityComponent.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/AbstractActivityComponent.java
new file mode 100644
index 000000000..430838e83
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/AbstractActivityComponent.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.example.dagger.activitygraphs;
+
+import android.app.Activity;
+import dagger.Component;
+
+/**
+ * A base component upon which fragment's components may depend. Activity-level components
+ * should extend this component.
+ */
+@PerActivity // Subtypes of AbstractActivityComponent should be decorated with @PerActivity.
+@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
+public interface AbstractActivityComponent {
+ Activity activity(); // Expose the activity to sub-graphs.
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ActivityModule.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ActivityModule.java
new file mode 100644
index 000000000..cf5462e50
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ActivityModule.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.example.dagger.activitygraphs;
+
+import android.app.Activity;
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * A module to wrap the Activity state and expose it to the graph.
+ */
+@Module
+public class ActivityModule {
+ private final Activity activity;
+
+ public ActivityModule(Activity activity) {
+ this.activity = activity;
+ }
+
+ /**
+ * Expose the activity to dependents in the graph.
+ */
+ @Provides @PerActivity Activity activity() {
+ return activity;
+ }
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ApplicationComponent.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ApplicationComponent.java
new file mode 100644
index 000000000..04c206225
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ApplicationComponent.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.example.dagger.activitygraphs;
+
+import android.app.Application;
+import android.location.LocationManager;
+import dagger.Component;
+import javax.inject.Singleton;
+
+/**
+ * A component whose lifetime is the life of the application.
+ */
+@Singleton // Constraints this component to one-per-application or unscoped bindings.
+@Component(modules = DemoApplicationModule.class)
+public interface ApplicationComponent {
+ // Field injections of any dependencies of the DemoApplication
+ void inject(DemoApplication application);
+
+ // Exported for child-components.
+ Application application();
+ LocationManager locationManager();
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/DemoApplication.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/DemoApplication.java
new file mode 100644
index 000000000..72057332c
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/DemoApplication.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.example.dagger.activitygraphs;
+
+import android.app.Application;
+import android.location.LocationManager;
+import javax.inject.Singleton;
+import javax.inject.Inject;
+
+public class DemoApplication extends Application {
+ private ApplicationComponent applicationComponent;
+
+ // TODO(cgruber): Figure out a better example of something one might inject into the app.
+ @Inject LocationManager locationManager; // to illustrate injecting something into the app.
+
+ @Override public void onCreate() {
+ super.onCreate();
+ applicationComponent = DaggerApplicationComponent.builder()
+ .demoApplicationModule(new DemoApplicationModule(this))
+ .build();
+ }
+
+ public ApplicationComponent component() {
+ return applicationComponent;
+ }
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/DemoApplicationModule.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/DemoApplicationModule.java
new file mode 100644
index 000000000..070d2c79d
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/DemoApplicationModule.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.example.dagger.activitygraphs;
+
+import android.app.Application;
+import android.location.LocationManager;
+import dagger.Module;
+import dagger.Provides;
+import javax.inject.Singleton;
+
+import static android.content.Context.LOCATION_SERVICE;
+
+/**
+ * A module for Android-specific dependencies which require a {@link Context} or
+ * {@link android.app.Application} to create.
+ */
+@Module
+public class DemoApplicationModule {
+ private final Application application;
+
+ public DemoApplicationModule(Application application) {
+ this.application = application;
+ }
+
+ /**
+ * Expose the application to the graph.
+ */
+ @Provides @Singleton Application application() {
+ return application;
+ }
+
+ @Provides @Singleton LocationManager provideLocationManager() {
+ return (LocationManager) application.getSystemService(LOCATION_SERVICE);
+ }
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/PerActivity.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/PerActivity.java
new file mode 100644
index 000000000..d54b193e3
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/PerActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.example.dagger.activitygraphs;
+
+import java.lang.annotation.Retention;
+import javax.inject.Scope;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * A scoping annotation to permit objects whose lifetime should
+ * conform to the life of the activity to be memoized in the
+ * correct component.
+ */
+@Scope
+@Retention(RUNTIME)
+public @interface PerActivity {
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/ActivityTitleController.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/ActivityTitleController.java
new file mode 100644
index 000000000..c416c75b3
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/ActivityTitleController.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.example.dagger.activitygraphs.ui;
+
+import android.app.Activity;
+import com.example.dagger.activitygraphs.PerActivity;
+import javax.inject.Inject;
+
+/**
+ * A simple abstraction which provides the ability to set the title on an activity.
+ * <p>
+ * Fragments should not directly modify any part of an activity outside of the view or dialog that
+ * it creates. This class provides a way for fragments to inject a controller that will allow for
+ * control of the activity title. While not exceedingly useful in practice, this concept could be
+ * expanded to things like facilitating control over the action bar, dialogs, notifications, etc.
+ */
+@PerActivity
+public class ActivityTitleController {
+ private final Activity activity;
+
+ @Inject public ActivityTitleController(Activity activity) {
+ this.activity = activity;
+ }
+
+ public void setTitle(CharSequence title) {
+ activity.setTitle(title);
+ }
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeActivity.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeActivity.java
new file mode 100644
index 000000000..1f3bb7002
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeActivity.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.example.dagger.activitygraphs.ui;
+
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import com.example.dagger.activitygraphs.ActivityModule;
+import com.example.dagger.activitygraphs.DemoApplication;
+import javax.inject.Inject;
+
+public class HomeActivity extends FragmentActivity {
+ @Inject LocationManager locationManager;
+ private HomeComponent component;
+
+ HomeComponent component() {
+ if (component == null) {
+ component = DaggerHomeComponent.builder()
+ .applicationComponent(((DemoApplication) getApplication()).component())
+ .activityModule(new ActivityModule(this))
+ .build();
+ }
+ return component;
+ }
+
+ @Override protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ component().inject(this);
+
+ if (savedInstanceState == null) {
+ getSupportFragmentManager().beginTransaction()
+ .add(android.R.id.content, new HomeFragment())
+ .commit();
+ }
+
+ // TODO do something with the injected dependencies here!
+ }
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeComponent.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeComponent.java
new file mode 100644
index 000000000..84d2a427c
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeComponent.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.example.dagger.activitygraphs.ui;
+
+import com.example.dagger.activitygraphs.AbstractActivityComponent;
+import com.example.dagger.activitygraphs.ActivityModule;
+import com.example.dagger.activitygraphs.ApplicationComponent;
+import com.example.dagger.activitygraphs.PerActivity;
+import dagger.Component;
+
+@PerActivity
+@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
+public interface HomeComponent extends AbstractActivityComponent {
+ void inject(HomeActivity homeActivity);
+ void inject(HomeFragment homeFragment);
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeFragment.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeFragment.java
new file mode 100644
index 000000000..1df2724cb
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeFragment.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.example.dagger.activitygraphs.ui;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import javax.inject.Inject;
+
+import static android.view.Gravity.CENTER;
+
+public class HomeFragment extends Fragment {
+ @Inject ActivityTitleController titleController;
+
+ @Override public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ ((HomeActivity) getActivity()).component().inject(this);
+ }
+
+ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ TextView tv = new TextView(getActivity());
+ tv.setGravity(CENTER);
+ tv.setText("Hello, World");
+ return tv;
+ }
+
+ @Override public void onResume() {
+ super.onResume();
+
+ // Fragments should not modify things outside of their own view. Use an external controller to
+ // ask the activity to change its title.
+ titleController.setTitle("Home Fragment");
+ }
+}
diff --git a/examples/android-activity-graphs/target/generated-sources/r/com/example/dagger/activitygraphs/BuildConfig.java b/examples/android-activity-graphs/target/generated-sources/r/com/example/dagger/activitygraphs/BuildConfig.java
new file mode 100644
index 000000000..173698284
--- /dev/null
+++ b/examples/android-activity-graphs/target/generated-sources/r/com/example/dagger/activitygraphs/BuildConfig.java
@@ -0,0 +1,8 @@
+/*___Generated_by_IDEA___*/
+
+package com.example.dagger.activitygraphs;
+
+/* This stub is only used by the IDE. It is NOT the BuildConfig class actually packed into the APK */
+public final class BuildConfig {
+ public final static boolean DEBUG = Boolean.parseBoolean(null);
+} \ No newline at end of file
diff --git a/examples/android-activity-graphs/target/generated-sources/r/com/example/dagger/activitygraphs/Manifest.java b/examples/android-activity-graphs/target/generated-sources/r/com/example/dagger/activitygraphs/Manifest.java
new file mode 100644
index 000000000..d0a612287
--- /dev/null
+++ b/examples/android-activity-graphs/target/generated-sources/r/com/example/dagger/activitygraphs/Manifest.java
@@ -0,0 +1,7 @@
+/*___Generated_by_IDEA___*/
+
+package com.example.dagger.activitygraphs;
+
+/* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */
+public final class Manifest {
+} \ No newline at end of file
diff --git a/examples/android-activity-graphs/target/generated-sources/r/com/example/dagger/activitygraphs/R.java b/examples/android-activity-graphs/target/generated-sources/r/com/example/dagger/activitygraphs/R.java
new file mode 100644
index 000000000..09fa17967
--- /dev/null
+++ b/examples/android-activity-graphs/target/generated-sources/r/com/example/dagger/activitygraphs/R.java
@@ -0,0 +1,7 @@
+/*___Generated_by_IDEA___*/
+
+package com.example.dagger.activitygraphs;
+
+/* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */
+public final class R {
+} \ No newline at end of file
diff --git a/examples/android-simple/AndroidManifest.xml b/examples/android-simple/AndroidManifest.xml
new file mode 100644
index 000000000..53c83bfd3
--- /dev/null
+++ b/examples/android-simple/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1"
+ android:versionName="1.0.0"
+ package="com.example.dagger.simple">
+
+ <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="17"/>
+
+ <application
+ android:label="app_name"
+ android:name=".DemoApplication">
+ <activity
+ android:label="app_name"
+ android:name=".ui.HomeActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/examples/android-simple/README.md b/examples/android-simple/README.md
new file mode 100644
index 000000000..944d01533
--- /dev/null
+++ b/examples/android-simple/README.md
@@ -0,0 +1,17 @@
+Example: Android Simple
+=======================
+
+This example demonstrates how to structure an Android application with Dagger.
+
+A custom `Application` class is used to manage a global object graph of objects. Modules are
+assembled with a `getModules` method on the application that can be overridden to add additional
+modules in development versions of your applications or in tests.
+
+Injection of activities is done automatically in a base activity.
+
+_Note: The app does not actually do anything when it is run. It is only to show how you can
+ structure Dagger within an Android app_
+
+_Note: The app is in transition to Dagger 2 and may not reflect recommended patterns. Before
+ we release Dagger 2.0 it will, but until this note is removed, please do not rely on this
+ example as a strong recommendation._
diff --git a/examples/android-simple/pom.xml b/examples/android-simple/pom.xml
new file mode 100644
index 000000000..332aeb66b
--- /dev/null
+++ b/examples/android-simple/pom.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2013 Square, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>com.google.dagger.example</groupId>
+ <artifactId>dagger-example-parent</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>android-simple</artifactId>
+ <name>Examples: Android - Simple</name>
+ <packaging>apk</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-compiler</artifactId>
+ <version>${project.version}</version>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.android</groupId>
+ <artifactId>android</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.jayway.maven.plugins.android.generation2</groupId>
+ <artifactId>android-maven-plugin</artifactId>
+ <extensions>true</extensions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/examples/android-simple/src/main/java/com/example/dagger/simple/AndroidModule.java b/examples/android-simple/src/main/java/com/example/dagger/simple/AndroidModule.java
new file mode 100644
index 000000000..18184d164
--- /dev/null
+++ b/examples/android-simple/src/main/java/com/example/dagger/simple/AndroidModule.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.example.dagger.simple;
+
+import android.content.Context;
+import android.location.LocationManager;
+import dagger.Module;
+import dagger.Provides;
+import javax.inject.Singleton;
+
+import static android.content.Context.LOCATION_SERVICE;
+
+/**
+ * A module for Android-specific dependencies which require a {@link Context} or
+ * {@link android.app.Application} to create.
+ */
+@Module
+public class AndroidModule {
+ private final DemoApplication application;
+
+ public AndroidModule(DemoApplication application) {
+ this.application = application;
+ }
+
+ /**
+ * Allow the application context to be injected but require that it be annotated with
+ * {@link ForApplication @Annotation} to explicitly differentiate it from an activity context.
+ */
+ @Provides @Singleton @ForApplication Context provideApplicationContext() {
+ return application;
+ }
+
+ @Provides @Singleton LocationManager provideLocationManager() {
+ return (LocationManager) application.getSystemService(LOCATION_SERVICE);
+ }
+}
diff --git a/examples/android-simple/src/main/java/com/example/dagger/simple/DemoActivity.java b/examples/android-simple/src/main/java/com/example/dagger/simple/DemoActivity.java
new file mode 100644
index 000000000..aa09f2d0a
--- /dev/null
+++ b/examples/android-simple/src/main/java/com/example/dagger/simple/DemoActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.example.dagger.simple;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public abstract class DemoActivity extends Activity {
+ @Override protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // Perform injection so that when this call returns all dependencies will be available for use.
+ ((DemoApplication) getApplication()).component().inject(this);
+ }
+}
diff --git a/examples/android-simple/src/main/java/com/example/dagger/simple/DemoApplication.java b/examples/android-simple/src/main/java/com/example/dagger/simple/DemoApplication.java
new file mode 100644
index 000000000..55402c654
--- /dev/null
+++ b/examples/android-simple/src/main/java/com/example/dagger/simple/DemoApplication.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.example.dagger.simple;
+
+import android.app.Application;
+import android.location.LocationManager;
+import com.example.dagger.simple.ui.HomeActivity;
+import dagger.Component;
+import java.util.Arrays;
+import java.util.List;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+public class DemoApplication extends Application {
+
+ @Singleton
+ @Component(modules = AndroidModule.class)
+ public interface ApplicationComponent {
+ void inject(DemoApplication application);
+ void inject(HomeActivity homeActivity);
+ void inject(DemoActivity demoActivity);
+ }
+
+ @Inject LocationManager locationManager; // for some reason.
+
+ private ApplicationComponent component;
+
+ @Override public void onCreate() {
+ super.onCreate();
+ component = DaggerDemoApplication_ApplicationComponent.builder()
+ .androidModule(new AndroidModule(this))
+ .build();
+ component().inject(this); // As of now, LocationManager should be injected into this.
+ }
+
+ public ApplicationComponent component() {
+ return component;
+ }
+}
diff --git a/examples/android-simple/src/main/java/com/example/dagger/simple/ForApplication.java b/examples/android-simple/src/main/java/com/example/dagger/simple/ForApplication.java
new file mode 100644
index 000000000..84d224740
--- /dev/null
+++ b/examples/android-simple/src/main/java/com/example/dagger/simple/ForApplication.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.example.dagger.simple;
+
+import java.lang.annotation.Retention;
+import javax.inject.Qualifier;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Qualifier @Retention(RUNTIME)
+public @interface ForApplication {
+}
diff --git a/examples/android-simple/src/main/java/com/example/dagger/simple/ui/HomeActivity.java b/examples/android-simple/src/main/java/com/example/dagger/simple/ui/HomeActivity.java
new file mode 100644
index 000000000..7e33b8eec
--- /dev/null
+++ b/examples/android-simple/src/main/java/com/example/dagger/simple/ui/HomeActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.example.dagger.simple.ui;
+
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.util.Log;
+import com.example.dagger.simple.DemoActivity;
+import com.example.dagger.simple.DemoApplication;
+import javax.inject.Inject;
+
+public class HomeActivity extends DemoActivity {
+ @Inject LocationManager locationManager;
+
+ @Override protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ((DemoApplication) getApplication()).component().inject(this);
+
+ // TODO do something with the injected dependencies here!
+ Log.d("HomeActivity", locationManager.toString());
+ }
+}
diff --git a/examples/android-simple/target/generated-sources/r/com/example/dagger/simple/BuildConfig.java b/examples/android-simple/target/generated-sources/r/com/example/dagger/simple/BuildConfig.java
new file mode 100644
index 000000000..53ff15459
--- /dev/null
+++ b/examples/android-simple/target/generated-sources/r/com/example/dagger/simple/BuildConfig.java
@@ -0,0 +1,8 @@
+/*___Generated_by_IDEA___*/
+
+package com.example.dagger.simple;
+
+/* This stub is only used by the IDE. It is NOT the BuildConfig class actually packed into the APK */
+public final class BuildConfig {
+ public final static boolean DEBUG = Boolean.parseBoolean(null);
+} \ No newline at end of file
diff --git a/examples/android-simple/target/generated-sources/r/com/example/dagger/simple/Manifest.java b/examples/android-simple/target/generated-sources/r/com/example/dagger/simple/Manifest.java
new file mode 100644
index 000000000..d7e5050d1
--- /dev/null
+++ b/examples/android-simple/target/generated-sources/r/com/example/dagger/simple/Manifest.java
@@ -0,0 +1,7 @@
+/*___Generated_by_IDEA___*/
+
+package com.example.dagger.simple;
+
+/* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */
+public final class Manifest {
+} \ No newline at end of file
diff --git a/examples/android-simple/target/generated-sources/r/com/example/dagger/simple/R.java b/examples/android-simple/target/generated-sources/r/com/example/dagger/simple/R.java
new file mode 100644
index 000000000..a42b98ee8
--- /dev/null
+++ b/examples/android-simple/target/generated-sources/r/com/example/dagger/simple/R.java
@@ -0,0 +1,7 @@
+/*___Generated_by_IDEA___*/
+
+package com.example.dagger.simple;
+
+/* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */
+public final class R {
+} \ No newline at end of file
diff --git a/examples/pom.xml b/examples/pom.xml
new file mode 100644
index 000000000..708635f1a
--- /dev/null
+++ b/examples/pom.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2013 Google, Inc.
+ Copyright (C) 2013 Square, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-parent</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+
+ <groupId>com.google.dagger.example</groupId>
+ <artifactId>dagger-example-parent</artifactId>
+ <packaging>pom</packaging>
+ <name>Examples</name>
+
+ <modules>
+ <module>simple</module>
+ <module>android-simple</module>
+ <module>android-activity-graphs</module>
+ </modules>
+
+ <!-- Example-only dependencies. -->
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.android</groupId>
+ <artifactId>android</artifactId>
+ <version>4.1.1.4</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.android</groupId>
+ <artifactId>support-v4</artifactId>
+ <version>r7</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>com.jayway.maven.plugins.android.generation2</groupId>
+ <artifactId>android-maven-plugin</artifactId>
+ <version>3.8.2</version>
+ <configuration>
+ <sdk>
+ <platform>16</platform>
+ </sdk>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+</project>
diff --git a/examples/simple/pom.xml b/examples/simple/pom.xml
new file mode 100644
index 000000000..0be10b86d
--- /dev/null
+++ b/examples/simple/pom.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2012 Square, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>com.google.dagger.example</groupId>
+ <artifactId>dagger-example-parent</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>simple</artifactId>
+ <name>Examples: Simple</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-compiler</artifactId>
+ <version>${project.version}</version>
+ <optional>true</optional>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/examples/simple/src/main/java/coffee/CoffeeApp.java b/examples/simple/src/main/java/coffee/CoffeeApp.java
new file mode 100644
index 000000000..b0a93ec3c
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/CoffeeApp.java
@@ -0,0 +1,17 @@
+package coffee;
+
+import dagger.Component;
+import javax.inject.Singleton;
+
+public class CoffeeApp {
+ @Singleton
+ @Component(modules = { DripCoffeeModule.class })
+ public interface Coffee {
+ CoffeeMaker maker();
+ }
+
+ public static void main(String[] args) {
+ Coffee coffee = DaggerCoffeeApp_Coffee.builder().build();
+ coffee.maker().brew();
+ }
+}
diff --git a/examples/simple/src/main/java/coffee/CoffeeMaker.java b/examples/simple/src/main/java/coffee/CoffeeMaker.java
new file mode 100644
index 000000000..6410336d0
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/CoffeeMaker.java
@@ -0,0 +1,21 @@
+package coffee;
+
+import dagger.Lazy;
+import javax.inject.Inject;
+
+class CoffeeMaker {
+ private final Lazy<Heater> heater; // Create a possibly costly heater only when we use it.
+ private final Pump pump;
+
+ @Inject CoffeeMaker(Lazy<Heater> heater, Pump pump) {
+ this.heater = heater;
+ this.pump = pump;
+ }
+
+ public void brew() {
+ heater.get().on();
+ pump.pump();
+ System.out.println(" [_]P coffee! [_]P ");
+ heater.get().off();
+ }
+}
diff --git a/examples/simple/src/main/java/coffee/DripCoffeeModule.java b/examples/simple/src/main/java/coffee/DripCoffeeModule.java
new file mode 100644
index 000000000..e50d249e1
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/DripCoffeeModule.java
@@ -0,0 +1,12 @@
+package coffee;
+
+import dagger.Module;
+import dagger.Provides;
+import javax.inject.Singleton;
+
+@Module(includes = PumpModule.class)
+class DripCoffeeModule {
+ @Provides @Singleton Heater provideHeater() {
+ return new ElectricHeater();
+ }
+}
diff --git a/examples/simple/src/main/java/coffee/ElectricHeater.java b/examples/simple/src/main/java/coffee/ElectricHeater.java
new file mode 100644
index 000000000..fbab399f2
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/ElectricHeater.java
@@ -0,0 +1,18 @@
+package coffee;
+
+class ElectricHeater implements Heater {
+ boolean heating;
+
+ @Override public void on() {
+ System.out.println("~ ~ ~ heating ~ ~ ~");
+ this.heating = true;
+ }
+
+ @Override public void off() {
+ this.heating = false;
+ }
+
+ @Override public boolean isHot() {
+ return heating;
+ }
+}
diff --git a/examples/simple/src/main/java/coffee/Heater.java b/examples/simple/src/main/java/coffee/Heater.java
new file mode 100644
index 000000000..b5ddb6b88
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/Heater.java
@@ -0,0 +1,7 @@
+package coffee;
+
+interface Heater {
+ void on();
+ void off();
+ boolean isHot();
+}
diff --git a/examples/simple/src/main/java/coffee/Pump.java b/examples/simple/src/main/java/coffee/Pump.java
new file mode 100644
index 000000000..e39434913
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/Pump.java
@@ -0,0 +1,5 @@
+package coffee;
+
+interface Pump {
+ void pump();
+}
diff --git a/examples/simple/src/main/java/coffee/PumpModule.java b/examples/simple/src/main/java/coffee/PumpModule.java
new file mode 100644
index 000000000..338ad33c2
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/PumpModule.java
@@ -0,0 +1,11 @@
+package coffee;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+class PumpModule {
+ @Provides Pump providePump(Thermosiphon pump) {
+ return pump;
+ }
+}
diff --git a/examples/simple/src/main/java/coffee/Thermosiphon.java b/examples/simple/src/main/java/coffee/Thermosiphon.java
new file mode 100644
index 000000000..c9f9828b0
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/Thermosiphon.java
@@ -0,0 +1,18 @@
+package coffee;
+
+import javax.inject.Inject;
+
+class Thermosiphon implements Pump {
+ private final Heater heater;
+
+ @Inject
+ Thermosiphon(Heater heater) {
+ this.heater = heater;
+ }
+
+ @Override public void pump() {
+ if (heater.isHot()) {
+ System.out.println("=> => pumping => =>");
+ }
+ }
+}
diff --git a/lib/auto-common-1.0-20151022.071545-39-sources.jar b/lib/auto-common-1.0-20151022.071545-39-sources.jar
new file mode 100644
index 000000000..66b78b08d
--- /dev/null
+++ b/lib/auto-common-1.0-20151022.071545-39-sources.jar
Binary files differ
diff --git a/lib/auto-common-1.0-20151022.071545-39.jar b/lib/auto-common-1.0-20151022.071545-39.jar
new file mode 100644
index 000000000..8967dead1
--- /dev/null
+++ b/lib/auto-common-1.0-20151022.071545-39.jar
Binary files differ
diff --git a/lib/auto-common-1.0-20151022.071545-39.jar.txt b/lib/auto-common-1.0-20151022.071545-39.jar.txt
new file mode 100644
index 000000000..892eaed8f
--- /dev/null
+++ b/lib/auto-common-1.0-20151022.071545-39.jar.txt
@@ -0,0 +1,203 @@
+Google Gson
+
+ 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 2008-2011 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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/lib/auto-factory-1.0-20150915.183854-35-sources.jar b/lib/auto-factory-1.0-20150915.183854-35-sources.jar
new file mode 100644
index 000000000..5c124070f
--- /dev/null
+++ b/lib/auto-factory-1.0-20150915.183854-35-sources.jar
Binary files differ
diff --git a/lib/auto-factory-1.0-20150915.183854-35.jar b/lib/auto-factory-1.0-20150915.183854-35.jar
new file mode 100644
index 000000000..09f408b77
--- /dev/null
+++ b/lib/auto-factory-1.0-20150915.183854-35.jar
Binary files differ
diff --git a/lib/auto-factory-1.0-20150915.183854-35.jar.txt b/lib/auto-factory-1.0-20150915.183854-35.jar.txt
new file mode 100644
index 000000000..892eaed8f
--- /dev/null
+++ b/lib/auto-factory-1.0-20150915.183854-35.jar.txt
@@ -0,0 +1,203 @@
+Google Gson
+
+ 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 2008-2011 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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/lib/auto-service-1.0-rc2-sources.jar b/lib/auto-service-1.0-rc2-sources.jar
new file mode 100644
index 000000000..cd8f687b3
--- /dev/null
+++ b/lib/auto-service-1.0-rc2-sources.jar
Binary files differ
diff --git a/lib/auto-service-1.0-rc2.jar b/lib/auto-service-1.0-rc2.jar
new file mode 100644
index 000000000..ea8fb68a6
--- /dev/null
+++ b/lib/auto-service-1.0-rc2.jar
Binary files differ
diff --git a/lib/auto-service-1.0-rc2.jar.txt b/lib/auto-service-1.0-rc2.jar.txt
new file mode 100644
index 000000000..892eaed8f
--- /dev/null
+++ b/lib/auto-service-1.0-rc2.jar.txt
@@ -0,0 +1,203 @@
+Google Gson
+
+ 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 2008-2011 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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/lib/auto-value-1.0-sources.jar b/lib/auto-value-1.0-sources.jar
new file mode 100644
index 000000000..86df40d0e
--- /dev/null
+++ b/lib/auto-value-1.0-sources.jar
Binary files differ
diff --git a/lib/auto-value-1.0.jar b/lib/auto-value-1.0.jar
new file mode 100644
index 000000000..3b8893f7e
--- /dev/null
+++ b/lib/auto-value-1.0.jar
Binary files differ
diff --git a/lib/auto-value-1.0.jar.txt b/lib/auto-value-1.0.jar.txt
new file mode 100644
index 000000000..892eaed8f
--- /dev/null
+++ b/lib/auto-value-1.0.jar.txt
@@ -0,0 +1,203 @@
+Google Gson
+
+ 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 2008-2011 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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/lib/google-java-format-0.1-20151017.042846-2.jar b/lib/google-java-format-0.1-20151017.042846-2.jar
new file mode 100644
index 000000000..964760f98
--- /dev/null
+++ b/lib/google-java-format-0.1-20151017.042846-2.jar
Binary files differ
diff --git a/lib/google-java-format-0.1-20151017.042846-2.jar.txt b/lib/google-java-format-0.1-20151017.042846-2.jar.txt
new file mode 100644
index 000000000..eb542743c
--- /dev/null
+++ b/lib/google-java-format-0.1-20151017.042846-2.jar.txt
Binary files differ
diff --git a/lib/javax-inject-src.jar b/lib/javax-inject-src.jar
new file mode 100644
index 000000000..a8a5aa70f
--- /dev/null
+++ b/lib/javax-inject-src.jar
Binary files differ
diff --git a/lib/javax-inject.jar b/lib/javax-inject.jar
new file mode 100644
index 000000000..4c86c52d2
--- /dev/null
+++ b/lib/javax-inject.jar
Binary files differ
diff --git a/lib/javax-inject.jar.txt b/lib/javax-inject.jar.txt
new file mode 100644
index 000000000..892eaed8f
--- /dev/null
+++ b/lib/javax-inject.jar.txt
@@ -0,0 +1,203 @@
+Google Gson
+
+ 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 2008-2011 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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/pom.xml b/pom.xml
new file mode 100644
index 000000000..d584d49d0
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2012 Square, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.sonatype.oss</groupId>
+ <artifactId>oss-parent</artifactId>
+ <version>7</version>
+ </parent>
+
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-parent</artifactId>
+ <packaging>pom</packaging>
+ <version>2.1-SNAPSHOT</version>
+ <name>Dagger (Parent)</name>
+ <description>A fast dependency injector for Android and Java.</description>
+ <url>https://github.com/square/dagger</url>
+
+ <modules>
+ <module>compiler</module>
+ <module>core</module>
+ <!-- examples are handled in a default profile (see below) -->
+ <module>producers</module>
+ </modules>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+
+ <!-- Compilation -->
+ <java.version>1.7</java.version>
+ <javax.inject.version>1</javax.inject.version>
+ <javawriter.version>2.5.0</javawriter.version>
+ <auto.common.version>1.0-SNAPSHOT</auto.common.version>
+ <auto.factory.version>1.0-SNAPSHOT</auto.factory.version>
+ <auto.service.version>1.0-rc2</auto.service.version>
+ <auto.value.version>1.0</auto.value.version>
+ <guava.version>18.0</guava.version>
+
+ <!-- Test Dependencies -->
+ <compile-testing.version>0.7</compile-testing.version>
+ <junit.version>4.11</junit.version>
+ <mockito.version>1.9.5</mockito.version>
+ <truth.version>0.26</truth.version>
+ </properties>
+
+ <scm>
+ <url>http://github.com/google/dagger/</url>
+ <connection>scm:git:git://github.com/google/dagger.git</connection>
+ <developerConnection>scm:git:ssh://git@github.com/google/dagger.git</developerConnection>
+ <tag>HEAD</tag>
+ </scm>
+
+ <issueManagement>
+ <system>GitHub Issues</system>
+ <url>http://github.com/google/dagger/issues</url>
+ </issueManagement>
+
+ <licenses>
+ <license>
+ <name>Apache 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ </license>
+ </licenses>
+
+ <organization>
+ <name>Google, Inc.</name>
+ <url>http://www.google.com</url>
+ </organization>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>javax.inject</groupId>
+ <artifactId>javax.inject</artifactId>
+ <version>${javax.inject.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.squareup</groupId>
+ <artifactId>javawriter</artifactId>
+ <version>${javawriter.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>${guava.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava-testlib</artifactId>
+ <version>${guava.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto</groupId>
+ <artifactId>auto-common</artifactId>
+ <version>${auto.common.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto.service</groupId>
+ <artifactId>auto-service</artifactId>
+ <version>${auto.service.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto.value</groupId>
+ <artifactId>auto-value</artifactId>
+ <version>${auto.value.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>${junit.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.testing.compile</groupId>
+ <artifactId>compile-testing</artifactId>
+ <version>${compile-testing.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>${mockito.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <version>${truth.version}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.7</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.5</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${java.version}</source>
+ <target>${java.version}</target>
+ <compilerArgument>-Xlint:all</compilerArgument>
+ <showWarnings>true</showWarnings>
+ <showDeprecation>true</showDeprecation>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.3.2</version><!--$NO-MVN-MAN-VER$-->
+ <configuration>
+ <autoVersionSubmodules>true</autoVersionSubmodules>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <doctitle>Dagger Dependency Injection ${project.version} API</doctitle>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <failsOnError>false</failsOnError>
+ <consoleOutput>true</consoleOutput>
+ <configLocation>checkstyle.xml</configLocation>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>compile</phase>
+ <goals>
+ <goal>checkstyle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <!--
+ A profile which when switched off excludes example modules. By default the profile
+ is on and invokes examples. However, when processing javadocs, it is switched off
+ omitting the example code from the javadoc.
+ -->
+ <profiles>
+ <profile>
+ <id>examples</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <modules>
+ <module>core</module>
+ <module>compiler</module>
+ <module>examples</module>
+ <module>producers</module>
+ </modules>
+ </profile>
+ </profiles>
+</project>
diff --git a/producers/pom.xml b/producers/pom.xml
new file mode 100644
index 000000000..1ee555b97
--- /dev/null
+++ b/producers/pom.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2014 Google, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-parent</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>dagger-producers</artifactId>
+ <name>Dagger Production Graphs</name>
+ <description>
+ An asynchronous dependency injection system that extends JSR-330.
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>dagger</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/producers/src/main/java/dagger/producers/Produced.java b/producers/src/main/java/dagger/producers/Produced.java
new file mode 100644
index 000000000..7edfee314
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/Produced.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import com.google.common.base.Objects;
+import dagger.internal.Beta;
+import java.util.concurrent.ExecutionException;
+import javax.annotation.Nullable;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * An interface that represents the result of a {@linkplain Producer production} of type {@code T},
+ * or an exception that was thrown during that production. For any type {@code T} that can be
+ * injected, you can also inject {@code Produced<T>}, which enables handling of any exceptions that
+ * were thrown during the production of {@code T}.
+ *
+ * <p>For example: <pre><code>
+ * {@literal @}Produces Html getResponse(
+ * UserInfo criticalInfo, {@literal Produced<ExtraInfo>} noncriticalInfo) {
+ * try {
+ * return new Html(criticalInfo, noncriticalInfo.get());
+ * } catch (ExecutionException e) {
+ * logger.warning(e, "Noncritical info");
+ * return new Html(criticalInfo);
+ * }
+ * }
+ * </code></pre>
+ *
+ * @author Jesse Beder
+ */
+@Beta
+public abstract class Produced<T> {
+ /**
+ * Returns the result of a production.
+ *
+ * @throws ExecutionException if the production threw an exception
+ */
+ public abstract T get() throws ExecutionException;
+
+ /**
+ * Two {@code Produced} objects compare equal if both are successful with equal values, or both
+ * are failed with equal exceptions.
+ */
+ @Override
+ public abstract boolean equals(Object o);
+
+ /** Returns an appropriate hash code to match {@link #equals). */
+ @Override
+ public abstract int hashCode();
+
+ /** Returns a successful {@code Produced}, whose {@link #get} will return the given value. */
+ public static <T> Produced<T> successful(@Nullable T value) {
+ return new Successful(value);
+ }
+
+ /**
+ * Returns a failed {@code Produced}, whose {@link #get} will throw an
+ * {@code ExecutionException} with the given cause.
+ */
+ public static <T> Produced<T> failed(Throwable throwable) {
+ return new Failed(checkNotNull(throwable));
+ }
+
+ private static final class Successful<T> extends Produced<T> {
+ @Nullable private final T value;
+
+ private Successful(@Nullable T value) {
+ this.value = value;
+ }
+
+ @Override public T get() {
+ return value;
+ }
+
+ @Override public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ } else if (o instanceof Successful) {
+ Successful that = (Successful) o;
+ return Objects.equal(this.value, that.value);
+ } else {
+ return false;
+ }
+ }
+
+ @Override public int hashCode() {
+ return value == null ? 0 : value.hashCode();
+ }
+ }
+
+ private static final class Failed<T> extends Produced<T> {
+ private final Throwable throwable;
+
+ private Failed(Throwable throwable) {
+ this.throwable = checkNotNull(throwable);
+ }
+
+ @Override public T get() throws ExecutionException {
+ throw new ExecutionException(throwable);
+ }
+
+ @Override public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ } else if (o instanceof Failed) {
+ Failed that = (Failed) o;
+ return this.throwable.equals(that.throwable);
+ } else {
+ return false;
+ }
+ }
+
+ @Override public int hashCode() {
+ return throwable.hashCode();
+ }
+ }
+
+ private Produced() {}
+}
diff --git a/producers/src/main/java/dagger/producers/Producer.java b/producers/src/main/java/dagger/producers/Producer.java
new file mode 100644
index 000000000..eb159bbf6
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/Producer.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import dagger.internal.Beta;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * An interface that represents the production of a type {@code T}. You can also inject
+ * {@code Producer<T>} instead of {@code T}, which will delay the execution of any code that
+ * produces the {@code T} until {@link #get} is called.
+ *
+ * <p>For example, you might inject {@code Producer} to lazily choose between several different
+ * implementations of some type: <pre><code>
+ * {@literal @Produces ListenableFuture<Heater>} getHeater(
+ * HeaterFlag flag,
+ * {@literal @Electric Producer<Heater>} electricHeater,
+ * {@literal @Gas Producer<Heater>} gasHeater) {
+ * return flag.useElectricHeater() ? electricHeater.get() : gasHeater.get();
+ * }
+ * </code></pre>
+ *
+ * <p>Here is a complete example that demonstrates how calling {@code get()} will cause each
+ * method to be executed: <pre><code>
+ *
+ * {@literal @}ProducerModule
+ * final class MyModule {
+ * {@literal @Produces ListenableFuture<A>} a() {
+ * System.out.println("a");
+ * return Futures.immediateFuture(new A());
+ * }
+ *
+ * {@literal @Produces ListenableFuture<B>} b(A a) {
+ * System.out.println("b");
+ * return Futures.immediateFuture(new B(a));
+ * }
+ *
+ * {@literal @Produces ListenableFuture<C>} c(B b) {
+ * System.out.println("c");
+ * return Futures.immediateFuture(new C(b));
+ * }
+ *
+ * {@literal @Produces @Delayed ListenableFuture<C>} delayedC(A a, {@literal Producer<C>} c) {
+ * System.out.println("delayed c");
+ * return c.get();
+ * }
+ * }
+ *
+ * {@literal @}ProductionComponent(modules = MyModule.class)
+ * interface MyComponent {
+ * {@literal @Delayed ListenableFuture<C>} delayedC();
+ * }
+ * </code></pre>
+ * Suppose we instantiate the generated implementation of this component and call
+ * {@code delayedC()}: <pre><code>
+ * MyComponent component = DaggerMyComponent
+ * .builder()
+ * .executor(MoreExecutors.directExecutor())
+ * .build();
+ * System.out.println("Constructed component");
+ * {@literal ListenableFuture<C>} cFuture = component.delayedC();
+ * System.out.println("Retrieved future");
+ * C c = cFuture.get();
+ * System.out.println("Retrieved c");
+ * </code></pre>
+ * Here, we're using {@code MoreExecutors.directExecutor} in order to illustrate how each call
+ * directly causes code to execute. The above code will print: <pre><code>
+ * Constructed component
+ * a
+ * delayed c
+ * b
+ * c
+ * Retrieved future
+ * Retrieved c
+ * </code></pre>
+ *
+ * @author Jesse Beder
+ */
+@Beta
+public interface Producer<T> {
+ /**
+ * Returns a future representing a running task that produces a value. Calling this method will
+ * trigger the submission of this task to the executor, if it has not already been triggered. In
+ * order to trigger this task's submission, the transitive dependencies required to produce the
+ * {@code T} will be submitted to the executor, as their dependencies become available.
+ *
+ * <p>If the key is bound to a {@link Produces} method, then calling this method multiple times
+ * will return the same future.
+ */
+ ListenableFuture<T> get();
+}
diff --git a/producers/src/main/java/dagger/producers/ProducerModule.java b/producers/src/main/java/dagger/producers/ProducerModule.java
new file mode 100644
index 000000000..714e3fa3e
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/ProducerModule.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import dagger.Module;
+import dagger.internal.Beta;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+/**
+ * Annotates a class that contributes {@link Produces} bindings to the production component.
+ *
+ * @author Jesse Beder
+ */
+@Documented
+@Target(TYPE)
+@Beta
+public @interface ProducerModule {
+ /**
+ * Additional {@code @ProducerModule}- or {@link 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/producers/src/main/java/dagger/producers/Produces.java b/producers/src/main/java/dagger/producers/Produces.java
new file mode 100644
index 000000000..1b57bc39d
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/Produces.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import dagger.internal.Beta;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+
+/**
+ * Annotates methods of a producer module to create a production binding. If the method returns
+ * a {@link ListenableFuture}, then the parameter type of the future is bound to the value that the
+ * future provides; otherwise, the return type is bound to the returned value. The production
+ * component will pass dependencies to the method as parameters.
+ *
+ * @author Jesse Beder
+ */
+@Documented
+@Target(METHOD)
+@Beta
+public @interface Produces {
+ /** The type of binding into which the return type of the annotated method contributes. */
+ enum Type {
+ /**
+ * The method is the only one which can produce the value for the specified type. This is the
+ * default behavior.
+ */
+ UNIQUE,
+
+ /**
+ * The method's resulting type forms the generic type argument of a {@code Set<T>}, and the
+ * returned value or future is contributed to the set. The {@code Set<T>} produced from the
+ * accumulation of values will be immutable.
+ */
+ SET,
+
+ /**
+ * Like {@link #SET}, except the method's return type is either {@code Set<T>} or
+ * {@code Set<ListenableFuture<T>>}, where any values are contributed to the set. An example use
+ * is to provide a default empty set binding, which is otherwise not possible using
+ * {@link #SET}.
+ */
+ SET_VALUES,
+
+ /**
+ * The method's return type forms the type argument for the value of a
+ * {@code Map<K, Producer<V>>}, and the combination of the annotated key and the returned value
+ * is contributed to the map as a key/value pair. The {@code Map<K, Producer<V>>} produced from
+ * the accumulation of values will be immutable.
+ */
+ MAP;
+ }
+
+ Type type() default Type.UNIQUE;
+}
diff --git a/producers/src/main/java/dagger/producers/ProductionComponent.java b/producers/src/main/java/dagger/producers/ProductionComponent.java
new file mode 100644
index 000000000..a6009c5b3
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/ProductionComponent.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.Module;
+import dagger.Provides;
+import dagger.internal.Beta;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+import javax.inject.Inject;
+import javax.inject.Qualifier;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+/**
+ * Annotates an interface or abstract class for which a fully-formed, dependency-injected
+ * implementation is to be generated from a set of {@linkplain #modules}. The generated class will
+ * have the name of the type annotated with {@code @ProductionComponent} prepended with
+ * {@code Dagger}. For example, {@code @ProductionComponent interface MyComponent {...}} will
+ * produce an implementation named {@code DaggerMyComponent}.
+ *
+ * <p>Each {@link Produces} method that contributes to the component will be called at most once per
+ * component instance, no matter how many times that binding is used as a dependency.
+ * TODO(user): Decide on how scope works for producers.
+ *
+ * <h2>Component methods</h2>
+ *
+ * <p>Every type annotated with {@code @ProductionComponent} must contain at least one abstract
+ * component method. Component methods must represent {@linkplain Producer production}.
+ *
+ * Production methods have no arguments and return either a {@link ListenableFuture} or
+ * {@link Producer} of a type that is {@link Inject injected}, {@link Provides provided}, or
+ * {@link Produces produced}. Each may have a {@link Qualifier} annotation as well. The following
+ * are all valid production method declarations: <pre><code>
+ * ListenableFuture<SomeType> getSomeType();
+ * {@literal Producer<Set<SomeType>>} getSomeTypes();
+ * {@literal @Response ListenableFuture<Html>} getResponse();
+ * </code></pre>
+ *
+ * <h2>Exceptions</h2>
+ *
+ * <p>When a producer throws an exception, the exception will be propagated to its downstream
+ * producers in the following way: if the downstream producer injects a type {@code T}, then that
+ * downstream producer will be skipped, and the exception propagated to its downstream producers;
+ * and if the downstream producer injects a {@code Produced<T>}, then the downstream producer will
+ * be run with the exception stored in the {@code Produced<T>}.
+ *
+ * <p>If a non-execution exception is thrown (e.g., an {@code InterruptedException} or
+ * {@code CancellationException}), then exception is handled as in
+ * {@link com.google.common.util.concurrent.Futures#transform}.
+ * <!-- TODO(beder): Explain this more thoroughly, and update the javadocs of those utilities. -->
+ *
+ * @author Jesse Beder
+ */
+@Documented
+@Target(TYPE)
+@Beta
+public @interface ProductionComponent {
+ /**
+ * A list of classes annotated with {@link Module} or {@link ProducerModule} whose bindings are
+ * used to generate the component implementation.
+ */
+ Class<?>[] modules() default {};
+
+ /**
+ * A list of types that are to be used as component dependencies.
+ */
+ Class<?>[] dependencies() default {};
+}
diff --git a/producers/src/main/java/dagger/producers/internal/AbstractProducer.java b/producers/src/main/java/dagger/producers/internal/AbstractProducer.java
new file mode 100644
index 000000000..7843b2094
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/internal/AbstractProducer.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Producer;
+import dagger.producers.monitoring.ProducerMonitor;
+import javax.annotation.Nullable;
+
+/**
+ * An abstract {@link Producer} implementation that memoizes the result of its compute method.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+public abstract class AbstractProducer<T> implements Producer<T> {
+ @Nullable protected final ProducerMonitor monitor;
+ private volatile ListenableFuture<T> instance = null;
+
+ protected AbstractProducer() {
+ this(null);
+ }
+
+ protected AbstractProducer(@Nullable ProducerMonitor monitor) {
+ this.monitor = monitor;
+ }
+
+ /** Computes this producer's future, which is then cached in {@link #get}. */
+ protected abstract ListenableFuture<T> compute();
+
+ @Override
+ public final ListenableFuture<T> get() {
+ // double-check idiom from EJ2: Item 71
+ ListenableFuture<T> result = instance;
+ if (result == null) {
+ synchronized (this) {
+ result = instance;
+ if (result == null) {
+ instance = result = compute();
+ if (result == null) {
+ throw new NullPointerException("compute returned null");
+ }
+ if (monitor != null) {
+ Futures.addCallback(
+ result,
+ new FutureCallback<T>() {
+ @Override
+ public void onSuccess(T value) {
+ monitor.succeeded(value);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ monitor.failed(t);
+ }
+ });
+ }
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/producers/src/main/java/dagger/producers/internal/Producers.java b/producers/src/main/java/dagger/producers/internal/Producers.java
new file mode 100644
index 000000000..6cd06d40e
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/internal/Producers.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.google.common.base.Function;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.FutureFallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListenableFutureTask;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import dagger.producers.monitoring.ProducerMonitor;
+import dagger.producers.monitoring.ProducerToken;
+import dagger.producers.monitoring.ProductionComponentMonitor;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+import javax.annotation.Nullable;
+import javax.inject.Provider;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Utility methods for use in generated producer code.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+public final class Producers {
+ /**
+ * Returns a future of {@link Produced} that represents the completion (either success or failure)
+ * of the given future. If the input future succeeds, then the resulting future also succeeds with
+ * a successful {@code Produced}; if the input future fails, then the resulting future succeeds
+ * with a failing {@code Produced}.
+ *
+ * <p>Cancelling the resulting future will propagate the cancellation to the input future; but
+ * cancelling the input future will trigger the resulting future to succeed with a failing
+ * {@code Produced}.
+ */
+ // TODO(user): Document what happens with an InterruptedException after you figure out how to
+ // trigger one in a test.
+ public static <T> ListenableFuture<Produced<T>> createFutureProduced(ListenableFuture<T> future) {
+ return Futures.withFallback(
+ Futures.transform(future, new Function<T, Produced<T>>() {
+ @Override public Produced<T> apply(final T value) {
+ return Produced.successful(value);
+ }
+ }), Producers.<T>futureFallbackForProduced());
+
+ }
+
+ private static final FutureFallback<Produced<Object>> FUTURE_FALLBACK_FOR_PRODUCED =
+ new FutureFallback<Produced<Object>>() {
+ @Override public ListenableFuture<Produced<Object>> create(final Throwable t) {
+ Produced<Object> produced = Produced.failed(t);
+ return Futures.immediateFuture(produced);
+ }
+ };
+
+ @SuppressWarnings({"unchecked", "rawtypes"}) // bivariant implementation
+ private static <T> FutureFallback<Produced<T>> futureFallbackForProduced() {
+ return (FutureFallback) FUTURE_FALLBACK_FOR_PRODUCED;
+ }
+
+ /**
+ * Returns a future of a {@code Set} that contains a single element: the result of the input
+ * future.
+ */
+ public static <T> ListenableFuture<Set<T>> createFutureSingletonSet(ListenableFuture<T> future) {
+ return Futures.transform(future, new Function<T, Set<T>>() {
+ @Override public Set<T> apply(T value) {
+ return ImmutableSet.of(value);
+ }
+ });
+ }
+
+ /**
+ * Submits a callable to an executor, returning the future representing the task. This mirrors
+ * {@link com.google.common.util.concurrent.ListeningExecutorService#submit}, but only requires an
+ * {@link Executor}.
+ *
+ * @throws RejectedExecutionException if this task cannot be accepted for execution.
+ */
+ public static <T> ListenableFuture<T> submitToExecutor(Callable<T> callable, Executor executor) {
+ ListenableFutureTask<T> future = ListenableFutureTask.create(callable);
+ executor.execute(future);
+ return future;
+ }
+
+ /**
+ * Returns a producer that immediately executes the binding logic for the given provider every
+ * time it is called.
+ */
+ public static <T> Producer<T> producerFromProvider(final Provider<T> provider) {
+ checkNotNull(provider);
+ return new AbstractProducer<T>() {
+ @Override
+ protected ListenableFuture<T> compute() {
+ return Futures.immediateFuture(provider.get());
+ }
+ };
+ }
+
+ /** Lifts {@link ProductionComponentMonitor#producerMonitorFor} to nullable types. */
+ @Nullable
+ public static ProducerMonitor producerMonitorFor(
+ @Nullable ProductionComponentMonitor componentMonitor, ProducerToken token) {
+ if (componentMonitor != null) {
+ return componentMonitor.producerMonitorFor(token);
+ }
+ return null;
+ }
+
+ private Producers() {}
+}
diff --git a/producers/src/main/java/dagger/producers/internal/SetProducer.java b/producers/src/main/java/dagger/producers/internal/SetProducer.java
new file mode 100644
index 000000000..ba3312882
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/internal/SetProducer.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.google.common.base.Function;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Producer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A {@link Producer} implementation used to implement {@link Set} bindings. This producer returns
+ * a future {@link Set} whose elements are populated by subsequent calls to the delegate
+ * {@link Producer#get} methods.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+public final class SetProducer<T> extends AbstractProducer<Set<T>> {
+ /**
+ * Returns a new producer that creates {@link Set} futures from the union of the given
+ * {@link Producer} instances.
+ */
+ public static <T> Producer<Set<T>> create(
+ @SuppressWarnings("unchecked") Producer<Set<T>>... producers) {
+ return new SetProducer<T>(ImmutableSet.copyOf(producers));
+ }
+
+ private final Set<Producer<Set<T>>> contributingProducers;
+
+ private SetProducer(Set<Producer<Set<T>>> contributingProducers) {
+ super();
+ this.contributingProducers = contributingProducers;
+ }
+
+ /**
+ * Returns a future {@link Set} whose iteration order is that of the elements given by each of the
+ * producers, which are invoked in the order given at creation.
+ *
+ * <p>If any of the delegate sets, or any elements therein, are null, then this future will fail
+ * with a NullPointerException.
+ *
+ * <p>Canceling this future will attempt to cancel all of the component futures, and if any of the
+ * delegate futures fails or is canceled, this one is, too.
+ *
+ * @throws NullPointerException if any of the delegate producers return null
+ */
+ @Override
+ public ListenableFuture<Set<T>> compute() {
+ List<ListenableFuture<Set<T>>> futureSets =
+ new ArrayList<ListenableFuture<Set<T>>>(contributingProducers.size());
+ for (Producer<Set<T>> producer : contributingProducers) {
+ ListenableFuture<Set<T>> futureSet = producer.get();
+ if (futureSet == null) {
+ throw new NullPointerException(producer + " returned null");
+ }
+ futureSets.add(futureSet);
+ }
+ return Futures.transform(Futures.allAsList(futureSets), new Function<List<Set<T>>, Set<T>>() {
+ @Override public Set<T> apply(List<Set<T>> sets) {
+ ImmutableSet.Builder<T> builder = ImmutableSet.builder();
+ for (Set<T> set : sets) {
+ builder.addAll(set);
+ }
+ return builder.build();
+ }
+ });
+ }
+}
diff --git a/producers/src/main/java/dagger/producers/monitoring/ProducerMonitor.java b/producers/src/main/java/dagger/producers/monitoring/ProducerMonitor.java
new file mode 100644
index 000000000..8e4e9b28b
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/monitoring/ProducerMonitor.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.monitoring;
+
+/**
+ * A hook for monitoring the execution of individual {@linkplain Produces producer methods}. See
+ * {@link ProductionComponentMonitor} for how to install these monitors.
+ *
+ * <p>The lifecycle of the monitor is:
+ * <ul>
+ * <li>{@link #methodStarting}
+ * <li>The method is called
+ * <li>{@link #methodFinished}
+ * <li>If the method returns a value, then:
+ * <ul>
+ * <li>{#succeeded} if the method returned normally; or
+ * <li>{#failed} if the method threw an exception.
+ * </ul>
+ * <li>If the method returns a future, then:
+ * <ul>
+ * <li>{#succeeded} if the method returned normally, and the future succeeded; or
+ * <li>{#failed} if the method threw an exception, or returned normally and the future failed.
+ * </ul>
+ * </ul>
+ *
+ * <p>If any of the monitor's methods throw, then the exception will be logged and processing will
+ * continue unaffected.
+ *
+ * @author Jesse Beder
+ */
+public abstract class ProducerMonitor {
+ /**
+ * Called when the producer method is about to start executing.
+ *
+ * <p>When multiple monitors are installed, the order that each monitor will call
+ * {@code methodWillStart} is unspecified, but will remain consistent throughout the course of the
+ * execution of a component.
+ */
+ public void methodStarting() {}
+
+ /**
+ * Called when the producer method has finished executing.
+ *
+ * <p>When multiple monitors are installed, the {@code methodFinished} calls will be in the
+ * reverse order from the {@link #methodWillStart} calls.
+ */
+ public void methodFinished() {}
+
+ /**
+ * Called when the producer’s future has completed successfully with a value.
+ *
+ * <p>When multiple monitors are installed, the {@code futureSucceeded} calls will be in the
+ * reverse order from the {@link #methodWillStart} calls.
+ */
+ public void succeeded(Object o) {}
+
+ /**
+ * Called when the producer's future has failed with an exception.
+ *
+ * <p>When multiple monitors are installed, the {@code futureFailed} calls will be in the reverse
+ * order from the {@link #methodWillStart} calls.
+ */
+ public void failed(Throwable t) {}
+}
diff --git a/producers/src/main/java/dagger/producers/monitoring/ProducerToken.java b/producers/src/main/java/dagger/producers/monitoring/ProducerToken.java
new file mode 100644
index 000000000..126a40d4e
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/monitoring/ProducerToken.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.monitoring;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/** A token that represents an individual {@linkplain Produces producer method}. */
+public final class ProducerToken {
+ private final Class<?> classToken;
+
+ private ProducerToken(Class<?> classToken) {
+ this.classToken = classToken;
+ }
+
+ /**
+ * Creates a token for a class token that represents the generated factory for a producer method.
+ *
+ * <p><b>Do not use this!</b> This is intended to be called by generated code only, and its
+ * signature may change at any time.
+ */
+ public static ProducerToken create(Class<?> classToken) {
+ return new ProducerToken(checkNotNull(classToken));
+ }
+
+ /** Two tokens are equal if they represent the same method. */
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ } else if (o instanceof ProducerToken) {
+ ProducerToken that = (ProducerToken) o;
+ return this.classToken.equals(that.classToken);
+ } else {
+ return false;
+ }
+ }
+
+ /** Returns an appropriate hash code to match {@link #equals). */
+ @Override
+ public int hashCode() {
+ return classToken.hashCode();
+ }
+
+ /** Returns a representation of the method. */
+ @Override
+ public String toString() {
+ return classToken.toString();
+ }
+}
diff --git a/producers/src/main/java/dagger/producers/monitoring/ProductionComponentMonitor.java b/producers/src/main/java/dagger/producers/monitoring/ProductionComponentMonitor.java
new file mode 100644
index 000000000..1a62dfa1f
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/monitoring/ProductionComponentMonitor.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.monitoring;
+
+/**
+ * A hook for monitoring execution of {@linkplain ProductionComponent production components}. To
+ * install a {@code ProductionComponentMonitor}, contribute to a set binding of
+ * {@code ProductionComponentMonitor.Factory}. The factory will be asked to create one monitor for
+ * the component, and the resulting single instance will be used to create individual monitors for
+ * producers.
+ *
+ * <p>For example: <pre><code>
+ * {@literal @Module}
+ * final class MyMonitorModule {
+ * {@literal @Provides(type = SET)} ProductionComponentMonitor.Factory provideMonitorFactory(
+ * MyProductionComponentMonitor.Factory monitorFactory) {
+ * return monitorFactory;
+ * }
+ * }
+ *
+ * {@literal @ProductionComponent(modules = {MyMonitorModule.class, MyProducerModule.class})}
+ * interface MyComponent {
+ * {@literal ListenableFuture<SomeType>} someType();
+ * }
+ * </code></pre>
+ *
+ * <p>If any of these methods throw, then the exception will be logged, and the framework will act
+ * as though a no-op monitor was returned.
+ *
+ * @author Jesse Beder
+ */
+public interface ProductionComponentMonitor {
+ /** Returns a monitor for an individual {@linkplain Produces producer method}. */
+ ProducerMonitor producerMonitorFor(ProducerToken token);
+
+ public interface Factory {
+ /** Creates a component-specific monitor when the component is created. */
+ ProductionComponentMonitor create(Object component);
+ }
+}
diff --git a/producers/src/main/java/dagger/producers/monitoring/package-info.java b/producers/src/main/java/dagger/producers/monitoring/package-info.java
new file mode 100644
index 000000000..d10408706
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/monitoring/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 provides hooks for monitoring producers.
+ *
+ * <p>The interfaces in this package are not stable. Do not use these interfaces unless you are
+ * prepared to be broken.
+ */
+package dagger.producers.monitoring;
diff --git a/producers/src/test/java/dagger/producers/ProducedTest.java b/producers/src/test/java/dagger/producers/ProducedTest.java
new file mode 100644
index 000000000..165e7301c
--- /dev/null
+++ b/producers/src/test/java/dagger/producers/ProducedTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import com.google.common.testing.EqualsTester;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests {@link Produced}.
+ */
+@RunWith(JUnit4.class)
+public class ProducedTest {
+ @Test public void successfulProduced() throws ExecutionException {
+ Object o = new Object();
+ assertThat(Produced.successful(5).get()).isEqualTo(5);
+ assertThat(Produced.successful("monkey").get()).isEqualTo("monkey");
+ assertThat(Produced.successful(o).get()).isSameAs(o);
+ }
+
+ @Test public void failedProduced() {
+ RuntimeException cause = new RuntimeException("monkey");
+ try {
+ Produced.failed(cause).get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).isSameAs(cause);
+ }
+ }
+
+ @Test public void producedEquivalence() {
+ RuntimeException e1 = new RuntimeException("monkey");
+ RuntimeException e2 = new CancellationException();
+ new EqualsTester()
+ .addEqualityGroup(Produced.successful(132435), Produced.successful(132435))
+ .addEqualityGroup(Produced.successful("hi"), Produced.successful("hi"))
+ .addEqualityGroup(Produced.failed(e1), Produced.failed(e1))
+ .addEqualityGroup(Produced.failed(e2), Produced.failed(e2))
+ .testEquals();
+ }
+}
diff --git a/producers/src/test/java/dagger/producers/internal/AbstractProducerTest.java b/producers/src/test/java/dagger/producers/internal/AbstractProducerTest.java
new file mode 100644
index 000000000..15a64bd1f
--- /dev/null
+++ b/producers/src/test/java/dagger/producers/internal/AbstractProducerTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import dagger.producers.Producer;
+import dagger.producers.monitoring.ProducerMonitor;
+import java.util.concurrent.ExecutionException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+/**
+ * Tests {@link AbstractProducer}.
+ */
+@RunWith(JUnit4.class)
+public class AbstractProducerTest {
+ @Mock private ProducerMonitor monitor;
+
+ @Before
+ public void initMocks() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void get_nullPointerException() {
+ Producer<Object> producer = new DelegateProducer<>(monitor, null);
+ try {
+ producer.get();
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ @Test public void get() throws Exception {
+ Producer<Integer> producer =
+ new AbstractProducer<Integer>(monitor) {
+ int i = 0;
+
+ @Override
+ public ListenableFuture<Integer> compute() {
+ return Futures.immediateFuture(i++);
+ }
+ };
+ assertThat(producer.get().get()).isEqualTo(0);
+ assertThat(producer.get().get()).isEqualTo(0);
+ assertThat(producer.get().get()).isEqualTo(0);
+ }
+
+ @Test
+ public void monitor_success() throws Exception {
+ SettableFuture<Integer> delegateFuture = SettableFuture.create();
+ Producer<Integer> producer = new DelegateProducer<>(monitor, delegateFuture);
+
+ ListenableFuture<Integer> future = producer.get();
+ assertThat(future.isDone()).isFalse();
+ verifyZeroInteractions(monitor);
+ delegateFuture.set(-42);
+ assertThat(future.get()).isEqualTo(-42);
+ verify(monitor).succeeded(-42);
+ verifyNoMoreInteractions(monitor);
+ }
+
+ @Test
+ public void monitor_failure() throws Exception {
+ SettableFuture<Integer> delegateFuture = SettableFuture.create();
+ Producer<Integer> producer = new DelegateProducer<>(monitor, delegateFuture);
+
+ ListenableFuture<Integer> future = producer.get();
+ assertThat(future.isDone()).isFalse();
+ verifyZeroInteractions(monitor);
+ Throwable t = new RuntimeException("monkey");
+ delegateFuture.setException(t);
+ try {
+ future.get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).isSameAs(t);
+ }
+ verify(monitor).failed(t);
+ verifyNoMoreInteractions(monitor);
+ }
+
+ @Test
+ public void monitor_null() throws Exception {
+ Producer<Integer> producer = new DelegateProducer<>(null, Futures.immediateFuture(42));
+ assertThat(producer.get().get()).isEqualTo(42);
+ }
+
+ static final class DelegateProducer<T> extends AbstractProducer<T> {
+ private final ListenableFuture<T> delegate;
+
+ DelegateProducer(ProducerMonitor monitor, ListenableFuture<T> delegate) {
+ super(monitor);
+ this.delegate = delegate;
+ }
+
+ @Override
+ public ListenableFuture<T> compute() {
+ return delegate;
+ }
+ }
+}
diff --git a/producers/src/test/java/dagger/producers/internal/ProducersTest.java b/producers/src/test/java/dagger/producers/internal/ProducersTest.java
new file mode 100644
index 000000000..43564089f
--- /dev/null
+++ b/producers/src/test/java/dagger/producers/internal/ProducersTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.SettableFuture;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import javax.inject.Provider;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests {@link Producers}.
+ */
+@RunWith(JUnit4.class)
+public class ProducersTest {
+ @Test public void createFutureProduced_success() throws Exception {
+ ListenableFuture<String> future = Futures.immediateFuture("monkey");
+ ListenableFuture<Produced<String>> producedFuture = Producers.createFutureProduced(future);
+ assertThat(producedFuture.isDone()).isTrue();
+ assertThat(producedFuture.get().get()).isEqualTo("monkey");
+ }
+
+ @Test public void createFutureProduced_failure() throws Exception {
+ ListenableFuture<String> future = Futures.immediateFailedFuture(new RuntimeException("monkey"));
+ ListenableFuture<Produced<String>> producedFuture = Producers.createFutureProduced(future);
+ assertThat(producedFuture.isDone()).isTrue();
+ assertThat(getProducedException(producedFuture.get()).getCause()).hasMessage("monkey");
+ }
+
+ @Test public void createFutureProduced_cancelPropagatesBackwards() throws Exception {
+ ListenableFuture<String> future = SettableFuture.create();
+ ListenableFuture<Produced<String>> producedFuture = Producers.createFutureProduced(future);
+ assertThat(producedFuture.isDone()).isFalse();
+ producedFuture.cancel(false);
+ assertThat(future.isCancelled()).isTrue();
+ }
+
+ @Test public void createFutureProduced_cancelDoesNotPropagateForwards() throws Exception {
+ ListenableFuture<String> future = SettableFuture.create();
+ ListenableFuture<Produced<String>> producedFuture = Producers.createFutureProduced(future);
+ assertThat(producedFuture.isDone()).isFalse();
+ future.cancel(false);
+ assertThat(producedFuture.isCancelled()).isFalse();
+ assertThat(getProducedException(producedFuture.get()).getCause())
+ .isInstanceOf(CancellationException.class);
+ }
+
+ private <T> ExecutionException getProducedException(Produced<T> produced) {
+ try {
+ produced.get();
+ throw new IllegalArgumentException("produced did not throw");
+ } catch (ExecutionException e) {
+ return e;
+ }
+ }
+
+ @Test public void createFutureSingletonSet_success() throws Exception {
+ ListenableFuture<String> future = Futures.immediateFuture("monkey");
+ ListenableFuture<Set<String>> setFuture = Producers.createFutureSingletonSet(future);
+ assertThat(setFuture.isDone()).isTrue();
+ assertThat(setFuture.get()).containsExactly("monkey");
+ }
+
+ @Test public void createFutureSingletonSet_failure() throws Exception {
+ ListenableFuture<String> future = Futures.immediateFailedFuture(new RuntimeException("monkey"));
+ ListenableFuture<Set<String>> setFuture = Producers.createFutureSingletonSet(future);
+ assertThat(setFuture.isDone()).isTrue();
+ try {
+ setFuture.get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).hasMessage("monkey");
+ }
+ }
+
+ @Test public void submitToExecutor() throws Exception {
+ ListenableFuture<Integer> future = Producers.submitToExecutor(new Callable<Integer>() {
+ @Override public Integer call() {
+ return 42;
+ }
+ }, MoreExecutors.directExecutor());
+ assertThat(future.isDone()).isTrue();
+ assertThat(future.get()).isEqualTo(42);
+ }
+
+ @Test public void producerFromProvider() throws Exception {
+ Producer<Integer> producer = Producers.producerFromProvider(new Provider<Integer>() {
+ int i = 0;
+
+ @Override public Integer get() {
+ return i++;
+ }
+ });
+ assertThat(producer.get().get()).isEqualTo(0);
+ assertThat(producer.get().get()).isEqualTo(0);
+ assertThat(producer.get().get()).isEqualTo(0);
+ }
+}
diff --git a/producers/src/test/java/dagger/producers/internal/SetProducerTest.java b/producers/src/test/java/dagger/producers/internal/SetProducerTest.java
new file mode 100644
index 000000000..1f8ff7c3a
--- /dev/null
+++ b/producers/src/test/java/dagger/producers/internal/SetProducerTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Producer;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests {@link SetProducer}.
+ */
+@RunWith(JUnit4.class)
+public class SetProducerTest {
+ @Test public void success() throws Exception {
+ Producer<Set<Integer>> producer = SetProducer.create(
+ new ImmediateProducer<Set<Integer>>(ImmutableSet.of(1, 2)),
+ new ImmediateProducer<Set<Integer>>(ImmutableSet.of(5, 7)));
+ assertThat(producer.get().get()).containsExactly(1, 2, 5, 7);
+ }
+
+ @Test public void delegateSetNpe() throws Exception {
+ Producer<Set<Integer>> producer = SetProducer.create(
+ new ImmediateProducer<Set<Integer>>(ImmutableSet.of(1, 2)),
+ new ImmediateProducer<Set<Integer>>(null));
+ ListenableFuture<Set<Integer>> future = producer.get();
+ try {
+ future.get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).isInstanceOf(NullPointerException.class);
+ }
+ }
+
+ @Test public void delegateElementNpe() throws Exception {
+ Producer<Set<Integer>> producer = SetProducer.create(
+ new ImmediateProducer<Set<Integer>>(ImmutableSet.of(1, 2)),
+ new ImmediateProducer<Set<Integer>>(
+ Collections.<Integer>singleton(null)));
+ ListenableFuture<Set<Integer>> future = producer.get();
+ try {
+ future.get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).isInstanceOf(NullPointerException.class);
+ }
+ }
+
+ private static final class ImmediateProducer<T> implements Producer<T> {
+ private final T value;
+
+ ImmediateProducer(T value) {
+ this.value = value;
+ }
+
+ @Override public ListenableFuture<T> get() {
+ return Futures.immediateFuture(value);
+ }
+ }
+}
diff --git a/util/generate-latest-docs.sh b/util/generate-latest-docs.sh
new file mode 100755
index 000000000..b68df0c4a
--- /dev/null
+++ b/util/generate-latest-docs.sh
@@ -0,0 +1,25 @@
+# see http://benlimmer.com/2013/12/26/automatically-publish-javadoc-to-gh-pages-with-travis-ci/ for details
+
+if [ "$TRAVIS_REPO_SLUG" == "google/dagger" ] && \
+ [ "$TRAVIS_JDK_VERSION" == "oraclejdk7" ] && \
+ [ "$TRAVIS_PULL_REQUEST" == "false" ] && \
+ [ "$TRAVIS_BRANCH" == "master" ]; then
+ echo -e "Publishing javadoc...\n"
+ mvn javadoc:aggregate -P!examples
+ TARGET="$(pwd)/target"
+
+ cd $HOME
+ git clone --quiet --branch=gh-pages https://${GH_TOKEN}@github.com/google/dagger gh-pages > /dev/null
+
+ cd gh-pages
+ git config --global user.email "travis@travis-ci.org"
+ git config --global user.name "travis-ci"
+ git rm -rf api/latest
+ mkdir -p api
+ mv ${TARGET}/site/apidocs api/latest
+ git add -f api/latest
+ git commit -m "Lastest javadoc on successful travis build $TRAVIS_BUILD_NUMBER auto-pushed to gh-pages"
+ git push -fq origin gh-pages > /dev/null
+
+ echo -e "Published Javadoc to gh-pages.\n"
+fi
diff --git a/util/mvn-deploy.sh b/util/mvn-deploy.sh
new file mode 100755
index 000000000..ec4b7a0d2
--- /dev/null
+++ b/util/mvn-deploy.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+if [ $# -lt 1 ]; then
+ echo "usage $0 <ssl-key> [<param> ...]"
+ exit 1;
+fi
+key=$1
+shift
+
+#validate key
+keystatus=$(gpg --list-keys | grep ${key} | awk '{print $1}')
+if [ "${keystatus}" != "pub" ]; then
+ echo "Could not find public key with label ${key}"
+ echo -n "Available keys from: "
+ gpg --list-keys | grep --invert-match '^sub'
+
+ exit 64
+fi
+
+mvn "$@" -P '!examples' -P sonatype-oss-release \
+ -Dgpg.skip=false -Dgpg.keyname=${key} \
+ clean site:jar deploy
diff --git a/util/publish-snapshot-on-commit.sh b/util/publish-snapshot-on-commit.sh
new file mode 100755
index 000000000..be27cb6e0
--- /dev/null
+++ b/util/publish-snapshot-on-commit.sh
@@ -0,0 +1,12 @@
+# see https://coderwall.com/p/9b_lfq
+
+if [ "$TRAVIS_REPO_SLUG" == "google/dagger" ] && \
+ [ "$TRAVIS_JDK_VERSION" == "oraclejdk7" ] && \
+ [ "$TRAVIS_PULL_REQUEST" == "false" ] && \
+ [ "$TRAVIS_BRANCH" == "master" ]; then
+ echo -e "Publishing maven snapshot...\n"
+
+ mvn clean source:jar deploy --settings="util/settings.xml" -DskipTests=true -Dinvoker.skip=true -Dmaven.javadoc.skip=true
+
+ echo -e "Published maven snapshot"
+fi
diff --git a/util/settings.xml b/util/settings.xml
new file mode 100644
index 000000000..91f444b22
--- /dev/null
+++ b/util/settings.xml
@@ -0,0 +1,9 @@
+<settings>
+ <servers>
+ <server>
+ <id>sonatype-nexus-snapshots</id>
+ <username>${env.CI_DEPLOY_USERNAME}</username>
+ <password>${env.CI_DEPLOY_PASSWORD}</password>
+ </server>
+ </servers>
+</settings>