• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 androidx.room.compiler.processing.XProcessingEnv;
20 import androidx.room.compiler.processing.util.Source;
21 import com.google.common.collect.ImmutableList;
22 import com.google.common.collect.ImmutableMap;
23 import com.squareup.javapoet.MethodSpec;
24 import com.squareup.javapoet.TypeSpec;
25 import dagger.internal.codegen.javapoet.TypeNames;
26 import dagger.testing.compile.CompilerTests;
27 import dagger.testing.golden.GoldenFileRule;
28 import org.junit.Rule;
29 import org.junit.Test;
30 import org.junit.runner.RunWith;
31 import org.junit.runners.Parameterized;
32 import org.junit.runners.Parameterized.Parameters;
33 
34 @RunWith(Parameterized.class)
35 public class MembersInjectionTest {
36 
37   private static final Source TYPE_USE_NULLABLE =
38       CompilerTests.javaSource(
39           "test.Nullable", // force one-string-per-line format
40           "package test;",
41           "import static java.lang.annotation.ElementType.TYPE_USE;",
42           "import java.lang.annotation.Target;",
43           "",
44           "@Target(TYPE_USE)",
45           "public @interface Nullable {}");
46   private static final Source NON_TYPE_USE_NULLABLE =
47       CompilerTests.javaSource(
48           "test.Nullable", // force one-string-per-line format
49           "package test;",
50           "",
51           "public @interface Nullable {}");
52 
53   @Parameters(name = "{0}")
parameters()54   public static ImmutableList<Object[]> parameters() {
55     return CompilerMode.TEST_PARAMETERS;
56   }
57 
58   @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule();
59 
60   private final CompilerMode compilerMode;
61 
MembersInjectionTest(CompilerMode compilerMode)62   public MembersInjectionTest(CompilerMode compilerMode) {
63     this.compilerMode = compilerMode;
64   }
65 
66   @Test
injectKotlinProtectField_fails()67   public void injectKotlinProtectField_fails() {
68     Source injectFieldSrc =
69         CompilerTests.kotlinSource(
70             "MyClass.kt",
71             "package test",
72             "",
73             "import javax.inject.Inject",
74             "",
75             "class MyClass @Inject constructor() {",
76             "  @Inject protected lateinit var protectedField: String",
77             "}");
78     Source moduleSrc =
79         CompilerTests.kotlinSource(
80             "MyModule.kt",
81             "package test",
82             "",
83             "import dagger.Module",
84             "import dagger.Provides",
85             "",
86             "@Module",
87             "object MyModule {",
88             "  @Provides",
89             "  fun providesString() = \"hello\"",
90             "}");
91     Source componentSrc =
92         CompilerTests.kotlinSource(
93             "MyComponent.kt",
94             "package test",
95             "",
96             "import dagger.Component",
97             "@Component(modules = [MyModule::class])",
98             "interface MyComponent {}");
99     CompilerTests.daggerCompiler(injectFieldSrc, moduleSrc, componentSrc)
100         .withProcessingOptions(compilerMode.processorOptions())
101         .compile(
102             subject -> {
103               subject.hasErrorCount(1);
104               subject.hasErrorContaining(
105                   "Dagger injector does not have access to kotlin protected fields");
106             });
107   }
108 
109   @Test
injectJavaProtectField_succeeds()110   public void injectJavaProtectField_succeeds() {
111     Source injectFieldSrc =
112         CompilerTests.javaSource(
113             "test.MyClass",
114             "package test;",
115             "",
116             "import javax.inject.Inject;",
117             "",
118             "public final class MyClass {",
119             "  @Inject MyClass() {}",
120             "  @Inject protected String protectedField;",
121             "}");
122     Source moduleSrc =
123         CompilerTests.kotlinSource(
124             "MyModule.kt",
125             "package test",
126             "",
127             "import dagger.Module",
128             "import dagger.Provides",
129             "",
130             "@Module",
131             "object MyModule {",
132             "  @Provides",
133             "  fun providesString() = \"hello\"",
134             "}");
135     Source componentSrc =
136         CompilerTests.kotlinSource(
137             "MyComponent.kt",
138             "package test",
139             "",
140             "import dagger.Component",
141             "@Component(modules = [MyModule::class])",
142             "interface MyComponent {}");
143     CompilerTests.daggerCompiler(injectFieldSrc, moduleSrc, componentSrc)
144         .withProcessingOptions(compilerMode.processorOptions())
145         .compile(subject -> subject.hasErrorCount(0));
146   }
147 
148   @Test
parentClass_noInjectedMembers()149   public void parentClass_noInjectedMembers() throws Exception {
150     Source childFile =
151         CompilerTests.javaSource(
152             "test.Child",
153             "package test;",
154             "",
155             "import javax.inject.Inject;",
156             "",
157             "public final class Child extends Parent {",
158             "  @Inject Child() {}",
159             "}");
160     Source parentFile =
161         CompilerTests.javaSource(
162             "test.Parent",
163             "package test;",
164             "",
165             "public abstract class Parent {}");
166 
167     Source componentFile =
168         CompilerTests.javaSource(
169             "test.TestComponent",
170             "package test;",
171             "",
172             "import dagger.Component;",
173             "",
174             "@Component",
175             "interface TestComponent {",
176             "  Child child();",
177             "}");
178 
179     CompilerTests.daggerCompiler(childFile, parentFile, componentFile)
180         .withProcessingOptions(compilerMode.processorOptions())
181         .compile(
182             subject -> {
183               subject.hasErrorCount(0);
184               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
185             });
186   }
187 
188   @Test
parentClass_injectedMembersInSupertype()189   public void parentClass_injectedMembersInSupertype() throws Exception {
190     Source childFile =
191         CompilerTests.javaSource(
192             "test.Child",
193             "package test;",
194             "",
195             "import javax.inject.Inject;",
196             "",
197             "public final class Child extends Parent {",
198             "  @Inject Child() {}",
199             "}");
200     Source parentFile =
201         CompilerTests.javaSource(
202             "test.Parent",
203             "package test;",
204             "",
205             "import javax.inject.Inject;",
206             "",
207             "public abstract class Parent {",
208             "  @Inject Dep dep;",
209             "}");
210     Source depFile =
211         CompilerTests.javaSource(
212             "test.Dep",
213             "package test;",
214             "",
215             "import javax.inject.Inject;",
216             "",
217             "final class Dep {",
218             "  @Inject Dep() {}",
219             "}");
220     Source componentFile =
221         CompilerTests.javaSource(
222             "test.TestComponent",
223             "package test;",
224             "",
225             "import dagger.Component;",
226             "",
227             "@Component",
228             "interface TestComponent {",
229             "  Child child();",
230             "}");
231 
232     CompilerTests.daggerCompiler(childFile, parentFile, depFile, componentFile)
233         .withProcessingOptions(compilerMode.processorOptions())
234         .compile(
235             subject -> {
236               subject.hasErrorCount(0);
237               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
238             });
239   }
240 
fieldAndMethodGenerics()241   @Test public void fieldAndMethodGenerics() {
242     Source file =
243         CompilerTests.javaSource(
244             "test.GenericClass",
245             "package test;",
246             "",
247             "import javax.inject.Inject;",
248             "",
249             "class GenericClass<A, B> {",
250             "  @Inject A a;",
251             "",
252             "  @Inject GenericClass() {}",
253             "",
254             " @Inject void register(B b) {}",
255             "}");
256 
257     CompilerTests.daggerCompiler(file)
258         .withProcessingOptions(compilerMode.processorOptions())
259         .compile(
260             subject -> {
261               subject.hasErrorCount(0);
262               subject.generatedSource(
263                   goldenFileRule.goldenSource("test/GenericClass_MembersInjector"));
264             });
265   }
266 
subclassedGenericMembersInjectors()267   @Test public void subclassedGenericMembersInjectors() {
268     Source a =
269         CompilerTests.javaSource(
270             "test.A",
271             "package test;",
272             "",
273             "import javax.inject.Inject;",
274             "",
275             "final class A {",
276             "  @Inject A() {}",
277             "}");
278     Source a2 =
279         CompilerTests.javaSource(
280             "test.A2",
281             "package test;",
282             "",
283             "import javax.inject.Inject;",
284             "",
285             "final class A2 {",
286             "  @Inject A2() {}",
287             "}");
288     Source parent =
289         CompilerTests.javaSource(
290             "test.Parent",
291             "package test;",
292             "",
293             "import javax.inject.Inject;",
294             "",
295             "class Parent<X, Y> {",
296             "  @Inject X x;",
297             "  @Inject Y y;",
298             "  @Inject A2 a2;",
299             "",
300             "  @Inject Parent() {}",
301             "}");
302     Source child =
303         CompilerTests.javaSource(
304             "test.Child",
305             "package test;",
306             "",
307             "import javax.inject.Inject;",
308             "",
309             "class Child<T> extends Parent<T, A> {",
310             "  @Inject A a;",
311             "  @Inject T t;",
312             "",
313             "  @Inject Child() {}",
314             "}");
315     CompilerTests.daggerCompiler(a, a2, parent, child)
316         .withProcessingOptions(compilerMode.processorOptions())
317         .compile(
318             subject -> {
319               subject.hasErrorCount(0);
320               subject.generatedSource(goldenFileRule.goldenSource("test/Child_MembersInjector"));
321             });
322   }
323 
fieldInjection()324   @Test public void fieldInjection() {
325     Source file =
326         CompilerTests.javaSource(
327             "test.FieldInjection",
328             "package test;",
329             "",
330             "import dagger.Lazy;",
331             "import javax.inject.Inject;",
332             "import javax.inject.Provider;",
333             "",
334             "class FieldInjection {",
335             "  @Inject String string;",
336             "  @Inject Lazy<String> lazyString;",
337             "  @Inject Provider<String> stringProvider;",
338             "}");
339     CompilerTests.daggerCompiler(file)
340         .withProcessingOptions(compilerMode.processorOptions())
341         .compile(
342             subject -> {
343               subject.hasErrorCount(0);
344               subject.generatedSource(
345                   goldenFileRule.goldenSource("test/FieldInjection_MembersInjector"));
346             });
347   }
348 
349   @Test
typeUseNullableFieldInjection()350   public void typeUseNullableFieldInjection() {
351     Source file =
352         CompilerTests.javaSource(
353             "test.FieldInjection",
354             "package test;",
355             "",
356             "import dagger.Lazy;",
357             "import javax.inject.Inject;",
358             "import javax.inject.Provider;",
359             "",
360             "class FieldInjection {",
361             "  @Inject @Nullable String string;",
362             "}");
363     CompilerTests.daggerCompiler(file, TYPE_USE_NULLABLE)
364         .withProcessingOptions(compilerMode.processorOptions())
365         .compile(
366             subject -> {
367               subject.hasErrorCount(0);
368               subject.generatedSource(
369                   goldenFileRule.goldenSource("test/FieldInjection_MembersInjector"));
370             });
371   }
372 
373   @Test
nonTypeUseNullableFieldInjection()374   public void nonTypeUseNullableFieldInjection() {
375     Source file =
376         CompilerTests.javaSource(
377             "test.FieldInjection",
378             "package test;",
379             "",
380             "import dagger.Lazy;",
381             "import javax.inject.Inject;",
382             "import javax.inject.Provider;",
383             "",
384             "class FieldInjection {",
385             "  @Inject @Nullable String string;",
386             "}");
387     CompilerTests.daggerCompiler(file, NON_TYPE_USE_NULLABLE)
388         .withProcessingOptions(compilerMode.processorOptions())
389         .compile(
390             subject -> {
391               subject.hasErrorCount(0);
392               subject.generatedSource(
393                   goldenFileRule.goldenSource("test/FieldInjection_MembersInjector"));
394             });
395   }
396 
397   @Test
fieldInjectionWithQualifier()398   public void fieldInjectionWithQualifier() {
399     Source file =
400         CompilerTests.javaSource(
401             "test.FieldInjectionWithQualifier",
402             "package test;",
403             "",
404             "import dagger.Lazy;",
405             "import javax.inject.Inject;",
406             "import javax.inject.Named;",
407             "import javax.inject.Provider;",
408             "",
409             "class FieldInjectionWithQualifier {",
410             "  @Inject @Named(\"A\") String a;",
411             "  @Inject @Named(\"B\") String b;",
412             "}");
413     CompilerTests.daggerCompiler(file)
414         .withProcessingOptions(compilerMode.processorOptions())
415         .compile(
416             subject -> {
417               subject.hasErrorCount(0);
418               subject.generatedSource(
419                   goldenFileRule.goldenSource("test/FieldInjectionWithQualifier_MembersInjector"));
420             });
421   }
422 
methodInjection()423   @Test public void methodInjection() {
424     Source file =
425         CompilerTests.javaSource(
426             "test.MethodInjection",
427             "package test;",
428             "",
429             "import dagger.Lazy;",
430             "import javax.inject.Inject;",
431             "import javax.inject.Provider;",
432             "",
433             "class MethodInjection {",
434             "  @Inject void noArgs() {}",
435             "  @Inject void oneArg(String string) {}",
436             "  @Inject void manyArgs(",
437             "      String string, Lazy<String> lazyString, Provider<String> stringProvider) {}",
438             "}");
439     CompilerTests.daggerCompiler(file)
440         .withProcessingOptions(compilerMode.processorOptions())
441         .compile(
442             subject -> {
443               subject.hasErrorCount(0);
444               subject.generatedSource(
445                   goldenFileRule.goldenSource("test/MethodInjection_MembersInjector"));
446             });
447   }
448 
449   @Test
mixedMemberInjection()450   public void mixedMemberInjection() {
451     Source file =
452         CompilerTests.javaSource(
453             "test.MixedMemberInjection",
454             "package test;",
455             "",
456             "import dagger.Lazy;",
457             "import javax.inject.Inject;",
458             "import javax.inject.Provider;",
459             "",
460             "class MixedMemberInjection {",
461             "  @Inject String string;",
462             "  @Inject void setString(String s) {}",
463             "  @Inject Object object;",
464             "  @Inject void setObject(Object o) {}",
465             "}");
466     CompilerTests.daggerCompiler(file)
467         .withProcessingOptions(compilerMode.processorOptions())
468         .compile(
469             subject -> {
470               subject.hasErrorCount(0);
471               subject.generatedSource(
472                   goldenFileRule.goldenSource("test/MixedMemberInjection_MembersInjector"));
473             });
474   }
475 
injectConstructorAndMembersInjection()476   @Test public void injectConstructorAndMembersInjection() {
477     Source file =
478         CompilerTests.javaSource(
479             "test.AllInjections",
480             "package test;",
481             "",
482             "import javax.inject.Inject;",
483             "",
484             "class AllInjections {",
485             "  @Inject String s;",
486             "  @Inject AllInjections(String s) {}",
487             "  @Inject void s(String s) {}",
488             "}");
489     CompilerTests.daggerCompiler(file)
490         .withProcessingOptions(compilerMode.processorOptions())
491         .compile(
492             subject -> {
493               subject.hasErrorCount(0);
494               subject.generatedSource(
495                   goldenFileRule.goldenSource("test/AllInjections_MembersInjector"));
496             });
497   }
498 
supertypeMembersInjection()499   @Test public void supertypeMembersInjection() {
500     Source aFile =
501         CompilerTests.javaSource(
502             "test.A",
503             "package test;",
504             "",
505             "class A {}");
506     Source bFile =
507         CompilerTests.javaSource(
508             "test.B",
509             "package test;",
510             "",
511             "import javax.inject.Inject;",
512             "",
513             "class B extends A {",
514             "  @Inject String s;",
515             "}");
516     CompilerTests.daggerCompiler(aFile, bFile)
517         .withProcessingOptions(compilerMode.processorOptions())
518         .compile(
519             subject -> {
520               subject.hasErrorCount(0);
521               subject.generatedSource(goldenFileRule.goldenSource("test/B_MembersInjector"));
522             });
523   }
524 
525   @Test
simpleComponentWithNesting()526   public void simpleComponentWithNesting() {
527     Source nestedTypesFile =
528         CompilerTests.javaSource(
529             "test.OuterType",
530             "package test;",
531             "",
532             "import dagger.Component;",
533             "import javax.inject.Inject;",
534             "",
535             "final class OuterType {",
536             "  static class A {",
537             "    @Inject A() {}",
538             "  }",
539             "  static class B {",
540             "    @Inject A a;",
541             "  }",
542             "  @Component interface SimpleComponent {",
543             "    A a();",
544             "    void inject(B b);",
545             "  }",
546             "}");
547     CompilerTests.daggerCompiler(nestedTypesFile)
548         .withProcessingOptions(compilerMode.processorOptions())
549         .compile(
550             subject -> {
551               subject.hasErrorCount(0);
552               subject.generatedSource(
553                   goldenFileRule.goldenSource("test/OuterType_B_MembersInjector"));
554             });
555   }
556 
557   @Test
componentWithNestingAndGeneratedType()558   public void componentWithNestingAndGeneratedType() {
559     Source nestedTypesFile =
560         CompilerTests.javaSource(
561             "test.OuterType",
562             "package test;",
563             "",
564             "import dagger.Component;",
565             "import javax.inject.Inject;",
566             "",
567             "final class OuterType {",
568             "  @Inject GeneratedInjectType generated;",
569             "  static class A {",
570             "    @Inject A() {}",
571             "  }",
572             "  static class B {",
573             "    @Inject A a;",
574             "  }",
575             "  @Component interface SimpleComponent {",
576             "    A a();",
577             "    void inject(B b);",
578             "  }",
579             "}");
580     TypeSpec generatedInjectType =
581         TypeSpec.classBuilder("GeneratedInjectType")
582             .addMethod(
583                 MethodSpec.constructorBuilder()
584                     .addAnnotation(TypeNames.INJECT_JAVAX)
585                     .build())
586             .build();
587 
588     CompilerTests.daggerCompiler(nestedTypesFile)
589         .withProcessingOptions(compilerMode.processorOptions())
590         .withProcessingSteps(() -> new GeneratingProcessingStep("test", generatedInjectType))
591         .compile(
592             subject -> {
593               subject.hasErrorCount(0);
594               subject.generatedSource(
595                   goldenFileRule.goldenSource("test/OuterType_B_MembersInjector"));
596             });
597   }
598 
599   @Test
lowerCaseNamedMembersInjector_forLowerCaseType()600   public void lowerCaseNamedMembersInjector_forLowerCaseType() {
601     Source foo =
602         CompilerTests.javaSource(
603             "test.foo",
604             "package test;",
605             "",
606             "import javax.inject.Inject;",
607             "",
608             "class foo {",
609             "  @Inject String string;",
610             "}");
611     Source fooModule =
612         CompilerTests.javaSource(
613             "test.fooModule",
614             "package test;",
615             "",
616             "import dagger.Module;",
617             "import dagger.Provides;",
618             "",
619             "@Module",
620             "class fooModule {",
621             "  @Provides String string() { return \"foo\"; }",
622             "}");
623     Source fooComponent =
624         CompilerTests.javaSource(
625             "test.fooComponent",
626             "package test;",
627             "",
628             "import dagger.Component;",
629             "",
630             "@Component(modules = fooModule.class)",
631             "interface fooComponent {",
632             "  void inject(foo target);",
633             "}");
634 
635     CompilerTests.daggerCompiler(foo, fooModule, fooComponent)
636         .withProcessingOptions(compilerMode.processorOptions())
637         .compile(
638             subject -> {
639               subject.hasErrorCount(0);
640               subject.generatedSourceFileWithPath("test/foo_MembersInjector.java");
641             });
642   }
643 
644   @Test
fieldInjectionForShadowedMember()645   public void fieldInjectionForShadowedMember() {
646     Source foo =
647         CompilerTests.javaSource(
648             "test.Foo",
649             "package test;",
650             "",
651             "import javax.inject.Inject;",
652             "",
653             "class Foo {",
654             "  @Inject Foo() {}",
655             "}");
656     Source bar =
657         CompilerTests.javaSource(
658             "test.Bar",
659             "package test;",
660             "",
661             "import javax.inject.Inject;",
662             "",
663             "class Bar {",
664             "  @Inject Bar() {}",
665             "}");
666     Source parent =
667         CompilerTests.javaSource(
668             "test.Parent",
669             "package test;",
670             "",
671             "import javax.inject.Inject;",
672             "",
673             "class Parent { ",
674             "  @Inject Foo object;",
675             "}");
676     Source child =
677         CompilerTests.javaSource(
678             "test.Child",
679             "package test;",
680             "",
681             "import javax.inject.Inject;",
682             "",
683             "class Child extends Parent { ",
684             "  @Inject Bar object;",
685             "}");
686     Source component =
687         CompilerTests.javaSource(
688             "test.C",
689             "package test;",
690             "",
691             "import dagger.Component;",
692             "",
693             "@Component",
694             "interface C { ",
695             "  void inject(Child child);",
696             "}");
697 
698     CompilerTests.daggerCompiler(foo, bar, parent, child, component)
699         .withProcessingOptions(compilerMode.processorOptions())
700         .compile(
701             subject -> {
702               subject.hasErrorCount(0);
703               subject.generatedSource(
704                   goldenFileRule.goldenSource("test/Child_MembersInjector"));
705             });
706   }
707 
privateNestedClassError()708   @Test public void privateNestedClassError() {
709     Source file =
710         CompilerTests.javaSource(
711             "test.OuterClass",
712             "package test;",
713             "",
714             "import javax.inject.Inject;",
715             "",
716             "final class OuterClass {",
717             "  private static final class InnerClass {",
718             "    @Inject int field;",
719             "  }",
720             "}");
721     CompilerTests.daggerCompiler(file)
722         .withProcessingOptions(compilerMode.processorOptions())
723         .compile(
724             subject -> {
725               subject.hasErrorCount(1);
726               subject.hasErrorContaining("Dagger does not support injection into private classes")
727                   .onSource(file)
728                   .onLine(6);
729             });
730   }
731 
privateNestedClassWarning()732   @Test public void privateNestedClassWarning() {
733     Source file =
734         CompilerTests.javaSource(
735             "test.OuterClass",
736             "package test;",
737             "",
738             "import javax.inject.Inject;",
739             "",
740             "final class OuterClass {",
741             "  private static final class InnerClass {",
742             "    @Inject int field;",
743             "  }",
744             "}");
745     CompilerTests.daggerCompiler(file)
746         .withProcessingOptions(
747             ImmutableMap.<String, String>builder()
748                 .putAll(compilerMode.processorOptions())
749                 .put("dagger.privateMemberValidation", "WARNING")
750                 .buildOrThrow())
751         .compile(
752             subject -> {
753               subject.hasErrorCount(0);
754               subject.hasWarningCount(1);
755               subject.hasWarningContaining("Dagger does not support injection into private classes")
756                   .onSource(file)
757                   .onLine(6);
758             });
759   }
760 
privateSuperclassIsOkIfNotInjectedInto()761   @Test public void privateSuperclassIsOkIfNotInjectedInto() {
762     Source file =
763         CompilerTests.javaSource(
764             "test.OuterClass",
765             "package test;",
766             "",
767             "import javax.inject.Inject;",
768             "",
769             "final class OuterClass {",
770             "  private static class BaseClass {}",
771             "",
772             "  static final class DerivedClass extends BaseClass {",
773             "    @Inject int field;",
774             "  }",
775             "}");
776     CompilerTests.daggerCompiler(file)
777         .withProcessingOptions(compilerMode.processorOptions())
778         .compile(subject -> subject.hasErrorCount(0));
779   }
780 
781   @Test
throwExceptionInjectedMethod()782   public void throwExceptionInjectedMethod() {
783     Source file =
784         CompilerTests.javaSource(
785             "test.",
786             "package test;",
787             "",
788             "import javax.inject.Inject;",
789             "class SomeClass {",
790             "@Inject void inject() throws Exception {}",
791             "}");
792 
793     CompilerTests.daggerCompiler(file)
794         .withProcessingOptions(compilerMode.processorOptions())
795         .compile(
796             subject -> {
797               subject.hasErrorCount(1);
798               subject.hasErrorContaining(
799                       "Methods with @Inject may not throw checked exceptions. "
800                           + "Please wrap your exceptions in a RuntimeException instead.")
801                   .onSource(file)
802                   .onLineContaining("throws Exception");
803             });
804   }
805 
806   @Test
rawFrameworkTypeField()807   public void rawFrameworkTypeField() {
808     Source file =
809         CompilerTests.javaSource(
810             "test.RawProviderField",
811             "package test;",
812             "",
813             "import javax.inject.Inject;",
814             "import javax.inject.Provider;",
815             "",
816             "class RawProviderField {",
817             "  @Inject",
818             "  Provider fieldWithRawProvider;",
819             "}");
820 
821     CompilerTests.daggerCompiler(file)
822         .withProcessingOptions(compilerMode.processorOptions())
823         .compile(
824             subject -> {
825               subject.hasErrorCount(1);
826               subject.hasErrorContaining(
827                       "Dagger does not support injecting raw type: javax.inject.Provider")
828                   .onSource(file)
829                   .onLineContaining("Provider fieldWithRawProvider");
830             });
831   }
832 
833   @Test
rawFrameworkMethodTypeParameter()834   public void rawFrameworkMethodTypeParameter() {
835     Source file =
836         CompilerTests.javaSource(
837             "test.RawProviderParameter",
838             "package test;",
839             "",
840             "import javax.inject.Inject;",
841             "import javax.inject.Provider;",
842             "",
843             "class RawProviderParameter {",
844             "  @Inject",
845             "  void methodInjection(",
846             "      Provider rawProviderParameter) {}",
847             "}");
848 
849     CompilerTests.daggerCompiler(file)
850         .withProcessingOptions(compilerMode.processorOptions())
851         .compile(
852             subject -> {
853               subject.hasErrorCount(1);
854               subject.hasErrorContaining(
855                       "Dagger does not support injecting raw type: javax.inject.Provider")
856                   .onSource(file)
857                   .onLineContaining("Provider rawProviderParameter");
858             });
859   }
860 
861   @Test
rawFrameworkConstructorTypeParameter()862   public void rawFrameworkConstructorTypeParameter() {
863     Source file =
864         CompilerTests.javaSource(
865             "test.RawProviderParameter",
866             "package test;",
867             "",
868             "import dagger.Component;",
869             "import javax.inject.Inject;",
870             "import javax.inject.Provider;",
871             "",
872             "class RawProviderParameter {",
873             "  @Inject",
874             "  RawProviderParameter(",
875             "      Provider rawProviderParameter) {}",
876             "}");
877 
878     CompilerTests.daggerCompiler(file)
879         .withProcessingOptions(compilerMode.processorOptions())
880         .compile(
881             subject -> {
882               subject.hasErrorCount(1);
883               subject.hasErrorContaining(
884                       "Dagger does not support injecting raw type: javax.inject.Provider")
885                   .onSource(file)
886                   .onLineContaining("Provider rawProviderParameter");
887             });
888   }
889 
890   @Test
rawMapFrameworkConstructorTypeParameter()891   public void rawMapFrameworkConstructorTypeParameter() {
892     Source file =
893         CompilerTests.javaSource(
894             "test.RawMapProviderParameter",
895             "package test;",
896             "",
897             "import dagger.Component;",
898             "import javax.inject.Inject;",
899             "import javax.inject.Provider;",
900             "import java.util.Map;",
901             "",
902             "class RawMapProviderParameter {",
903             "  @Inject",
904             "  RawMapProviderParameter(",
905             "      Map<String, Provider> rawProviderParameter) {}",
906             "}");
907 
908     CompilerTests.daggerCompiler(file)
909         .withProcessingOptions(compilerMode.processorOptions())
910         .compile(
911             subject -> {
912               subject.hasErrorCount(1);
913               subject.hasErrorContaining(
914                       "Dagger does not support injecting maps of raw framework types: "
915                       + "java.util.Map<java.lang.String,javax.inject.Provider>")
916                   .onSource(file)
917                   .onLineContaining("Map<String, Provider> rawProviderParameter");
918             });
919   }
920 
921   @Test
daggerProviderField()922   public void daggerProviderField() {
923     Source file =
924         CompilerTests.javaSource(
925             "test.DaggerProviderField",
926             "package test;",
927             "",
928             "import dagger.internal.Provider;",
929             "import javax.inject.Inject;",
930             "",
931             "class DaggerProviderField {",
932             "  @Inject",
933             "  Provider<String> fieldWithDaggerProvider;",
934             "}");
935 
936     CompilerTests.daggerCompiler(file)
937         .withProcessingOptions(compilerMode.processorOptions())
938         .compile(
939             subject -> {
940               subject.hasErrorCount(1);
941               subject.hasErrorContaining(
942                       "Dagger disallows injecting the type: "
943                       + "dagger.internal.Provider<java.lang.String>")
944                   .onSource(file)
945                   .onLineContaining("Provider<String> fieldWithDaggerProvider");
946             });
947   }
948 
949   @Test
daggerProviderMethodTypeParameter()950   public void daggerProviderMethodTypeParameter() {
951     Source file =
952         CompilerTests.javaSource(
953             "test.DaggerProviderParameter",
954             "package test;",
955             "",
956             "import dagger.internal.Provider;",
957             "import javax.inject.Inject;",
958             "",
959             "class DaggerProviderParameter {",
960             "  @Inject",
961             "  void methodInjection(",
962             "      Provider<String> daggerProviderParameter) {}",
963             "}");
964 
965     CompilerTests.daggerCompiler(file)
966         .withProcessingOptions(compilerMode.processorOptions())
967         .compile(
968             subject -> {
969               subject.hasErrorCount(1);
970               subject.hasErrorContaining(
971                       "Dagger disallows injecting the type: "
972                       + "dagger.internal.Provider<java.lang.String>")
973                   .onSource(file)
974                   .onLineContaining("Provider<String> daggerProviderParameter");
975             });
976   }
977 
978   @Test
daggerProviderConstructorTypeParameter()979   public void daggerProviderConstructorTypeParameter() {
980     Source file =
981         CompilerTests.javaSource(
982             "test.DaggerProviderParameter",
983             "package test;",
984             "",
985             "import dagger.Component;",
986             "import dagger.internal.Provider;",
987             "import javax.inject.Inject;",
988             "",
989             "class DaggerProviderParameter {",
990             "  @Inject",
991             "  DaggerProviderParameter(",
992             "      Provider<String> daggerProviderParameter) {}",
993             "}");
994 
995     CompilerTests.daggerCompiler(file)
996         .withProcessingOptions(compilerMode.processorOptions())
997         .compile(
998             subject -> {
999               subject.hasErrorCount(1);
1000               subject.hasErrorContaining(
1001                       "Dagger disallows injecting the type: "
1002                       + "dagger.internal.Provider<java.lang.String>")
1003                   .onSource(file)
1004                   .onLineContaining("Provider<String> daggerProviderParameter");
1005             });
1006   }
1007 
1008   @Test
rawDaggerProviderConstructorTypeParameter()1009   public void rawDaggerProviderConstructorTypeParameter() {
1010     Source file =
1011         CompilerTests.javaSource(
1012             "test.RawDaggerProviderParameter",
1013             "package test;",
1014             "",
1015             "import dagger.Component;",
1016             "import dagger.internal.Provider;",
1017             "import javax.inject.Inject;",
1018             "",
1019             "class RawDaggerProviderParameter {",
1020             "  @Inject",
1021             "  RawDaggerProviderParameter(",
1022             "      Provider rawDaggerProviderParameter) {}",
1023             "}");
1024 
1025     CompilerTests.daggerCompiler(file)
1026         .withProcessingOptions(compilerMode.processorOptions())
1027         .compile(
1028             subject -> {
1029               subject.hasErrorCount(1);
1030               subject.hasErrorContaining(
1031                       "Dagger disallows injecting the type: dagger.internal.Provider")
1032                   .onSource(file)
1033                   .onLineContaining("Provider rawDaggerProviderParameter");
1034             });
1035   }
1036 
1037   @Test
daggerMapProviderField()1038   public void daggerMapProviderField() {
1039     Source file =
1040         CompilerTests.javaSource(
1041             "test.DaggerMapProviderField",
1042             "package test;",
1043             "",
1044             "import dagger.internal.Provider;",
1045             "import javax.inject.Inject;",
1046             "import java.util.Map;",
1047             "",
1048             "class DaggerMapProviderField {",
1049             "  @Inject",
1050             "  Map<String, Provider<Long>> fieldWithDaggerMapProvider;",
1051             "}");
1052 
1053     CompilerTests.daggerCompiler(file)
1054         .withProcessingOptions(compilerMode.processorOptions())
1055         .compile(
1056             subject -> {
1057               subject.hasErrorCount(1);
1058               subject.hasErrorContaining(
1059                       "Dagger does not support injecting maps of disallowed types: "
1060                       + "java.util.Map<java.lang.String,dagger.internal.Provider<java.lang.Long>>")
1061                   .onSource(file)
1062                   .onLineContaining("Map<String, Provider<Long>> fieldWithDaggerMapProvider");
1063             });
1064   }
1065 
1066   @Test
daggerMapProviderMethodTypeParameter()1067   public void daggerMapProviderMethodTypeParameter() {
1068     Source file =
1069         CompilerTests.javaSource(
1070             "test.DaggerMapProviderParameter",
1071             "package test;",
1072             "",
1073             "import dagger.internal.Provider;",
1074             "import javax.inject.Inject;",
1075             "import java.util.Map;",
1076             "",
1077             "class DaggerMapProviderParameter {",
1078             "  @Inject",
1079             "  void methodInjection(",
1080             "      Map<String, Provider<Long>> daggerMapProviderParameter) {}",
1081             "}");
1082 
1083     CompilerTests.daggerCompiler(file)
1084         .withProcessingOptions(compilerMode.processorOptions())
1085         .compile(
1086             subject -> {
1087               subject.hasErrorCount(1);
1088               subject.hasErrorContaining(
1089                   "Dagger does not support injecting maps of disallowed types: "
1090                       + "java.util.Map<java.lang.String,dagger.internal.Provider<java.lang.Long>>")
1091                   .onSource(file)
1092                   .onLineContaining("Map<String, Provider<Long>> daggerMapProviderParameter");
1093             });
1094   }
1095 
1096   @Test
daggerMapProviderConstructorTypeParameter()1097   public void daggerMapProviderConstructorTypeParameter() {
1098     Source file =
1099         CompilerTests.javaSource(
1100             "test.DaggerMapProviderParameter",
1101             "package test;",
1102             "",
1103             "import dagger.Component;",
1104             "import dagger.internal.Provider;",
1105             "import javax.inject.Inject;",
1106             "import java.util.Map;",
1107             "",
1108             "class DaggerMapProviderParameter {",
1109             "  @Inject",
1110             "  DaggerMapProviderParameter(",
1111             "      Map<String, Provider<Long>> daggerMapProviderParameter) {}",
1112             "}");
1113 
1114     CompilerTests.daggerCompiler(file)
1115         .withProcessingOptions(compilerMode.processorOptions())
1116         .compile(
1117             subject -> {
1118               subject.hasErrorCount(1);
1119               subject.hasErrorContaining(
1120                   "Dagger does not support injecting maps of disallowed types: "
1121                   + "java.util.Map<java.lang.String,dagger.internal.Provider<java.lang.Long>>")
1122                   .onSource(file)
1123                   .onLineContaining("Map<String, Provider<Long>> daggerMapProviderParameter");
1124             });
1125   }
1126 
1127   @Test
rawDaggerMapProviderConstructorTypeParameter()1128   public void rawDaggerMapProviderConstructorTypeParameter() {
1129     Source file =
1130         CompilerTests.javaSource(
1131             "test.RawDaggerMapProviderParameter",
1132             "package test;",
1133             "",
1134             "import dagger.Component;",
1135             "import dagger.internal.Provider;",
1136             "import javax.inject.Inject;",
1137             "import java.util.Map;",
1138             "",
1139             "class RawDaggerMapProviderParameter {",
1140             "  @Inject",
1141             "  RawDaggerMapProviderParameter(",
1142             "      Map<String, Provider> rawDaggerMapProviderParameter) {}",
1143             "}");
1144 
1145     CompilerTests.daggerCompiler(file)
1146         .withProcessingOptions(compilerMode.processorOptions())
1147         .compile(
1148             subject -> {
1149               subject.hasErrorCount(1);
1150               subject.hasErrorContaining(
1151                   "Dagger does not support injecting maps of disallowed types: "
1152                   + "java.util.Map<java.lang.String,dagger.internal.Provider>")
1153                   .onSource(file)
1154                   .onLineContaining("Map<String, Provider> rawDaggerMapProviderParameter");
1155             });
1156   }
1157 
1158   @Test
injectsPrimitive()1159   public void injectsPrimitive() throws Exception {
1160     Source injectedType =
1161         CompilerTests.javaSource(
1162             "test.InjectedType",
1163             "package test;",
1164             "",
1165             "import javax.inject.Inject;",
1166             "",
1167             "class InjectedType {",
1168             "  @Inject InjectedType() {}",
1169             "",
1170             "  @Inject int primitiveInt;",
1171             "  @Inject Integer boxedInt;",
1172             "}");
1173 
1174     CompilerTests.daggerCompiler(injectedType)
1175         .withProcessingOptions(compilerMode.processorOptions())
1176         .compile(
1177             subject -> {
1178               subject.hasErrorCount(0);
1179               subject.generatedSource(
1180                   goldenFileRule.goldenSource("test/InjectedType_MembersInjector"));
1181               subject.generatedSource(
1182                   goldenFileRule.goldenSource("test/InjectedType_Factory"));
1183             });
1184   }
1185 
1186   @Test
accessibility()1187   public void accessibility() throws Exception {
1188     Source foo =
1189         CompilerTests.javaSource(
1190             "other.Foo",
1191             "package other;",
1192             "",
1193             "import javax.inject.Inject;",
1194             "",
1195             "class Foo {",
1196             "  @Inject Foo() {}",
1197             "}");
1198     Source inaccessible =
1199         CompilerTests.javaSource(
1200             "other.Inaccessible",
1201             "package other;",
1202             "",
1203             "import javax.inject.Inject;",
1204             "",
1205             "class Inaccessible {",
1206             "  @Inject Inaccessible() {}",
1207             "  @Inject Foo foo;",
1208             "  @Inject void method(Foo foo) {}",
1209             "}");
1210     Source usesInaccessible =
1211         CompilerTests.javaSource(
1212             "other.UsesInaccessible",
1213             "package other;",
1214             "",
1215             "import javax.inject.Inject;",
1216             "",
1217             "public class UsesInaccessible {",
1218             "  @Inject UsesInaccessible(Inaccessible inaccessible) {}",
1219             "}");
1220     Source component =
1221         CompilerTests.javaSource(
1222             "test.TestComponent",
1223             "package test;",
1224             "",
1225             "import dagger.Component;",
1226             "import other.UsesInaccessible;",
1227             "",
1228             "@Component",
1229             "interface TestComponent {",
1230             "  UsesInaccessible usesInaccessible();",
1231             "}");
1232 
1233     CompilerTests.daggerCompiler(foo, inaccessible, usesInaccessible, component)
1234         .withProcessingOptions(compilerMode.processorOptions())
1235         .compile(
1236             subject -> {
1237               subject.hasErrorCount(0);
1238               subject.generatedSource(
1239                   goldenFileRule.goldenSource("other/Inaccessible_MembersInjector"));
1240               subject.generatedSource(
1241                   goldenFileRule.goldenSource("test/DaggerTestComponent"));
1242             });
1243   }
1244 
1245   @Test
accessibleRawType_ofInaccessibleType()1246   public void accessibleRawType_ofInaccessibleType() throws Exception {
1247     Source inaccessible =
1248         CompilerTests.javaSource(
1249             "other.Inaccessible",
1250             "package other;",
1251             "",
1252             "class Inaccessible {}");
1253     Source inaccessiblesModule =
1254         CompilerTests.javaSource(
1255             "other.InaccessiblesModule",
1256             "package other;",
1257             "",
1258             "import dagger.Module;",
1259             "import dagger.Provides;",
1260             "import java.util.ArrayList;",
1261             "import java.util.List;",
1262             "import javax.inject.Provider;",
1263             "import javax.inject.Singleton;",
1264             "",
1265             "@Module",
1266             "public class InaccessiblesModule {",
1267             // force Provider initialization
1268             "  @Provides @Singleton static List<Inaccessible> inaccessibles() {",
1269             "    return new ArrayList<>();",
1270             "  }",
1271             "}");
1272     Source usesInaccessibles =
1273         CompilerTests.javaSource(
1274             "other.UsesInaccessibles",
1275             "package other;",
1276             "",
1277             "import java.util.List;",
1278             "import javax.inject.Inject;",
1279             "",
1280             "public class UsesInaccessibles {",
1281             "  @Inject UsesInaccessibles() {}",
1282             "  @Inject List<Inaccessible> inaccessibles;",
1283             "}");
1284     Source component =
1285         CompilerTests.javaSource(
1286             "test.TestComponent",
1287             "package test;",
1288             "",
1289             "import dagger.Component;",
1290             "import javax.inject.Singleton;",
1291             "import other.UsesInaccessibles;",
1292             "",
1293             "@Singleton",
1294             "@Component(modules = other.InaccessiblesModule.class)",
1295             "interface TestComponent {",
1296             "  UsesInaccessibles usesInaccessibles();",
1297             "}");
1298 
1299     CompilerTests.daggerCompiler(inaccessible, inaccessiblesModule, usesInaccessibles, component)
1300         .withProcessingOptions(compilerMode.processorOptions())
1301         .compile(
1302             subject -> {
1303               subject.hasErrorCount(0);
1304               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
1305             });
1306   }
1307 
1308   @Test
publicSupertypeHiddenSubtype()1309   public void publicSupertypeHiddenSubtype() throws Exception {
1310     Source foo =
1311         CompilerTests.javaSource(
1312             "other.Foo",
1313             "package other;",
1314             "",
1315             "import javax.inject.Inject;",
1316             "",
1317             "class Foo {",
1318             "  @Inject Foo() {}",
1319             "}");
1320     Source supertype =
1321         CompilerTests.javaSource(
1322             "other.Supertype",
1323             "package other;",
1324             "",
1325             "import javax.inject.Inject;",
1326             "",
1327             "public class Supertype<T> {",
1328             "  @Inject T t;",
1329             "}");
1330     Source subtype =
1331         CompilerTests.javaSource(
1332             "other.Subtype",
1333             "package other;",
1334             "",
1335             "import javax.inject.Inject;",
1336             "",
1337             "class Subtype extends Supertype<Foo> {",
1338             "  @Inject Subtype() {}",
1339             "}");
1340     Source injectsSubtype =
1341         CompilerTests.javaSource(
1342             "other.InjectsSubtype",
1343             "package other;",
1344             "",
1345             "import javax.inject.Inject;",
1346             "",
1347             "public class InjectsSubtype {",
1348             "  @Inject InjectsSubtype(Subtype s) {}",
1349             "}");
1350     Source component =
1351         CompilerTests.javaSource(
1352             "test.TestComponent",
1353             "package test;",
1354             "",
1355             "import dagger.Component;",
1356             "",
1357             "@Component",
1358             "interface TestComponent {",
1359             "  other.InjectsSubtype injectsSubtype();",
1360             "}");
1361 
1362     CompilerTests.daggerCompiler(foo, supertype, subtype, injectsSubtype, component)
1363         .withProcessingOptions(compilerMode.processorOptions())
1364         .compile(
1365             subject -> {
1366               subject.hasErrorCount(0);
1367               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
1368             });
1369   }
1370 
1371   // Shows that we shouldn't create a members injector for a type that doesn't have
1372   // @Inject fields or @Inject constructor even if it extends and is extended by types that do.
1373   @Test
middleClassNoFieldInjection()1374   public void middleClassNoFieldInjection() throws Exception {
1375     Source classA =
1376         CompilerTests.javaSource(
1377             "test.A",
1378             "package test;",
1379             "",
1380             "import javax.inject.Inject;",
1381             "",
1382             "class A extends B {",
1383             "  @Inject String valueA;",
1384             "}");
1385     Source classB =
1386         CompilerTests.javaSource(
1387             "test.B",
1388             "package test;",
1389             "",
1390             "class B extends C {",
1391             "}");
1392     Source classC =
1393         CompilerTests.javaSource(
1394             "test.C",
1395             "package test;",
1396             "",
1397             "import javax.inject.Inject;",
1398             "",
1399             "class C { ",
1400             "  @Inject String valueC;",
1401             "}");
1402 
1403     CompilerTests.daggerCompiler(classA, classB, classC)
1404         .withProcessingOptions(compilerMode.processorOptions())
1405         .compile(
1406             subject -> {
1407               subject.hasErrorCount(0);
1408               subject.generatedSource(goldenFileRule.goldenSource("test/A_MembersInjector"));
1409               subject.generatedSource(goldenFileRule.goldenSource("test/C_MembersInjector"));
1410 
1411               try {
1412                 subject.generatedSourceFileWithPath("test/B_MembersInjector");
1413                 // Can't throw an assertion error since it would be caught.
1414                 throw new IllegalStateException("Test generated a B_MembersInjector");
1415               } catch (AssertionError expected) {}
1416             });
1417   }
1418 
1419   // Shows that we do generate a MembersInjector for a type that has an @Inject
1420   // constructor and that extends a type with @Inject fields, even if it has no local field
1421   // injection sites
1422   // TODO(erichang): Are these even used anymore?
1423   @Test
testConstructorInjectedFieldInjection()1424   public void testConstructorInjectedFieldInjection() throws Exception {
1425     Source classA =
1426         CompilerTests.javaSource(
1427             "test.A",
1428             "package test;",
1429             "",
1430             "import javax.inject.Inject;",
1431             "",
1432             "class A extends B {",
1433             "  @Inject A() {}",
1434             "}");
1435     Source classB =
1436         CompilerTests.javaSource(
1437             "test.B",
1438             "package test;",
1439             "",
1440             "import javax.inject.Inject;",
1441             "",
1442             "class B { ",
1443             "  @Inject String valueB;",
1444             "}");
1445 
1446     CompilerTests.daggerCompiler(classA, classB)
1447         .withProcessingOptions(compilerMode.processorOptions())
1448         .compile(
1449             subject -> {
1450               subject.hasErrorCount(0);
1451               subject.generatedSource(goldenFileRule.goldenSource("test/A_MembersInjector"));
1452               subject.generatedSource(goldenFileRule.goldenSource("test/B_MembersInjector"));
1453             });
1454   }
1455 
1456   // Regression test for https://github.com/google/dagger/issues/3143
1457   @Test
testMembersInjectionBindingExistsInParentComponent()1458   public void testMembersInjectionBindingExistsInParentComponent() throws Exception {
1459     Source component =
1460         CompilerTests.javaSource(
1461             "test.MyComponent",
1462             "package test;",
1463             "",
1464             "import dagger.Component;",
1465             "",
1466             "@Component(modules = MyComponentModule.class)",
1467             "public interface MyComponent {",
1468             "  void inject(Bar bar);",
1469             "",
1470             "  MySubcomponent subcomponent();",
1471             "}");
1472 
1473     Source subcomponent =
1474         CompilerTests.javaSource(
1475             "test.MySubcomponent",
1476             "package test;",
1477             "",
1478             "import dagger.Subcomponent;",
1479             "",
1480             "@Subcomponent(modules = MySubcomponentModule.class)",
1481             "interface MySubcomponent {",
1482             "  Foo foo();",
1483             "}");
1484 
1485     Source foo =
1486         CompilerTests.javaSource(
1487             "test.Foo",
1488             "package test;",
1489             "",
1490             "import javax.inject.Inject;",
1491             "",
1492             "class Foo {",
1493             "  @Inject Foo(Bar bar) {}",
1494             "}");
1495 
1496     Source bar =
1497         CompilerTests.javaSource(
1498             "test.Bar",
1499             "package test;",
1500             "",
1501             "import java.util.Set;",
1502             "import javax.inject.Inject;",
1503             "",
1504             "class Bar {",
1505             "  @Inject Set<String> multibindingStrings;",
1506             "  @Inject Bar() {}",
1507             "}");
1508 
1509     Source componentModule =
1510         CompilerTests.javaSource(
1511             "test.MyComponentModule",
1512             "package test;",
1513             "",
1514             "import dagger.Module;",
1515             "import dagger.Provides;",
1516             "import dagger.multibindings.IntoSet;",
1517             "",
1518             "@Module",
1519             "interface MyComponentModule {",
1520             "  @Provides",
1521             "  @IntoSet",
1522             "  static String provideString() {",
1523             "    return \"\";",
1524             "  }",
1525             "}");
1526 
1527     Source subcomponentModule =
1528         CompilerTests.javaSource(
1529             "test.MySubcomponentModule",
1530             "package test;",
1531             "",
1532             "import dagger.Module;",
1533             "import dagger.Provides;",
1534             "import dagger.multibindings.IntoSet;",
1535             "",
1536             "@Module",
1537             "interface MySubcomponentModule {",
1538             "  @Provides",
1539             "  @IntoSet",
1540             "  static String provideString() {",
1541             "    return \"\";",
1542             "  }",
1543             "}");
1544 
1545     CompilerTests.daggerCompiler(
1546             component, subcomponent, foo, bar, componentModule, subcomponentModule)
1547         .withProcessingOptions(compilerMode.processorOptions())
1548         .compile(
1549             subject -> {
1550               subject.hasErrorCount(0);
1551               // Check that the injectBar() method is not shared across components.
1552               // We avoid sharing them in general because they may be different (e.g. in this case
1553               // we inject multibindings that are different across components).
1554               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerMyComponent"));
1555             });
1556 
1557   }
1558 
1559   // Test that if both a MembersInjectionBinding and ProvisionBinding both exist in the same
1560   // component they share the same inject methods rather than generating their own.
1561   @Test
testMembersInjectionBindingSharesInjectMethodsWithProvisionBinding()1562   public void testMembersInjectionBindingSharesInjectMethodsWithProvisionBinding()
1563       throws Exception {
1564     Source component =
1565         CompilerTests.javaSource(
1566             "test.MyComponent",
1567             "package test;",
1568             "",
1569             "import dagger.Component;",
1570             "",
1571             "@Component",
1572             "public interface MyComponent {",
1573             "  Foo foo();",
1574             "",
1575             "  void inject(Foo foo);",
1576             "}");
1577 
1578     Source foo =
1579         CompilerTests.javaSource(
1580             "test.Foo",
1581             "package test;",
1582             "",
1583             "import javax.inject.Inject;",
1584             "",
1585             "class Foo {",
1586             "  @Inject Bar bar;",
1587             "  @Inject Foo() {}",
1588             "}");
1589 
1590     Source bar =
1591         CompilerTests.javaSource(
1592             "test.Bar",
1593             "package test;",
1594             "",
1595             "import javax.inject.Inject;",
1596             "",
1597             "class Bar {",
1598             "  @Inject Bar() {}",
1599             "}");
1600     CompilerTests.daggerCompiler(component, foo, bar)
1601         .withProcessingOptions(compilerMode.processorOptions())
1602         .compile(
1603             subject -> {
1604               subject.hasErrorCount(0);
1605               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerMyComponent"));
1606             });
1607   }
1608 
1609   @Test
kotlinNullableFieldInjection()1610   public void kotlinNullableFieldInjection() {
1611     Source file =
1612         CompilerTests.kotlinSource(
1613             "MyClass.kt",
1614             "package test;",
1615             "",
1616             "import javax.inject.Inject;",
1617             "",
1618             "class MyClass @Inject constructor() {",
1619             "  @JvmField @Inject var nullableString: String? = null",
1620             "  @JvmField @Inject var nullableObject: Any? = null",
1621             "}");
1622     CompilerTests.daggerCompiler(file)
1623         .withProcessingOptions(compilerMode.processorOptions())
1624         .compile(
1625             subject -> {
1626               subject.hasErrorCount(0);
1627               Source expectedSource = goldenFileRule.goldenSource("test/MyClass_MembersInjector");
1628               subject.generatedSource(
1629                   CompilerTests.backend(subject) == XProcessingEnv.Backend.KSP
1630                       ? stripJetbrainsNullable(expectedSource)
1631                       : expectedSource);
1632             });
1633   }
1634 
1635   @Test
testMembersInjectionBindingWithNoInjectionSites()1636   public void testMembersInjectionBindingWithNoInjectionSites() throws Exception {
1637     Source component =
1638         CompilerTests.javaSource(
1639             "test.MyComponent",
1640             "package test;",
1641             "",
1642             "import dagger.Component;",
1643             "",
1644             "@Component",
1645             "public interface MyComponent {",
1646             "  void inject(Foo foo);",
1647             "",
1648             "  Foo injectAndReturn(Foo foo);",
1649             "}");
1650 
1651     Source foo =
1652         CompilerTests.javaSource(
1653             "test.Foo",
1654             "package test;",
1655             "",
1656             "class Foo {}");
1657 
1658     CompilerTests.daggerCompiler(component, foo)
1659         .withProcessingOptions(compilerMode.processorOptions())
1660         .compile(
1661             subject -> {
1662               subject.hasErrorCount(0);
1663               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerMyComponent"));
1664             });
1665   }
1666 
stripJetbrainsNullable(Source source)1667   private Source stripJetbrainsNullable(Source source) {
1668     return CompilerTests.javaSource(
1669         ((Source.JavaSource) source).getQName(),
1670         source
1671             .getContents()
1672             .replace("@Nullable ", "")
1673             .replace("import org.jetbrains.annotations.Nullable;\n", ""));
1674   }
1675 }
1676