• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Dagger Authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package dagger.internal.codegen;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static org.junit.Assert.assertThrows;
21 
22 import androidx.room.compiler.processing.util.CompilationResultSubject;
23 import androidx.room.compiler.processing.util.Source;
24 import com.google.common.collect.ImmutableList;
25 import com.google.common.collect.ImmutableMap;
26 import com.squareup.javapoet.AnnotationSpec;
27 import com.squareup.javapoet.MethodSpec;
28 import com.squareup.javapoet.TypeSpec;
29 import dagger.MembersInjector;
30 import dagger.internal.codegen.javapoet.TypeNames;
31 import dagger.testing.compile.CompilerTests;
32 import dagger.testing.golden.GoldenFileRule;
33 import java.util.Collection;
34 import javax.inject.Inject;
35 import javax.tools.Diagnostic;
36 import org.junit.Rule;
37 import org.junit.Test;
38 import org.junit.runner.RunWith;
39 import org.junit.runners.Parameterized;
40 import org.junit.runners.Parameterized.Parameters;
41 
42 @RunWith(Parameterized.class)
43 public class ComponentProcessorTest {
44   @Parameters(name = "{0}")
parameters()45   public static Collection<Object[]> parameters() {
46     return CompilerMode.TEST_PARAMETERS;
47   }
48 
49   private static final TypeSpec GENERATED_INJECT_TYPE =
50       TypeSpec.classBuilder("GeneratedInjectType")
51           .addMethod(
52               MethodSpec.constructorBuilder()
53                   .addAnnotation(TypeNames.INJECT_JAVAX)
54                   .build())
55           .build();
56 
57   private static final TypeSpec GENERATED_QUALIFIER =
58       TypeSpec.annotationBuilder("GeneratedQualifier")
59           .addAnnotation(AnnotationSpec.builder(TypeNames.QUALIFIER_JAVAX).build())
60           .build();
61 
62   private static final TypeSpec GENERATED_MODULE =
63       TypeSpec.classBuilder("GeneratedModule").addAnnotation(TypeNames.MODULE).build();
64 
65 
66   @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule();
67 
68   private final CompilerMode compilerMode;
69 
ComponentProcessorTest(CompilerMode compilerMode)70   public ComponentProcessorTest(CompilerMode compilerMode) {
71     this.compilerMode = compilerMode;
72   }
73 
74   @Test
doubleBindingFromResolvedModules()75   public void doubleBindingFromResolvedModules() {
76     Source parent = CompilerTests.javaSource("test.ParentModule",
77             "package test;",
78             "",
79             "import dagger.Module;",
80             "import dagger.Provides;",
81             "import java.util.List;",
82             "",
83             "@Module",
84             "abstract class ParentModule<A> {",
85             "  @Provides List<A> provideListB(A a) { return null; }",
86             "}");
87     Source child = CompilerTests.javaSource("test.ChildNumberModule",
88             "package test;",
89             "",
90             "import dagger.Module;",
91             "import dagger.Provides;",
92             "",
93             "@Module",
94             "class ChildNumberModule extends ParentModule<Integer> {",
95             "  @Provides Integer provideInteger() { return null; }",
96             "}");
97     Source another = CompilerTests.javaSource("test.AnotherModule",
98             "package test;",
99             "",
100             "import dagger.Module;",
101             "import dagger.Provides;",
102             "import java.util.List;",
103             "",
104             "@Module",
105             "class AnotherModule {",
106             "  @Provides List<Integer> provideListOfInteger() { return null; }",
107             "}");
108     Source componentFile = CompilerTests.javaSource("test.BadComponent",
109             "package test;",
110             "",
111             "import dagger.Component;",
112             "import java.util.List;",
113             "",
114             "@Component(modules = {ChildNumberModule.class, AnotherModule.class})",
115             "interface BadComponent {",
116             "  List<Integer> listOfInteger();",
117             "}");
118 
119     CompilerTests.daggerCompiler(parent, child, another, componentFile)
120         .withProcessingOptions(compilerMode.processorOptions())
121         .compile(
122             subject -> {
123               subject.hasErrorCount(1);
124               subject.hasErrorContaining("List<Integer> is bound multiple times");
125               subject.hasErrorContaining(
126                   "@Provides List<Integer> ChildNumberModule.provideListB(Integer)");
127               subject.hasErrorContaining(
128                   "@Provides List<Integer> AnotherModule.provideListOfInteger()");
129             });
130   }
131 
132   @Test
privateNestedClassWithWarningThatIsAnErrorInComponent()133   public void privateNestedClassWithWarningThatIsAnErrorInComponent() {
134     Source outerClass = CompilerTests.javaSource("test.OuterClass",
135             "package test;",
136             "",
137             "import javax.inject.Inject;",
138             "",
139             "final class OuterClass {",
140             "  @Inject OuterClass(InnerClass innerClass) {}",
141             "",
142             "  private static final class InnerClass {",
143             "    @Inject InnerClass() {}",
144             "  }",
145             "}");
146     Source componentFile = CompilerTests.javaSource("test.BadComponent",
147             "package test;",
148             "",
149             "import dagger.Component;",
150             "",
151             "@Component",
152             "interface BadComponent {",
153             "  OuterClass outerClass();",
154             "}");
155     CompilerTests.daggerCompiler(outerClass, componentFile)
156         .withProcessingOptions(
157             ImmutableMap.<String, String>builder()
158                 .putAll(compilerMode.processorOptions())
159                 .put("dagger.privateMemberValidation", "WARNING")
160                 .buildOrThrow())
161         .compile(
162             subject ->
163                 // Because it is just a warning until it is used, the factory still gets generated
164                 // which has errors from referencing the private class, so there are extra errors.
165                 // Hence we don't assert on the number of errors.
166                 subject.hasErrorContaining(
167                     "Dagger does not support injection into private classes"));
168   }
169 
170   @Test
simpleComponent()171   public void simpleComponent() throws Exception {
172     Source injectableTypeFile = CompilerTests.javaSource("test/SomeInjectableType",
173             "package test;",
174             "",
175             "import javax.inject.Inject;",
176             "",
177             "final class SomeInjectableType {",
178             "  @Inject SomeInjectableType() {}",
179             "}");
180     Source componentFile = CompilerTests.javaSource("test/SimpleComponent",
181             "package test;",
182             "",
183             "import dagger.Component;",
184             "import dagger.Lazy;",
185             "import javax.inject.Provider;",
186             "",
187             "@Component",
188             "interface SimpleComponent {",
189             "  SomeInjectableType someInjectableType();",
190             "  Lazy<SomeInjectableType> lazySomeInjectableType();",
191             "  Provider<SomeInjectableType> someInjectableTypeProvider();",
192             "}");
193 
194     CompilerTests.daggerCompiler(injectableTypeFile, componentFile)
195         .withProcessingOptions(compilerMode.processorOptions())
196         .compile(
197             subject -> {
198               subject.hasErrorCount(0);
199               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent"));
200             });
201   }
202 
203   @Test
componentWithScope()204   public void componentWithScope() throws Exception {
205     Source injectableTypeFile = CompilerTests.javaSource("test.SomeInjectableType",
206             "package test;",
207             "",
208             "import javax.inject.Inject;",
209             "import javax.inject.Singleton;",
210             "",
211             "@Singleton",
212             "final class SomeInjectableType {",
213             "  @Inject SomeInjectableType() {}",
214             "}");
215     Source componentFile = CompilerTests.javaSource("test.SimpleComponent",
216             "package test;",
217             "",
218             "import dagger.Component;",
219             "import dagger.Lazy;",
220             "import javax.inject.Provider;",
221             "import javax.inject.Singleton;",
222             "",
223             "@Singleton",
224             "@Component",
225             "interface SimpleComponent {",
226             "  SomeInjectableType someInjectableType();",
227             "  Lazy<SomeInjectableType> lazySomeInjectableType();",
228             "  Provider<SomeInjectableType> someInjectableTypeProvider();",
229             "}");
230 
231     CompilerTests.daggerCompiler(injectableTypeFile, componentFile)
232         .withProcessingOptions(compilerMode.processorOptions())
233         .compile(
234             subject -> {
235               subject.hasErrorCount(0);
236               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent"));
237             });
238   }
239 
240   @Test
simpleComponentWithNesting()241   public void simpleComponentWithNesting() throws Exception {
242     Source nestedTypesFile = CompilerTests.javaSource("test.OuterType",
243             "package test;",
244             "",
245             "import dagger.Component;",
246             "import javax.inject.Inject;",
247             "",
248             "final class OuterType {",
249             "  static class A {",
250             "    @Inject A() {}",
251             "  }",
252             "  static class B {",
253             "    @Inject A a;",
254             "  }",
255             "  @Component interface SimpleComponent {",
256             "    A a();",
257             "    void inject(B b);",
258             "  }",
259             "}");
260 
261     CompilerTests.daggerCompiler(nestedTypesFile)
262         .withProcessingOptions(compilerMode.processorOptions())
263         .compile(
264             subject -> {
265               subject.hasErrorCount(0);
266               subject.generatedSource(
267                   goldenFileRule.goldenSource("test/DaggerOuterType_SimpleComponent"));
268             });
269   }
270 
271   @Test
componentWithModule()272   public void componentWithModule() throws Exception {
273     Source aFile = CompilerTests.javaSource("test.A",
274             "package test;",
275             "",
276             "import javax.inject.Inject;",
277             "",
278             "final class A {",
279             "  @Inject A(B b) {}",
280             "}");
281     Source bFile = CompilerTests.javaSource("test.B",
282         "package test;",
283         "",
284         "interface B {}");
285     Source cFile = CompilerTests.javaSource("test.C",
286             "package test;",
287             "",
288             "import javax.inject.Inject;",
289             "",
290             "final class C {",
291             "  @Inject C() {}",
292             "}");
293 
294     Source moduleFile = CompilerTests.javaSource("test.TestModule",
295             "package test;",
296             "",
297             "import dagger.Module;",
298             "import dagger.Provides;",
299             "",
300             "@Module",
301             "final class TestModule {",
302             "  @Provides B b(C c) { return null; }",
303             "}");
304 
305     Source componentFile = CompilerTests.javaSource("test.TestComponent",
306             "package test;",
307             "",
308             "import dagger.Component;",
309             "import javax.inject.Provider;",
310             "",
311             "@Component(modules = TestModule.class)",
312             "interface TestComponent {",
313             "  A a();",
314             "}");
315 
316     CompilerTests.daggerCompiler(aFile, bFile, cFile, moduleFile, componentFile)
317         .withProcessingOptions(compilerMode.processorOptions())
318         .compile(
319             subject -> {
320               subject.hasErrorCount(0);
321               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
322             });
323   }
324 
325   @Test
componentWithAbstractModule()326   public void componentWithAbstractModule() throws Exception {
327     Source aFile = CompilerTests.javaSource(
328             "test.A",
329             "package test;",
330             "",
331             "import javax.inject.Inject;",
332             "",
333             "final class A {",
334             "  @Inject A(B b) {}",
335             "}");
336     Source bFile = CompilerTests.javaSource("test.B",
337             "package test;",
338             "",
339             "interface B {}");
340     Source cFile = CompilerTests.javaSource(
341             "test.C",
342             "package test;",
343             "",
344             "import javax.inject.Inject;",
345             "",
346             "final class C {",
347             "  @Inject C() {}",
348             "}");
349 
350     Source moduleFile = CompilerTests.javaSource(
351             "test.TestModule",
352             "package test;",
353             "",
354             "import dagger.Module;",
355             "import dagger.Provides;",
356             "",
357             "@Module",
358             "abstract class TestModule {",
359             "  @Provides static B b(C c) { return null; }",
360             "}");
361 
362     Source componentFile = CompilerTests.javaSource(
363             "test.TestComponent",
364             "package test;",
365             "",
366             "import dagger.Component;",
367             "",
368             "@Component(modules = TestModule.class)",
369             "interface TestComponent {",
370             "  A a();",
371             "}");
372 
373     CompilerTests.daggerCompiler(aFile, bFile, cFile, moduleFile, componentFile)
374         .withProcessingOptions(compilerMode.processorOptions())
375         .compile(
376             subject -> {
377               subject.hasErrorCount(0);
378               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
379             });
380   }
381 
382   @Test
transitiveModuleDeps()383   public void transitiveModuleDeps() throws Exception {
384     Source always = CompilerTests.javaSource("test.AlwaysIncluded",
385             "package test;",
386             "",
387             "import dagger.Module;",
388             "",
389             "@Module",
390             "final class AlwaysIncluded {}");
391     Source testModule = CompilerTests.javaSource("test.TestModule",
392             "package test;",
393             "",
394             "import dagger.Module;",
395             "",
396             "@Module(includes = {DepModule.class, AlwaysIncluded.class})",
397             "final class TestModule extends ParentTestModule {}");
398     Source parentTest = CompilerTests.javaSource("test.ParentTestModule",
399             "package test;",
400             "",
401             "import dagger.Module;",
402             "",
403             "@Module(includes = {ParentTestIncluded.class, AlwaysIncluded.class})",
404             "class ParentTestModule {}");
405     Source parentTestIncluded = CompilerTests.javaSource("test.ParentTestIncluded",
406             "package test;",
407             "",
408             "import dagger.Module;",
409             "",
410             "@Module(includes = AlwaysIncluded.class)",
411             "final class ParentTestIncluded {}");
412     Source depModule = CompilerTests.javaSource("test.DepModule",
413             "package test;",
414             "",
415             "import dagger.Module;",
416             "",
417             "@Module(includes = {RefByDep.class, AlwaysIncluded.class})",
418             "final class DepModule extends ParentDepModule {}");
419     Source refByDep = CompilerTests.javaSource("test.RefByDep",
420             "package test;",
421             "",
422             "import dagger.Module;",
423             "",
424             "@Module(includes = AlwaysIncluded.class)",
425             "final class RefByDep extends ParentDepModule {}");
426     Source parentDep = CompilerTests.javaSource("test.ParentDepModule",
427             "package test;",
428             "",
429             "import dagger.Module;",
430             "",
431             "@Module(includes = {ParentDepIncluded.class, AlwaysIncluded.class})",
432             "class ParentDepModule {}");
433     Source parentDepIncluded = CompilerTests.javaSource("test.ParentDepIncluded",
434             "package test;",
435             "",
436             "import dagger.Module;",
437             "",
438             "@Module(includes = AlwaysIncluded.class)",
439             "final class ParentDepIncluded {}");
440 
441     Source componentFile = CompilerTests.javaSource("test.TestComponent",
442             "package test;",
443             "",
444             "import dagger.Component;",
445             "",
446             "@Component(modules = TestModule.class)",
447             "interface TestComponent {",
448             "}");
449 
450     CompilerTests.daggerCompiler(
451             always,
452             testModule,
453             parentTest,
454             parentTestIncluded,
455             depModule,
456             refByDep,
457             parentDep,
458             parentDepIncluded,
459             componentFile)
460         .withProcessingOptions(compilerMode.processorOptions())
461         .compile(
462             subject -> {
463               subject.hasErrorCount(0);
464               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
465             });
466   }
467 
468   @Test
generatedTransitiveModule()469   public void generatedTransitiveModule() {
470     Source rootModule =
471         CompilerTests.javaSource(
472             "test.RootModule",
473             "package test;",
474             "",
475             "import dagger.Module;",
476             "",
477             "@Module(includes = GeneratedModule.class)",
478             "final class RootModule {}");
479     Source component =
480         CompilerTests.javaSource(
481             "test.TestComponent",
482             "package test;",
483             "",
484             "import dagger.Component;",
485             "",
486             "@Component(modules = RootModule.class)",
487             "interface TestComponent {}");
488 
489     CompilerTests.daggerCompiler(rootModule, component)
490         .withProcessingOptions(compilerMode.processorOptions())
491         .compile(subject -> subject.hasError());
492 
493     CompilerTests.daggerCompiler(rootModule, component)
494         .withProcessingOptions(compilerMode.processorOptions())
495         .withProcessingSteps(() -> new GeneratingProcessingStep("test", GENERATED_MODULE))
496         .compile(subject -> subject.hasErrorCount(0));
497   }
498 
499   @Test
generatedModuleInSubcomponent()500   public void generatedModuleInSubcomponent() {
501     Source subcomponent =
502         CompilerTests.javaSource(
503             "test.ChildComponent",
504             "package test;",
505             "",
506             "import dagger.Subcomponent;",
507             "",
508             "@Subcomponent(modules = GeneratedModule.class)",
509             "interface ChildComponent {}");
510     Source component =
511         CompilerTests.javaSource(
512             "test.TestComponent",
513             "package test;",
514             "",
515             "import dagger.Component;",
516             "",
517             "@Component",
518             "interface TestComponent {",
519             "  ChildComponent childComponent();",
520             "}");
521     CompilerTests.daggerCompiler(subcomponent, component)
522         .withProcessingOptions(compilerMode.processorOptions())
523         .compile(subject -> subject.hasError());
524 
525     CompilerTests.daggerCompiler(subcomponent, component)
526         .withProcessingOptions(compilerMode.processorOptions())
527         .withProcessingSteps(() -> new GeneratingProcessingStep("test", GENERATED_MODULE))
528         .compile(subject -> subject.hasErrorCount(0));
529   }
530 
531   @Test
subcomponentNotGeneratedIfNotUsedInGraph()532   public void subcomponentNotGeneratedIfNotUsedInGraph() throws Exception {
533     Source component =
534         CompilerTests.javaSource(
535             "test.Parent",
536             "package test;",
537             "",
538             "import dagger.Component;",
539             "",
540             "@Component(modules = ParentModule.class)",
541             "interface Parent {",
542             "  String notSubcomponent();",
543             "}");
544     Source module =
545         CompilerTests.javaSource(
546             "test.ParentModule",
547             "package test;",
548             "",
549             "import dagger.Module;",
550             "import dagger.Provides;",
551             "",
552             "@Module(subcomponents = Child.class)",
553             "class ParentModule {",
554             "  @Provides static String notSubcomponent() { return new String(); }",
555             "}");
556 
557     Source subcomponent =
558         CompilerTests.javaSource(
559             "test.Child",
560             "package test;",
561             "",
562             "import dagger.Subcomponent;",
563             "",
564             "@Subcomponent",
565             "interface Child {",
566             "  @Subcomponent.Builder",
567             "  interface Builder {",
568             "    Child build();",
569             "  }",
570             "}");
571 
572     CompilerTests.daggerCompiler(component, module, subcomponent)
573         .withProcessingOptions(compilerMode.processorOptions())
574         .compile(
575             subject -> {
576               subject.hasErrorCount(0);
577               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerParent"));
578             });
579   }
580 
581   @Test
testDefaultPackage()582   public void testDefaultPackage() {
583     Source aClass = CompilerTests.javaSource("AClass", "class AClass {}");
584     Source bClass = CompilerTests.javaSource("BClass",
585             "import javax.inject.Inject;",
586             "",
587             "class BClass {",
588             "  @Inject BClass(AClass a) {}",
589             "}");
590     Source aModule = CompilerTests.javaSource("AModule",
591             "import dagger.Module;",
592             "import dagger.Provides;",
593             "",
594             "@Module class AModule {",
595             "  @Provides AClass aClass() {",
596             "    return new AClass();",
597             "  }",
598             "}");
599     Source component = CompilerTests.javaSource("SomeComponent",
600             "import dagger.Component;",
601             "",
602             "@Component(modules = AModule.class)",
603             "interface SomeComponent {",
604             "  BClass bClass();",
605             "}");
606 
607     CompilerTests.daggerCompiler(aModule, aClass, bClass, component)
608         .withProcessingOptions(compilerMode.processorOptions())
609         .compile(subject -> subject.hasErrorCount(0));
610   }
611 
612   @Test
membersInjection()613   public void membersInjection() throws Exception {
614     Source injectableTypeFile = CompilerTests.javaSource("test.SomeInjectableType",
615             "package test;",
616             "",
617             "import javax.inject.Inject;",
618             "",
619             "final class SomeInjectableType {",
620             "  @Inject SomeInjectableType() {}",
621             "}");
622     Source injectedTypeFile = CompilerTests.javaSource("test.SomeInjectedType",
623             "package test;",
624             "",
625             "import javax.inject.Inject;",
626             "",
627             "final class SomeInjectedType {",
628             "  @Inject SomeInjectableType injectedField;",
629             "  SomeInjectedType() {}",
630             "}");
631     Source componentFile = CompilerTests.javaSource("test.SimpleComponent",
632             "package test;",
633             "",
634             "import dagger.Component;",
635             "import dagger.Lazy;",
636             "import javax.inject.Provider;",
637             "",
638             "@Component",
639             "interface SimpleComponent {",
640             "  void inject(SomeInjectedType instance);",
641             "  SomeInjectedType injectAndReturn(SomeInjectedType instance);",
642             "}");
643 
644     CompilerTests.daggerCompiler(injectableTypeFile, injectedTypeFile, componentFile)
645         .withProcessingOptions(compilerMode.processorOptions())
646         .compile(
647             subject -> {
648               subject.hasErrorCount(0);
649               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent"));
650             });
651   }
652 
653   @Test
componentInjection()654   public void componentInjection() throws Exception {
655     Source injectableTypeFile =
656         CompilerTests.javaSource(
657             "test.SomeInjectableType",
658             "package test;",
659             "",
660             "import javax.inject.Inject;",
661             "",
662             "final class SomeInjectableType {",
663             "  @Inject SomeInjectableType(SimpleComponent component) {}",
664             "}");
665     Source componentFile =
666         CompilerTests.javaSource(
667             "test.SimpleComponent",
668             "package test;",
669             "",
670             "import dagger.Component;",
671             "import dagger.Lazy;",
672             "import javax.inject.Provider;",
673             "",
674             "@Component",
675             "interface SimpleComponent {",
676             "  SomeInjectableType someInjectableType();",
677             "  Provider<SimpleComponent> selfProvider();",
678             "}");
679 
680     CompilerTests.daggerCompiler(injectableTypeFile, componentFile)
681         .withProcessingOptions(compilerMode.processorOptions())
682         .compile(
683             subject -> {
684               subject.hasErrorCount(0);
685               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent"));
686             });
687   }
688 
689   @Test
membersInjectionInsideProvision()690   public void membersInjectionInsideProvision() throws Exception {
691     Source injectableTypeFile =
692         CompilerTests.javaSource(
693             "test.SomeInjectableType",
694             "package test;",
695             "",
696             "import javax.inject.Inject;",
697             "",
698             "final class SomeInjectableType {",
699             "  @Inject SomeInjectableType() {}",
700             "}");
701     Source injectedTypeFile =
702         CompilerTests.javaSource(
703             "test.SomeInjectedType",
704             "package test;",
705             "",
706             "import javax.inject.Inject;",
707             "",
708             "final class SomeInjectedType {",
709             "  @Inject SomeInjectableType injectedField;",
710             "  @Inject SomeInjectedType() {}",
711             "}");
712     Source componentFile =
713         CompilerTests.javaSource(
714             "test.SimpleComponent",
715             "package test;",
716             "",
717             "import dagger.Component;",
718             "",
719             "@Component",
720             "interface SimpleComponent {",
721             "  SomeInjectedType createAndInject();",
722             "}");
723     CompilerTests.daggerCompiler(injectableTypeFile, injectedTypeFile, componentFile)
724         .withProcessingOptions(compilerMode.processorOptions())
725         .compile(
726           subject -> {
727             subject.hasErrorCount(0);
728             subject.generatedSourceFileWithPath("test/DaggerSimpleComponent.java");
729           });
730   }
731 
732   @Test
componentDependency()733   public void componentDependency() throws Exception {
734     Source aFile = CompilerTests.javaSource("test.A",
735             "package test;",
736             "",
737             "import javax.inject.Inject;",
738             "",
739             "final class A {",
740             "  @Inject A() {}",
741             "}");
742     Source bFile = CompilerTests.javaSource("test.B",
743             "package test;",
744             "",
745             "import javax.inject.Inject;",
746             "import javax.inject.Provider;",
747             "",
748             "final class B {",
749             "  @Inject B(Provider<A> a) {}",
750             "}");
751     Source aComponentFile = CompilerTests.javaSource("test.AComponent",
752             "package test;",
753             "",
754             "import dagger.Component;",
755             "",
756             "@Component",
757             "interface AComponent {",
758             "  A a();",
759             "}");
760     Source bComponentFile = CompilerTests.javaSource("test.BComponent",
761             "package test;",
762             "",
763             "import dagger.Component;",
764             "",
765             "@Component(dependencies = AComponent.class)",
766             "interface BComponent {",
767             "  B b();",
768             "}");
769 
770     CompilerTests.daggerCompiler(aFile, bFile, aComponentFile, bComponentFile)
771         .withProcessingOptions(compilerMode.processorOptions())
772         .compile(
773             subject -> {
774               subject.hasErrorCount(0);
775               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerBComponent"));
776             });
777   }
778 
779   @Test
primitiveComponentDependency()780   public void primitiveComponentDependency() throws Exception {
781     Source bFile = CompilerTests.javaSource("test.B",
782             "package test;",
783             "",
784             "import javax.inject.Inject;",
785             "import javax.inject.Provider;",
786             "",
787             "final class B {",
788             "  @Inject B(Provider<Integer> i) {}",
789             "}");
790     Source intComponentFile = CompilerTests.javaSource("test.IntComponent",
791             "package test;",
792             "",
793             "interface IntComponent {",
794             "  int i();",
795             "}");
796     Source bComponentFile = CompilerTests.javaSource("test.BComponent",
797             "package test;",
798             "",
799             "import dagger.Component;",
800             "",
801             "@Component(dependencies = IntComponent.class)",
802             "interface BComponent {",
803             "  B b();",
804             "}");
805 
806     CompilerTests.daggerCompiler(bFile, intComponentFile, bComponentFile)
807         .withProcessingOptions(compilerMode.processorOptions())
808         .compile(
809             subject -> {
810               subject.hasErrorCount(0);
811               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerBComponent"));
812             });
813   }
814 
815   @Test
arrayComponentDependency()816   public void arrayComponentDependency() throws Exception {
817     Source bFile = CompilerTests.javaSource("test.B",
818             "package test;",
819             "",
820             "import javax.inject.Inject;",
821             "import javax.inject.Provider;",
822             "",
823             "final class B {",
824             "  @Inject B(Provider<String[]> i) {}",
825             "}");
826     Source arrayComponentFile = CompilerTests.javaSource("test.ArrayComponent",
827             "package test;",
828             "",
829             "interface ArrayComponent {",
830             "  String[] strings();",
831             "}");
832     Source bComponentFile = CompilerTests.javaSource("test.BComponent",
833             "package test;",
834             "",
835             "import dagger.Component;",
836             "",
837             "@Component(dependencies = ArrayComponent.class)",
838             "interface BComponent {",
839             "  B b();",
840             "}");
841 
842     CompilerTests.daggerCompiler(bFile, arrayComponentFile, bComponentFile)
843         .withProcessingOptions(compilerMode.processorOptions())
844         .compile(
845             subject -> {
846               subject.hasErrorCount(0);
847               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerBComponent"));
848             });
849   }
850 
851   @Test
dependencyNameCollision()852   public void dependencyNameCollision() throws Exception {
853     Source a1 = CompilerTests.javaSource("pkg1.A",
854             "package pkg1;",
855             "",
856             "import javax.inject.Inject;",
857             "",
858             "public final class A {",
859             "  @Inject A() {}",
860             "}");
861     Source a2 = CompilerTests.javaSource("pkg2.A",
862             "package pkg2;",
863             "",
864             "import javax.inject.Inject;",
865             "",
866             "public final class A {",
867             "  @Inject A() {}",
868             "}");
869     Source a1Component = CompilerTests.javaSource("pkg1.AComponent",
870             "package pkg1;",
871             "",
872             "import dagger.Component;",
873             "",
874             "@Component",
875             "public interface AComponent {",
876             "  A a();",
877             "}");
878     Source a2Component = CompilerTests.javaSource("pkg2.AComponent",
879             "package pkg2;",
880             "",
881             "import dagger.Component;",
882             "",
883             "@Component",
884             "public interface AComponent {",
885             "  A a();",
886             "}");
887     Source bComponent = CompilerTests.javaSource("test.BComponent",
888             "package test;",
889             "",
890             "import dagger.Component;",
891             "",
892             "@Component(dependencies = {pkg1.AComponent.class, pkg2.AComponent.class})",
893             "interface BComponent {",
894             "  B b();",
895             "}");
896     Source b = CompilerTests.javaSource("test.B",
897             "package test;",
898             "",
899             "import javax.inject.Inject;",
900             "import javax.inject.Provider;",
901             "",
902             "final class B {",
903             "  @Inject B(Provider<pkg1.A> a1, Provider<pkg2.A> a2) {}",
904             "}");
905 
906     CompilerTests.daggerCompiler(a1, a2, b, a1Component, a2Component, bComponent)
907         .withProcessingOptions(compilerMode.processorOptions())
908         .compile(
909             subject -> {
910               subject.hasErrorCount(0);
911               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerBComponent"));
912             });
913   }
914 
915   @Test
moduleNameCollision()916   public void moduleNameCollision() throws Exception {
917     Source aFile =
918         CompilerTests.javaSource(
919             "test.A",
920             "package test;",
921             "",
922             "public final class A {}");
923     Source otherAFile =
924         CompilerTests.javaSource(
925             "other.test.A",
926             "package other.test;",
927             "",
928             "public final class A {}");
929     Source moduleFile =
930         CompilerTests.javaSource(
931             "test.TestModule",
932             "package test;",
933             "",
934             "import dagger.Module;",
935             "import dagger.Provides;",
936             "",
937             "@Module",
938             "public final class TestModule {",
939             "  @Provides A a() { return null; }",
940             "}");
941     Source otherModuleFile =
942         CompilerTests.javaSource(
943             "other.test.TestModule",
944             "package other.test;",
945             "",
946             "import dagger.Module;",
947             "import dagger.Provides;",
948             "",
949             "@Module",
950             "public final class TestModule {",
951             "  @Provides A a() { return null; }",
952             "}");
953     Source componentFile =
954         CompilerTests.javaSource(
955             "test.TestComponent",
956             "package test;",
957             "",
958             "import dagger.Component;",
959             "import javax.inject.Provider;",
960             "",
961             "@Component(modules = {TestModule.class, other.test.TestModule.class})",
962             "interface TestComponent {",
963             "  A a();",
964             "  other.test.A otherA();",
965             "}");
966     CompilerTests.daggerCompiler(aFile, otherAFile, moduleFile, otherModuleFile, componentFile)
967         .withProcessingOptions(compilerMode.processorOptions())
968         .compile(
969             subject -> {
970               subject.hasErrorCount(0);
971               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
972             });
973   }
974 
975   @Test
ignoresDependencyMethodsFromObject()976   public void ignoresDependencyMethodsFromObject() throws Exception {
977     Source injectedTypeFile =
978         CompilerTests.javaSource(
979             "test.InjectedType",
980             "package test;",
981             "",
982             "import javax.inject.Inject;",
983             "import javax.inject.Provider;",
984             "",
985             "final class InjectedType {",
986             "  @Inject InjectedType(",
987             "      String stringInjection,",
988             "      int intInjection,",
989             "      AComponent aComponent,",
990             "      Class<AComponent> aClass) {}",
991             "}");
992     Source aComponentFile =
993         CompilerTests.javaSource(
994             "test.AComponent",
995             "package test;",
996             "",
997             "class AComponent {",
998             "  String someStringInjection() {",
999             "    return \"injectedString\";",
1000             "  }",
1001             "",
1002             "  int someIntInjection() {",
1003             "    return 123;",
1004             "  }",
1005             "",
1006             "  Class<AComponent> someClassInjection() {",
1007             "    return AComponent.class;",
1008             "  }",
1009             "",
1010             "  @Override",
1011             "  public String toString() {",
1012             "    return null;",
1013             "  }",
1014             "",
1015             "  @Override",
1016             "  public int hashCode() {",
1017             "    return 456;",
1018             "  }",
1019             "",
1020             "  @Override",
1021             "  public AComponent clone() {",
1022             "    return null;",
1023             "  }",
1024             "}");
1025     Source bComponentFile =
1026         CompilerTests.javaSource(
1027             "test.BComponent",
1028             "package test;",
1029             "",
1030             "import dagger.Component;",
1031             "",
1032             "@Component(dependencies = AComponent.class)",
1033             "interface BComponent {",
1034             "  InjectedType injectedType();",
1035             "}");
1036 
1037     CompilerTests.daggerCompiler(injectedTypeFile, aComponentFile, bComponentFile)
1038         .withProcessingOptions(compilerMode.processorOptions())
1039         .compile(
1040             subject -> {
1041               subject.hasErrorCount(0);
1042               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerBComponent"));
1043             });
1044   }
1045 
1046   @Test
resolutionOrder()1047   public void resolutionOrder() throws Exception {
1048     Source aFile = CompilerTests.javaSource("test.A",
1049             "package test;",
1050             "",
1051             "import javax.inject.Inject;",
1052             "",
1053             "final class A {",
1054             "  @Inject A(B b) {}",
1055             "}");
1056     Source bFile = CompilerTests.javaSource("test.B",
1057             "package test;",
1058             "",
1059             "import javax.inject.Inject;",
1060             "",
1061             "final class B {",
1062             "  @Inject B(C c) {}",
1063             "}");
1064     Source cFile = CompilerTests.javaSource("test.C",
1065             "package test;",
1066             "",
1067             "import javax.inject.Inject;",
1068             "",
1069             "final class C {",
1070             "  @Inject C() {}",
1071             "}");
1072     Source xFile = CompilerTests.javaSource("test.X",
1073             "package test;",
1074             "",
1075             "import javax.inject.Inject;",
1076             "",
1077             "final class X {",
1078             "  @Inject X(C c) {}",
1079             "}");
1080 
1081     Source componentFile = CompilerTests.javaSource("test.TestComponent",
1082             "package test;",
1083             "",
1084             "import dagger.Component;",
1085             "import javax.inject.Provider;",
1086             "",
1087             "@Component",
1088             "interface TestComponent {",
1089             "  A a();",
1090             "  C c();",
1091             "  X x();",
1092             "}");
1093     CompilerTests.daggerCompiler(aFile, bFile, cFile, xFile, componentFile)
1094         .withProcessingOptions(compilerMode.processorOptions())
1095         .compile(
1096             subject -> {
1097               subject.hasErrorCount(0);
1098               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
1099             });
1100   }
1101 
1102   @Test
simpleComponent_redundantComponentMethod()1103   public void simpleComponent_redundantComponentMethod() throws Exception {
1104     Source injectableTypeFile =
1105         CompilerTests.javaSource(
1106             "test.SomeInjectableType",
1107             "package test;",
1108             "",
1109             "import javax.inject.Inject;",
1110             "",
1111             "final class SomeInjectableType {",
1112             "  @Inject SomeInjectableType() {}",
1113             "}");
1114     Source componentSupertypeAFile =
1115         CompilerTests.javaSource(
1116             "test.SupertypeA",
1117             "package test;",
1118             "",
1119             "import dagger.Component;",
1120             "import dagger.Lazy;",
1121             "import javax.inject.Provider;",
1122             "",
1123             "@Component",
1124             "interface SupertypeA {",
1125             "  SomeInjectableType someInjectableType();",
1126             "}");
1127     Source componentSupertypeBFile =
1128         CompilerTests.javaSource(
1129             "test.SupertypeB",
1130             "package test;",
1131             "",
1132             "import dagger.Component;",
1133             "import dagger.Lazy;",
1134             "import javax.inject.Provider;",
1135             "",
1136             "@Component",
1137             "interface SupertypeB {",
1138             "  SomeInjectableType someInjectableType();",
1139             "}");
1140     Source componentFile =
1141         CompilerTests.javaSource(
1142             "test.SimpleComponent",
1143             "package test;",
1144             "",
1145             "import dagger.Component;",
1146             "import dagger.Lazy;",
1147             "import javax.inject.Provider;",
1148             "",
1149             "@Component",
1150             "interface SimpleComponent extends SupertypeA, SupertypeB {",
1151             "}");
1152     CompilerTests.daggerCompiler(
1153             injectableTypeFile, componentSupertypeAFile, componentSupertypeBFile, componentFile)
1154         .withProcessingOptions(compilerMode.processorOptions())
1155         .compile(
1156             subject -> {
1157               subject.hasErrorCount(0);
1158               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent"));
1159             });
1160   }
1161 
1162   @Test
simpleComponent_inheritedComponentMethodDep()1163   public void simpleComponent_inheritedComponentMethodDep() throws Exception {
1164     Source injectableTypeFile = CompilerTests.javaSource("test.SomeInjectableType",
1165             "package test;",
1166             "",
1167             "import javax.inject.Inject;",
1168             "",
1169             "final class SomeInjectableType {",
1170             "  @Inject SomeInjectableType() {}",
1171             "}");
1172     Source componentSupertype = CompilerTests.javaSource("test.Supertype",
1173             "package test;",
1174             "",
1175             "import dagger.Component;",
1176             "",
1177             "@Component",
1178             "interface Supertype {",
1179             "  SomeInjectableType someInjectableType();",
1180             "}");
1181     Source depComponentFile = CompilerTests.javaSource("test.SimpleComponent",
1182             "package test;",
1183             "",
1184             "import dagger.Component;",
1185             "",
1186             "@Component",
1187             "interface SimpleComponent extends Supertype {",
1188             "}");
1189 
1190     CompilerTests.daggerCompiler(injectableTypeFile, componentSupertype, depComponentFile)
1191         .withProcessingOptions(compilerMode.processorOptions())
1192         .compile(
1193             subject -> {
1194               subject.hasErrorCount(0);
1195               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent"));
1196             });
1197   }
1198 
1199   @Test
wildcardGenericsRequiresAtProvides()1200   public void wildcardGenericsRequiresAtProvides() {
1201     Source aFile = CompilerTests.javaSource("test.A",
1202             "package test;",
1203             "",
1204             "import javax.inject.Inject;",
1205             "",
1206             "final class A {",
1207             "  @Inject A() {}",
1208             "}");
1209     Source bFile = CompilerTests.javaSource("test.B",
1210             "package test;",
1211             "",
1212             "import javax.inject.Inject;",
1213             "import javax.inject.Provider;",
1214             "",
1215             "final class B<T> {",
1216             "  @Inject B(T t) {}",
1217             "}");
1218     Source cFile = CompilerTests.javaSource("test.C",
1219             "package test;",
1220             "",
1221             "import javax.inject.Inject;",
1222             "import javax.inject.Provider;",
1223             "",
1224             "final class C {",
1225             "  @Inject C(B<? extends A> bA) {}",
1226             "}");
1227     Source componentFile = CompilerTests.javaSource("test.SimpleComponent",
1228             "package test;",
1229             "",
1230             "import dagger.Component;",
1231             "import dagger.Lazy;",
1232             "import javax.inject.Provider;",
1233             "",
1234             "@Component",
1235             "interface SimpleComponent {",
1236             "  C c();",
1237             "}");
1238 
1239     CompilerTests.daggerCompiler(aFile, bFile, cFile, componentFile)
1240         .withProcessingOptions(compilerMode.processorOptions())
1241         .compile(
1242             subject -> {
1243               subject.hasErrorCount(1);
1244               subject.hasErrorContaining(
1245                   "test.B<? extends test.A> cannot be provided without an @Provides-annotated "
1246                       + "method");
1247             });
1248   }
1249 
1250   // https://github.com/google/dagger/issues/630
1251   @Test
arrayKeyRequiresAtProvides()1252   public void arrayKeyRequiresAtProvides() {
1253     Source component =
1254         CompilerTests.javaSource(
1255             "test.TestComponent",
1256             "package test;",
1257             "",
1258             "import dagger.Component;",
1259             "",
1260             "@Component",
1261             "interface TestComponent {",
1262             "  String[] array();",
1263             "}");
1264 
1265     CompilerTests.daggerCompiler(component)
1266         .withProcessingOptions(compilerMode.processorOptions())
1267         .compile(
1268             subject -> {
1269               subject.hasErrorCount(1);
1270               subject.hasErrorContaining(
1271                   "String[] cannot be provided without an @Provides-annotated method");
1272             });
1273   }
1274 
1275   @Test
componentImplicitlyDependsOnGeneratedType()1276   public void componentImplicitlyDependsOnGeneratedType() {
1277     Source injectableTypeFile =
1278         CompilerTests.javaSource(
1279             "test.SomeInjectableType",
1280             "package test;",
1281             "",
1282             "import javax.inject.Inject;",
1283             "",
1284             "final class SomeInjectableType {",
1285             "  @Inject SomeInjectableType(GeneratedInjectType generatedInjectType) {}",
1286             "}");
1287     Source componentFile =
1288         CompilerTests.javaSource(
1289             "test.SimpleComponent",
1290             "package test;",
1291             "",
1292             "import dagger.Component;",
1293             "",
1294             "@Component",
1295             "interface SimpleComponent {",
1296             "  SomeInjectableType someInjectableType();",
1297             "}");
1298     CompilerTests.daggerCompiler(injectableTypeFile, componentFile)
1299         .withProcessingOptions(compilerMode.processorOptions())
1300         .withProcessingSteps(() -> new GeneratingProcessingStep("test", GENERATED_INJECT_TYPE))
1301         .compile(
1302           subject -> {
1303             subject.hasErrorCount(0);
1304             subject.generatedSourceFileWithPath("test/DaggerSimpleComponent.java");
1305           });
1306   }
1307 
1308   @Test
componentSupertypeDependsOnGeneratedType()1309   public void componentSupertypeDependsOnGeneratedType() {
1310     Source componentFile =
1311         CompilerTests.javaSource(
1312             "test.SimpleComponent",
1313             "package test;",
1314             "",
1315             "import dagger.Component;",
1316             "",
1317             "@Component",
1318             "interface SimpleComponent extends SimpleComponentInterface {}");
1319     Source interfaceFile =
1320         CompilerTests.javaSource(
1321             "test.SimpleComponentInterface",
1322             "package test;",
1323             "",
1324             "interface SimpleComponentInterface {",
1325             "  GeneratedInjectType generatedInjectType();",
1326             "}");
1327     CompilerTests.daggerCompiler(componentFile, interfaceFile)
1328         .withProcessingOptions(compilerMode.processorOptions())
1329         .withProcessingSteps(() -> new GeneratingProcessingStep("test", GENERATED_INJECT_TYPE))
1330         .compile(
1331           subject -> {
1332             subject.hasErrorCount(0);
1333             subject.generatedSourceFileWithPath("test/DaggerSimpleComponent.java");
1334           });
1335   }
1336 
1337   /**
1338    * We warn when generating a {@link MembersInjector} for a type post-hoc (i.e., if Dagger wasn't
1339    * invoked when compiling the type). But Dagger only generates {@link MembersInjector}s for types
1340    * with {@link Inject @Inject} constructors if they have any injection sites, and it only
1341    * generates them for types without {@link Inject @Inject} constructors if they have local
1342    * (non-inherited) injection sites. So make sure we warn in only those cases where running the
1343    * Dagger processor actually generates a {@link MembersInjector}.
1344    */
1345   @Test
unprocessedMembersInjectorNotes()1346   public void unprocessedMembersInjectorNotes() {
1347     Source component =
1348         CompilerTests.javaSource(
1349             "test.TestComponent",
1350             "package test;",
1351             "",
1352             "import dagger.Component;",
1353             "import dagger.internal.codegen.ComponentProcessorTestClasses;",
1354             "",
1355             "@Component(modules = TestModule.class)",
1356             "interface TestComponent {",
1357             "  void inject(ComponentProcessorTestClasses.NoInjectMemberNoConstructor object);",
1358             "  void inject(ComponentProcessorTestClasses.NoInjectMemberWithConstructor object);",
1359             "  void inject(ComponentProcessorTestClasses.LocalInjectMemberNoConstructor object);",
1360             "  void inject(ComponentProcessorTestClasses.LocalInjectMemberWithConstructor object);",
1361             "  void inject(ComponentProcessorTestClasses.ParentInjectMemberNoConstructor object);",
1362             "  void inject(",
1363             "      ComponentProcessorTestClasses.ParentInjectMemberWithConstructor object);",
1364             "}");
1365     Source module =
1366         CompilerTests.javaSource(
1367             "test.TestModule",
1368             "package test;",
1369             "",
1370             "import dagger.Module;",
1371             "import dagger.Provides;",
1372             "",
1373             "@Module",
1374             "class TestModule {",
1375             "  @Provides static Object object() {",
1376             "    return \"object\";",
1377             "  }",
1378             "}");
1379     CompilerTests.daggerCompiler(module, component)
1380         .withProcessingOptions(
1381             ImmutableMap.<String, String>builder()
1382                 .putAll(compilerMode.processorOptions())
1383                 .put("dagger.warnIfInjectionFactoryNotGeneratedUpstream", "enabled")
1384                 .buildOrThrow())
1385         .compile(
1386             subject -> {
1387               subject.hasErrorCount(0);
1388               subject.hasWarningCount(0);
1389 
1390               String generatedFileTemplate =
1391                   "dagger/internal/codegen/ComponentProcessorTestClasses_%s_MembersInjector.java";
1392               String noteTemplate =
1393                   "Generating a MembersInjector for "
1394                       + "dagger.internal.codegen.ComponentProcessorTestClasses.%s.";
1395 
1396               // Assert that we generate sources and notes for the following classes.
1397               ImmutableList.of(
1398                       "LocalInjectMemberNoConstructor",
1399                       "LocalInjectMemberWithConstructor",
1400                       "ParentInjectMemberWithConstructor")
1401                   .forEach(
1402                       className -> {
1403                         subject.generatedSourceFileWithPath(
1404                             String.format(generatedFileTemplate, className));
1405                         subject.hasNoteContaining(String.format(noteTemplate, className));
1406                       });
1407 
1408               // Assert that we **do not** generate sources and notes for the following classes.
1409               ImmutableList.of(
1410                       "ParentInjectMemberNoConstructor",
1411                       "NoInjectMemberNoConstructor",
1412                       "NoInjectMemberWithConstructor")
1413                   .forEach(
1414                       className -> {
1415                         assertFileNotGenerated(
1416                             subject, String.format(generatedFileTemplate, className));
1417                         assertDoesNotHaveNoteContaining(
1418                             subject, String.format(noteTemplate, className));
1419                       });
1420             });
1421   }
1422 
assertFileNotGenerated(CompilationResultSubject subject, String filePath)1423   private void assertFileNotGenerated(CompilationResultSubject subject, String filePath) {
1424     // TODO(b/303653163): replace this with better XProcessing API once we have the ability to get a
1425     // list of all generated sources.
1426     AssertionError error =
1427         assertThrows(
1428             AssertionError.class,
1429             () -> subject.generatedSourceFileWithPath(filePath));
1430     assertThat(error).hasMessageThat().contains("Didn't generate file");
1431   }
1432 
assertDoesNotHaveNoteContaining(CompilationResultSubject subject, String content)1433   private void assertDoesNotHaveNoteContaining(CompilationResultSubject subject, String content) {
1434     assertThat(
1435             subject.getCompilationResult().getDiagnostics().get(Diagnostic.Kind.NOTE).stream()
1436                 .filter(diagnostic -> diagnostic.getMsg().contains(content)))
1437         .isEmpty();
1438   }
1439 
1440   @Test
scopeAnnotationOnInjectConstructorNotValid()1441   public void scopeAnnotationOnInjectConstructorNotValid() {
1442     Source aScope =
1443         CompilerTests.javaSource(
1444             "test.AScope",
1445             "package test;",
1446             "",
1447             "import javax.inject.Scope;",
1448             "",
1449             "@Scope",
1450             "@interface AScope {}");
1451     Source aClass =
1452         CompilerTests.javaSource(
1453             "test.AClass",
1454             "package test;",
1455             "",
1456             "import javax.inject.Inject;",
1457             "",
1458             "final class AClass {",
1459             "  @Inject @AScope AClass() {}",
1460             "}");
1461     CompilerTests.daggerCompiler(aScope, aClass)
1462         .withProcessingOptions(compilerMode.processorOptions())
1463         .compile(
1464             subject -> {
1465               subject.hasErrorCount(1);
1466               subject
1467                   .hasErrorContaining("@Scope annotations are not allowed on @Inject constructors")
1468                   .onSource(aClass)
1469                   .onLine(6);
1470             });
1471   }
1472 
1473   @Test
unusedSubcomponents_dontResolveExtraBindingsInParentComponents()1474   public void unusedSubcomponents_dontResolveExtraBindingsInParentComponents() throws Exception {
1475     Source foo =
1476         CompilerTests.javaSource(
1477             "test.Foo",
1478             "package test;",
1479             "",
1480             "import javax.inject.Inject;",
1481             "import javax.inject.Singleton;",
1482             "",
1483             "@Singleton",
1484             "class Foo {",
1485             "  @Inject Foo() {}",
1486             "}");
1487 
1488     Source module =
1489         CompilerTests.javaSource(
1490             "test.TestModule",
1491             "package test;",
1492             "",
1493             "import dagger.Module;",
1494             "",
1495             "@Module(subcomponents = Pruned.class)",
1496             "class TestModule {}");
1497 
1498     Source component =
1499         CompilerTests.javaSource(
1500             "test.Parent",
1501             "package test;",
1502             "",
1503             "import dagger.Component;",
1504             "import javax.inject.Singleton;",
1505             "",
1506             "@Singleton",
1507             "@Component(modules = TestModule.class)",
1508             "interface Parent {}");
1509 
1510     Source prunedSubcomponent =
1511         CompilerTests.javaSource(
1512             "test.Pruned",
1513             "package test;",
1514             "",
1515             "import dagger.Subcomponent;",
1516             "",
1517             "@Subcomponent",
1518             "interface Pruned {",
1519             "  @Subcomponent.Builder",
1520             "  interface Builder {",
1521             "    Pruned build();",
1522             "  }",
1523             "",
1524             "  Foo foo();",
1525             "}");
1526 
1527     CompilerTests.daggerCompiler(foo, module, component, prunedSubcomponent)
1528         .withProcessingOptions(compilerMode.processorOptions())
1529         .compile(
1530             subject -> {
1531               subject.hasErrorCount(0);
1532               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerParent"));
1533             });
1534   }
1535 
1536   @Test
bindsToDuplicateBinding_bindsKeyIsNotDuplicated()1537   public void bindsToDuplicateBinding_bindsKeyIsNotDuplicated() {
1538     Source firstModule =
1539         CompilerTests.javaSource(
1540             "test.FirstModule",
1541             "package test;",
1542             "",
1543             "import dagger.Module;",
1544             "import dagger.Provides;",
1545             "",
1546             "@Module",
1547             "abstract class FirstModule {",
1548             "  @Provides static String first() { return \"first\"; }",
1549             "}");
1550     Source secondModule =
1551         CompilerTests.javaSource(
1552             "test.SecondModule",
1553             "package test;",
1554             "",
1555             "import dagger.Module;",
1556             "import dagger.Provides;",
1557             "",
1558             "@Module",
1559             "abstract class SecondModule {",
1560             "  @Provides static String second() { return \"second\"; }",
1561             "}");
1562     Source bindsModule =
1563         CompilerTests.javaSource(
1564             "test.BindsModule",
1565             "package test;",
1566             "",
1567             "import dagger.Binds;",
1568             "import dagger.Module;",
1569             "",
1570             "@Module",
1571             "abstract class BindsModule {",
1572             "  @Binds abstract Object bindToDuplicateBinding(String duplicate);",
1573             "}");
1574     Source component =
1575         CompilerTests.javaSource(
1576             "test.TestComponent",
1577             "package test;",
1578             "",
1579             "import dagger.Component;",
1580             "",
1581             "@Component(modules = {FirstModule.class, SecondModule.class, BindsModule.class})",
1582             "interface TestComponent {",
1583             "  Object notDuplicated();",
1584             "}");
1585 
1586     CompilerTests.daggerCompiler(firstModule, secondModule, bindsModule, component)
1587         .withProcessingOptions(compilerMode.processorOptions())
1588         .compile(
1589             subject -> {
1590               subject.hasErrorCount(1);
1591               subject.hasErrorContaining("String is bound multiple times")
1592                   .onSource(component)
1593                   .onLineContaining("interface TestComponent");
1594             });
1595   }
1596 
1597   @Test
nullIncorrectlyReturnedFromNonNullableInlinedProvider()1598   public void nullIncorrectlyReturnedFromNonNullableInlinedProvider() throws Exception {
1599      CompilerTests.daggerCompiler(
1600              CompilerTests.javaSource(
1601                 "test.TestModule",
1602                 "package test;",
1603                 "",
1604                 "import dagger.Module;",
1605                 "import dagger.Provides;",
1606                 "",
1607                 "@Module",
1608                 "public abstract class TestModule {",
1609                 "  @Provides static String nonNullableString() { return \"string\"; }",
1610                 "}"),
1611             CompilerTests.javaSource(
1612                 "test.InjectsMember",
1613                 "package test;",
1614                 "",
1615                 "import javax.inject.Inject;",
1616                 "",
1617                 "public class InjectsMember {",
1618                 "  @Inject String member;",
1619                 "}"),
1620             CompilerTests.javaSource(
1621                 "test.TestComponent",
1622                 "package test;",
1623                 "",
1624                 "import dagger.Component;",
1625                 "",
1626                 "@Component(modules = TestModule.class)",
1627                 "interface TestComponent {",
1628                 "  String nonNullableString();",
1629                 "  void inject(InjectsMember member);",
1630                 "}"))
1631         .withProcessingOptions(compilerMode.processorOptions())
1632         .compile(
1633             subject -> {
1634               // TODO(bcorso): Replace with subject.succeededWithoutWarnings()
1635               subject.hasErrorCount(0);
1636               subject.hasWarningCount(0);
1637               subject.generatedSource(
1638                   goldenFileRule.goldenSource("test/TestModule_NonNullableStringFactory"));
1639               subject.generatedSource(
1640                   goldenFileRule.goldenSource("test/DaggerTestComponent"));
1641             });
1642   }
1643 
1644   @Test
nullCheckingIgnoredWhenProviderReturnsPrimitive()1645   public void nullCheckingIgnoredWhenProviderReturnsPrimitive() throws Exception {
1646     CompilerTests.daggerCompiler(
1647             CompilerTests.javaSource(
1648                 "test.TestModule",
1649                 "package test;",
1650                 "",
1651                 "import dagger.Module;",
1652                 "import dagger.Provides;",
1653                 "",
1654                 "@Module",
1655                 "public abstract class TestModule {",
1656                 "  @Provides static int primitiveInteger() { return 1; }",
1657                 "}"),
1658             CompilerTests.javaSource(
1659                 "test.InjectsMember",
1660                 "package test;",
1661                 "",
1662                 "import javax.inject.Inject;",
1663                 "",
1664                 "public class InjectsMember {",
1665                 "  @Inject Integer member;",
1666                 "}"),
1667             CompilerTests.javaSource(
1668                 "test.TestComponent",
1669                 "package test;",
1670                 "",
1671                 "import dagger.Component;",
1672                 "",
1673                 "@Component(modules = TestModule.class)",
1674                 "interface TestComponent {",
1675                 "  Integer nonNullableInteger();",
1676                 "  void inject(InjectsMember member);",
1677                 "}"))
1678         .withProcessingOptions(compilerMode.processorOptions())
1679         .compile(
1680             subject -> {
1681               // TODO(bcorso): Replace with subject.succeededWithoutWarnings()
1682               subject.hasErrorCount(0);
1683               subject.hasWarningCount(0);
1684               subject.generatedSource(
1685                   goldenFileRule.goldenSource("test/TestModule_PrimitiveIntegerFactory"));
1686               subject.generatedSource(
1687                   goldenFileRule.goldenSource("test/DaggerTestComponent"));
1688             });
1689   }
1690 
1691   @Test
privateMethodUsedOnlyInChildDoesNotUseQualifiedThis()1692   public void privateMethodUsedOnlyInChildDoesNotUseQualifiedThis() throws Exception {
1693     Source parent =
1694         CompilerTests.javaSource(
1695             "test.Parent",
1696             "package test;",
1697             "",
1698             "import dagger.Component;",
1699             "import javax.inject.Singleton;",
1700             "",
1701             "@Singleton",
1702             "@Component(modules=TestModule.class)",
1703             "interface Parent {",
1704             "  Child child();",
1705             "}");
1706     Source testModule =
1707         CompilerTests.javaSource(
1708             "test.TestModule",
1709             "package test;",
1710             "",
1711             "import dagger.Module;",
1712             "import dagger.Provides;",
1713             "import javax.inject.Singleton;",
1714             "",
1715             "@Module",
1716             "abstract class TestModule {",
1717             "  @Provides @Singleton static Number number() {",
1718             "    return 3;",
1719             "  }",
1720             "",
1721             "  @Provides static String string(Number number) {",
1722             "    return number.toString();",
1723             "  }",
1724             "}");
1725     Source child =
1726         CompilerTests.javaSource(
1727             "test.Child",
1728             "package test;",
1729             "",
1730             "import dagger.Subcomponent;",
1731             "",
1732             "@Subcomponent",
1733             "interface Child {",
1734             "  String string();",
1735             "}");
1736 
1737     CompilerTests.daggerCompiler(parent, testModule, child)
1738         .withProcessingOptions(compilerMode.processorOptions())
1739         .compile(
1740             subject -> {
1741               // TODO(bcorso): Replace with subject.succeededWithoutWarnings()
1742               subject.hasErrorCount(0);
1743               subject.hasWarningCount(0);
1744               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerParent"));
1745             });
1746   }
1747 
1748   @Test
componentMethodInChildCallsComponentMethodInParent()1749   public void componentMethodInChildCallsComponentMethodInParent() throws Exception {
1750     Source supertype =
1751         CompilerTests.javaSource(
1752             "test.Supertype",
1753             "package test;",
1754             "",
1755             "interface Supertype {",
1756             "  String string();",
1757             "}");
1758     Source parent =
1759         CompilerTests.javaSource(
1760             "test.Parent",
1761             "package test;",
1762             "",
1763             "import dagger.Component;",
1764             "import javax.inject.Singleton;",
1765             "",
1766             "@Singleton",
1767             "@Component(modules=TestModule.class)",
1768             "interface Parent extends Supertype {",
1769             "  Child child();",
1770             "}");
1771     Source testModule =
1772         CompilerTests.javaSource(
1773             "test.TestModule",
1774             "package test;",
1775             "",
1776             "import dagger.Module;",
1777             "import dagger.Provides;",
1778             "import javax.inject.Singleton;",
1779             "",
1780             "@Module",
1781             "abstract class TestModule {",
1782             "  @Provides @Singleton static Number number() {",
1783             "    return 3;",
1784             "  }",
1785             "",
1786             "  @Provides static String string(Number number) {",
1787             "    return number.toString();",
1788             "  }",
1789             "}");
1790     Source child =
1791         CompilerTests.javaSource(
1792             "test.Child",
1793             "package test;",
1794             "",
1795             "import dagger.Subcomponent;",
1796             "",
1797             "@Subcomponent",
1798             "interface Child extends Supertype {}");
1799 
1800     CompilerTests.daggerCompiler(supertype, parent, testModule, child)
1801         .withProcessingOptions(compilerMode.processorOptions())
1802         .compile(
1803             subject -> {
1804               // TODO(bcorso): Replace with subject.succeededWithoutWarnings()
1805               subject.hasErrorCount(0);
1806               subject.hasWarningCount(0);
1807               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerParent"));
1808             });
1809   }
1810 
1811   @Test
justInTimeAtInjectConstructor_hasGeneratedQualifier()1812   public void justInTimeAtInjectConstructor_hasGeneratedQualifier() throws Exception {
1813     Source injected =
1814         CompilerTests.javaSource(
1815             "test.Injected",
1816             "package test;",
1817             "",
1818             "import javax.inject.Inject;",
1819             "",
1820             "class Injected {",
1821             "  @Inject Injected(@GeneratedQualifier String string) {}",
1822             "}");
1823     Source module =
1824         CompilerTests.javaSource(
1825             "test.TestModule",
1826             "package test;",
1827             "",
1828             "import dagger.Module;",
1829             "import dagger.Provides;",
1830             "",
1831             "@Module",
1832             "interface TestModule {",
1833             "  @Provides",
1834             "  static String unqualified() {",
1835             "    return new String();",
1836             "  }",
1837             "",
1838             "  @Provides",
1839             "  @GeneratedQualifier",
1840             "  static String qualified() {",
1841             "    return new String();",
1842             "  }",
1843             "}");
1844     Source component =
1845         CompilerTests.javaSource(
1846             "test.TestComponent",
1847             "package test;",
1848             "",
1849             "import dagger.Component;",
1850             "",
1851             "@Component(modules = TestModule.class)",
1852             "interface TestComponent {",
1853             "  Injected injected();",
1854             "}");
1855     CompilerTests.daggerCompiler(injected, module, component)
1856         .withProcessingOptions(compilerMode.processorOptions())
1857         .withProcessingSteps(() -> new GeneratingProcessingStep("test", GENERATED_QUALIFIER))
1858         .compile(
1859           subject -> {
1860               subject.hasErrorCount(0);
1861               subject.hasWarningCount(0);
1862               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
1863           });
1864   }
1865 
1866   @Test
moduleHasGeneratedQualifier()1867   public void moduleHasGeneratedQualifier() throws Exception {
1868     Source module =
1869         CompilerTests.javaSource(
1870             "test.TestModule",
1871             "package test;",
1872             "",
1873             "import dagger.Module;",
1874             "import dagger.Provides;",
1875             "",
1876             "@Module",
1877             "interface TestModule {",
1878             "  @Provides",
1879             "  static String unqualified() {",
1880             "    return new String();",
1881             "  }",
1882             "",
1883             "  @Provides",
1884             "  @GeneratedQualifier",
1885             "  static String qualified() {",
1886             "    return new String();",
1887             "  }",
1888             "}");
1889     Source component =
1890         CompilerTests.javaSource(
1891             "test.TestComponent",
1892             "package test;",
1893             "",
1894             "import dagger.Component;",
1895             "",
1896             "@Component(modules = TestModule.class)",
1897             "interface TestComponent {",
1898             "  String unqualified();",
1899             "}");
1900 
1901     CompilerTests.daggerCompiler(module, component)
1902         .withProcessingOptions(compilerMode.processorOptions())
1903         .withProcessingSteps(() -> new GeneratingProcessingStep("test", GENERATED_QUALIFIER))
1904         .compile(
1905           subject -> {
1906               subject.hasErrorCount(0);
1907               subject.hasWarningCount(0);
1908               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
1909           });
1910   }
1911 
1912   @Test
publicComponentType()1913   public void publicComponentType() throws Exception {
1914     Source publicComponent =
1915         CompilerTests.javaSource(
1916             "test.PublicComponent",
1917             "package test;",
1918             "",
1919             "import dagger.Component;",
1920             "",
1921             "@Component",
1922             "public interface PublicComponent {}");
1923     CompilerTests.daggerCompiler(publicComponent)
1924         .withProcessingOptions(compilerMode.processorOptions())
1925         .compile(
1926             subject -> {
1927               subject.hasErrorCount(0);
1928               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerPublicComponent"));
1929             });
1930   }
1931 
1932   @Test
componentFactoryInterfaceTest()1933   public void componentFactoryInterfaceTest() {
1934     Source parentInterface =
1935         CompilerTests.javaSource(
1936             "test.ParentInterface",
1937             "package test;",
1938             "",
1939             "interface ParentInterface extends ChildInterface.Factory {}");
1940 
1941     Source childInterface =
1942         CompilerTests.javaSource(
1943             "test.ChildInterface",
1944             "package test;",
1945             "",
1946             "interface ChildInterface {",
1947             "  interface Factory {",
1948             "    ChildInterface child(ChildModule childModule);",
1949             "  }",
1950             "}");
1951 
1952     Source parent =
1953         CompilerTests.javaSource(
1954             "test.Parent",
1955             "package test;",
1956             "",
1957             "import dagger.Component;",
1958             "",
1959             "@Component",
1960             "interface Parent extends ParentInterface, Child.Factory {}");
1961 
1962     Source child =
1963         CompilerTests.javaSource(
1964             "test.Child",
1965             "package test;",
1966             "",
1967             "import dagger.Subcomponent;",
1968             "",
1969             "@Subcomponent(modules = ChildModule.class)",
1970             "interface Child extends ChildInterface {",
1971             "  interface Factory extends ChildInterface.Factory {",
1972             "    @Override Child child(ChildModule childModule);",
1973             "  }",
1974             "}");
1975 
1976     Source childModule =
1977         CompilerTests.javaSource(
1978             "test.ChildModule",
1979             "package test;",
1980             "",
1981             "import dagger.Module;",
1982             "import dagger.Provides;",
1983             "",
1984             "@Module",
1985             "class ChildModule {",
1986             "  @Provides",
1987             "  int provideInt() {",
1988             "    return 0;",
1989             "  }",
1990             "}");
1991 
1992     CompilerTests.daggerCompiler(parentInterface, childInterface, parent, child, childModule)
1993         .withProcessingOptions(compilerMode.processorOptions())
1994         .compile(subject -> subject.hasErrorCount(0));
1995   }
1996 
1997   @Test
providerComponentType()1998   public void providerComponentType() throws Exception {
1999     Source entryPoint =
2000         CompilerTests.javaSource(
2001             "test.SomeEntryPoint",
2002             "package test;",
2003             "",
2004             "import javax.inject.Inject;",
2005             "import javax.inject.Provider;",
2006             "",
2007             "public class SomeEntryPoint {",
2008             "  @Inject SomeEntryPoint(Foo foo, Provider<Foo> fooProvider) {}",
2009             "}");
2010     Source foo =
2011         CompilerTests.javaSource(
2012             "test.Foo",
2013             "package test;",
2014             "",
2015             "import javax.inject.Inject;",
2016             "",
2017             "public class Foo {",
2018             "  @Inject Foo(Bar bar) {}",
2019             "}");
2020     Source bar =
2021         CompilerTests.javaSource(
2022             "test.Bar",
2023             "package test;",
2024             "",
2025             "import javax.inject.Inject;",
2026             "",
2027             "public class Bar {",
2028             "  @Inject Bar() {}",
2029             "}");
2030     Source component =
2031         CompilerTests.javaSource(
2032             "test.TestComponent",
2033             "package test;",
2034             "",
2035             "import dagger.Component;",
2036             "import javax.inject.Provider;",
2037             "",
2038             "@Component",
2039             "public interface TestComponent {",
2040             "  SomeEntryPoint someEntryPoint();",
2041             "}");
2042     CompilerTests.daggerCompiler(component, foo, bar, entryPoint)
2043         .withProcessingOptions(compilerMode.processorOptions())
2044         .compile(
2045             subject -> {
2046               subject.hasErrorCount(0);
2047               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
2048             });
2049   }
2050 
2051   @Test
injectedTypeHasGeneratedParam()2052   public void injectedTypeHasGeneratedParam() {
2053     Source foo =
2054         CompilerTests.javaSource(
2055             "test.Foo",
2056             "package test;",
2057             "",
2058             "import javax.inject.Inject;",
2059             "",
2060             "public final class Foo {",
2061             "",
2062             "  @Inject",
2063             "  public Foo(GeneratedInjectType param) {}",
2064             "",
2065             "  @Inject",
2066             "  public void init() {}",
2067             "}");
2068     Source component =
2069         CompilerTests.javaSource(
2070             "test.TestComponent",
2071             "package test;",
2072             "",
2073             "import dagger.Component;",
2074             "import java.util.Set;",
2075             "",
2076             "@Component",
2077             "interface TestComponent {",
2078             "  Foo foo();",
2079             "}");
2080 
2081     CompilerTests.daggerCompiler(foo, component)
2082         .withProcessingOptions(compilerMode.processorOptions())
2083         .withProcessingSteps(() -> new GeneratingProcessingStep("test", GENERATED_INJECT_TYPE))
2084         .compile(
2085           subject -> {
2086               subject.hasErrorCount(0);
2087               subject.hasWarningCount(0);
2088           });
2089   }
2090 
2091   @Test
abstractVarFieldInComponent_failsValidation()2092   public void abstractVarFieldInComponent_failsValidation() {
2093     Source component =
2094         CompilerTests.kotlinSource(
2095             "test.TestComponent.kt",
2096             "package test",
2097             "",
2098             "import dagger.Component",
2099             "",
2100             "@Component(modules = [TestModule::class])",
2101             "interface TestComponent {",
2102             " var foo: String",
2103             "}");
2104 
2105     Source module =
2106         CompilerTests.javaSource(
2107             "test.TestModule",
2108             "package test;",
2109             "",
2110             "import dagger.Module;",
2111             "import dagger.Provides;",
2112             "",
2113             "@Module",
2114             "abstract class TestModule {",
2115             "  @Provides",
2116             "  static String provideString() { return \"hello\"; }",
2117             "}");
2118 
2119     CompilerTests.daggerCompiler(component, module)
2120         .withProcessingOptions(compilerMode.processorOptions())
2121         .compile(
2122             subject -> {
2123               subject.hasErrorCount(1);
2124               subject.hasErrorContaining(
2125                   "Cannot use 'abstract var' property in a component declaration to get a binding."
2126                       + " Use 'val' or 'fun' instead: foo");
2127             });
2128   }
2129 
2130   @Test
nonAbstractVarFieldInComponent_passesValidation()2131   public void nonAbstractVarFieldInComponent_passesValidation() {
2132     Source component =
2133         CompilerTests.kotlinSource(
2134             "test.TestComponent.kt",
2135             "package test",
2136             "",
2137             "import dagger.Component",
2138             "",
2139             "@Component(modules = [TestModule::class])",
2140             "abstract class TestComponent {",
2141             " var foo: String = \"hello\"",
2142             "}");
2143 
2144     Source module =
2145         CompilerTests.javaSource(
2146             "test.TestModule",
2147             "package test;",
2148             "",
2149             "import dagger.Module;",
2150             "import dagger.Provides;",
2151             "",
2152             "@Module",
2153             "abstract class TestModule {",
2154             "  @Provides",
2155             "  static String provideString() { return \"hello\"; }",
2156             "}");
2157 
2158     CompilerTests.daggerCompiler(component, module)
2159         .withProcessingOptions(compilerMode.processorOptions())
2160         .compile(subject -> subject.hasErrorCount(0));
2161   }
2162 }
2163