• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 
21 import androidx.room.compiler.processing.XProcessingEnv;
22 import androidx.room.compiler.processing.util.DiagnosticMessage;
23 import androidx.room.compiler.processing.util.Source;
24 import com.google.common.collect.ImmutableList;
25 import dagger.testing.compile.CompilerTests;
26 import java.util.List;
27 import javax.tools.Diagnostic;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 import org.junit.runners.Parameterized;
31 import org.junit.runners.Parameterized.Parameters;
32 
33 @RunWith(Parameterized.class)
34 public class MissingBindingValidationTest {
35   private static final String JVM_SUPPRESS_WILDCARDS_MESSAGE =
36       "(For Kotlin sources, you may need to use '@JvmSuppressWildcards' or '@JvmWildcard' if you "
37           + "need to explicitly control the wildcards at a particular usage site.)";
38 
39   @Parameters(name = "{0}")
parameters()40   public static ImmutableList<Object[]> parameters() {
41     return CompilerMode.TEST_PARAMETERS;
42   }
43 
44   private final CompilerMode compilerMode;
45 
MissingBindingValidationTest(CompilerMode compilerMode)46   public MissingBindingValidationTest(CompilerMode compilerMode) {
47     this.compilerMode = compilerMode;
48   }
49 
50   @Test
dependOnInterface()51   public void dependOnInterface() {
52     Source component =
53         CompilerTests.javaSource(
54             "test.MyComponent",
55             "package test;",
56             "",
57             "import dagger.Component;",
58             "",
59             "@Component",
60             "interface MyComponent {",
61             "  Foo getFoo();",
62             "}");
63     Source injectable =
64         CompilerTests.javaSource(
65             "test.Foo",
66             "package test;",
67             "",
68             "import javax.inject.Inject;",
69             "",
70             "class Foo {",
71             "  @Inject Foo(Bar bar) {}",
72             "}");
73     Source nonInjectable =
74         CompilerTests.javaSource(
75             "test.Bar",
76             "package test;",
77             "",
78             "import javax.inject.Inject;",
79             "",
80             "interface Bar {}");
81     CompilerTests.daggerCompiler(component, injectable, nonInjectable)
82         .withProcessingOptions(compilerMode.processorOptions())
83         .compile(
84             subject -> {
85               subject.hasErrorCount(1);
86               subject.hasErrorContaining(
87                       "Bar cannot be provided without an @Provides-annotated method.")
88                   .onSource(component)
89                   .onLineContaining("interface MyComponent");
90             });
91   }
92 
93   @Test
entryPointDependsOnInterface()94   public void entryPointDependsOnInterface() {
95     Source component =
96         CompilerTests.javaSource(
97             "test.TestClass",
98             "package test;",
99             "",
100             "import dagger.Component;",
101             "",
102             "final class TestClass {",
103             "  interface A {}",
104             "",
105             "  @Component()",
106             "  interface AComponent {",
107             "    A getA();",
108             "  }",
109             "}");
110     CompilerTests.daggerCompiler(component)
111         .withProcessingOptions(compilerMode.processorOptions())
112         .compile(
113             subject -> {
114               subject.hasErrorCount(1);
115               subject.hasErrorContaining(
116                       "\033[1;31m[Dagger/MissingBinding]\033[0m TestClass.A cannot be provided "
117                           + "without an @Provides-annotated method.")
118                   .onSource(component)
119                   .onLineContaining("interface AComponent");
120             });
121   }
122 
123   @Test
entryPointDependsOnQualifiedInterface()124   public void entryPointDependsOnQualifiedInterface() {
125     Source component =
126         CompilerTests.javaSource(
127             "test.TestClass",
128             "package test;",
129             "",
130             "import dagger.Component;",
131             "import javax.inject.Qualifier;",
132             "",
133             "final class TestClass {",
134             "  @Qualifier @interface Q {}",
135             "  interface A {}",
136             "",
137             "  @Component()",
138             "  interface AComponent {",
139             "    @Q A qualifiedA();",
140             "  }",
141             "}");
142     CompilerTests.daggerCompiler(component)
143         .withProcessingOptions(compilerMode.processorOptions())
144         .compile(
145             subject -> {
146               subject.hasErrorCount(1);
147               subject.hasErrorContaining(
148                       "\033[1;31m[Dagger/MissingBinding]\033[0m @TestClass.Q TestClass.A cannot be "
149                           + "provided without an @Provides-annotated method.")
150                   .onSource(component)
151                   .onLineContaining("interface AComponent");
152             });
153   }
154 
constructorInjectionWithoutAnnotation()155   @Test public void constructorInjectionWithoutAnnotation() {
156     Source component =
157         CompilerTests.javaSource("test.TestClass",
158         "package test;",
159         "",
160         "import dagger.Component;",
161         "import dagger.Module;",
162         "import dagger.Provides;",
163         "import javax.inject.Inject;",
164         "",
165         "final class TestClass {",
166         "  static class A {",
167         "    A() {}",
168         "  }",
169         "",
170         "  @Component()",
171         "  interface AComponent {",
172         "    A getA();",
173         "  }",
174         "}");
175 
176     CompilerTests.daggerCompiler(component)
177         .withProcessingOptions(compilerMode.processorOptions())
178         .compile(
179             subject -> {
180               subject.hasErrorCount(1);
181               subject.hasErrorContaining(
182                       "TestClass.A cannot be provided without an @Inject constructor or an "
183                           + "@Provides-annotated method.")
184                   .onSource(component)
185                   .onLineContaining("interface AComponent");
186             });
187   }
188 
membersInjectWithoutProvision()189   @Test public void membersInjectWithoutProvision() {
190     Source component =
191         CompilerTests.javaSource(
192             "test.TestClass",
193             "package test;",
194             "",
195             "import dagger.Component;",
196             "import dagger.Module;",
197             "import dagger.Provides;",
198             "import javax.inject.Inject;",
199             "",
200             "final class TestClass {",
201             "  static class A {",
202             "    @Inject A() {}",
203             "  }",
204             "",
205             "  static class B {",
206             "    @Inject A a;",
207             "  }",
208             "",
209             "  @Component()",
210             "  interface AComponent {",
211             "    B getB();",
212             "  }",
213             "}");
214 
215     CompilerTests.daggerCompiler(component)
216         .withProcessingOptions(compilerMode.processorOptions())
217         .compile(
218             subject -> {
219               subject.hasErrorCount(1);
220               subject.hasErrorContaining(
221                       "TestClass.B cannot be provided without an @Inject constructor or an "
222                           + "@Provides-annotated method. This type supports members injection but "
223                           + "cannot be implicitly provided.")
224                   .onSource(component)
225                   .onLineContaining("interface AComponent");
226             });
227   }
228 
229   @Test
missingBindingWithSameKeyAsMembersInjectionMethod()230   public void missingBindingWithSameKeyAsMembersInjectionMethod() {
231     Source self =
232         CompilerTests.javaSource(
233             "test.Self",
234             "package test;",
235             "",
236             "import javax.inject.Inject;",
237             "import javax.inject.Provider;",
238             "",
239             "class Self {",
240             "  @Inject Provider<Self> selfProvider;",
241             "}");
242     Source component =
243         CompilerTests.javaSource(
244             "test.SelfComponent",
245             "package test;",
246             "",
247             "import dagger.Component;",
248             "",
249             "@Component",
250             "interface SelfComponent {",
251             "  void inject(Self target);",
252             "}");
253 
254     CompilerTests.daggerCompiler(self, component)
255         .withProcessingOptions(compilerMode.processorOptions())
256         .compile(
257             subject -> {
258               subject.hasErrorCount(1);
259               subject.hasErrorContaining("Self cannot be provided without an @Inject constructor")
260                   .onSource(component)
261                   .onLineContaining("interface SelfComponent");
262             });
263   }
264 
265   @Test
genericInjectClassWithWildcardDependencies()266   public void genericInjectClassWithWildcardDependencies() {
267     Source component =
268         CompilerTests.javaSource(
269             "test.TestComponent",
270             "package test;",
271             "",
272             "import dagger.Component;",
273             "",
274             "@Component",
275             "interface TestComponent {",
276             "  Foo<? extends Number> foo();",
277             "}");
278     Source foo =
279         CompilerTests.javaSource(
280             "test.Foo",
281             "package test;",
282             "",
283             "import javax.inject.Inject;",
284             "",
285             "final class Foo<T> {",
286             "  @Inject Foo(T t) {}",
287             "}");
288     CompilerTests.daggerCompiler(component, foo)
289         .withProcessingOptions(compilerMode.processorOptions())
290         .compile(
291             subject -> {
292               subject.hasErrorCount(1);
293               subject.hasErrorContaining(
294                   "Foo<? extends Number> cannot be provided "
295                       + "without an @Provides-annotated method");
296             });
297   }
298 
longChainOfDependencies()299   @Test public void longChainOfDependencies() {
300     Source component =
301         CompilerTests.javaSource(
302             "test.TestClass",
303             "package test;",
304             "",
305             "import dagger.Component;",
306             "import dagger.Lazy;",
307             "import dagger.Module;",
308             "import dagger.Provides;",
309             "import javax.inject.Inject;",
310             "import javax.inject.Named;",
311             "import javax.inject.Provider;",
312             "",
313             "final class TestClass {",
314             "  interface A {}",
315             "",
316             "  static class B {",
317             "    @Inject B(A a) {}",
318             "  }",
319             "",
320             "  static class C {",
321             "    @Inject B b;",
322             "    @Inject C(X x) {}",
323             "  }",
324             "",
325             "  interface D { }",
326             "",
327             "  static class DImpl implements D {",
328             "    @Inject DImpl(C c, B b) {}",
329             "  }",
330             "",
331             "  static class X {",
332             "    @Inject X() {}",
333             "  }",
334             "",
335             "  @Module",
336             "  static class DModule {",
337             "    @Provides @Named(\"slim shady\") D d(X x1, DImpl impl, X x2) { return impl; }",
338             "  }",
339             "",
340             "  @Component(modules = { DModule.class })",
341             "  interface AComponent {",
342             "    @Named(\"slim shady\") D getFoo();",
343             "    C injectC(C c);",
344             "    Provider<C> cProvider();",
345             "    Lazy<C> lazyC();",
346             "    Provider<Lazy<C>> lazyCProvider();",
347             "  }",
348             "}");
349 
350     CompilerTests.daggerCompiler(component)
351         .withProcessingOptions(compilerMode.processorOptions())
352         .compile(
353             subject -> {
354               subject.hasErrorCount(1);
355               subject.hasErrorContaining(
356                   String.join(
357                       "\n",
358                       "TestClass.A cannot be provided without an @Provides-annotated method.",
359                       "",
360                       "    TestClass.A is injected at",
361                       "        [TestClass.AComponent] TestClass.B(a)",
362                       "    TestClass.B is injected at",
363                       "        [TestClass.AComponent] TestClass.C.b",
364                       "    TestClass.C is injected at",
365                       "        [TestClass.AComponent] TestClass.AComponent.injectC(TestClass.C)",
366                       "The following other entry points also depend on it:",
367                       "    TestClass.AComponent.getFoo()",
368                       "    TestClass.AComponent.cProvider()",
369                       "    TestClass.AComponent.lazyC()",
370                       "    TestClass.AComponent.lazyCProvider()"))
371                   .onSource(component)
372                   .onLineContaining("interface AComponent");
373             });
374   }
375 
376   @Test
bindsMethodAppearsInTrace()377   public void bindsMethodAppearsInTrace() {
378     Source component =
379         CompilerTests.javaSource(
380             "TestComponent",
381             "import dagger.Component;",
382             "",
383             "@Component(modules = TestModule.class)",
384             "interface TestComponent {",
385             "  TestInterface testInterface();",
386             "}");
387     Source interfaceFile =
388         CompilerTests.javaSource("TestInterface", "interface TestInterface {}");
389     Source implementationFile =
390         CompilerTests.javaSource(
391             "TestImplementation",
392             "import javax.inject.Inject;",
393             "",
394             "final class TestImplementation implements TestInterface {",
395             "  @Inject TestImplementation(String missingBinding) {}",
396             "}");
397     Source module =
398         CompilerTests.javaSource(
399             "TestModule",
400             "import dagger.Binds;",
401             "import dagger.Module;",
402             "",
403             "@Module",
404             "interface TestModule {",
405             "  @Binds abstract TestInterface bindTestInterface(TestImplementation implementation);",
406             "}");
407 
408     CompilerTests.daggerCompiler(component, module, interfaceFile, implementationFile)
409         .withProcessingOptions(compilerMode.processorOptions())
410         .compile(
411             subject -> {
412               subject.hasErrorCount(1);
413               subject.hasErrorContaining(
414                   String.join(
415                       "\n",
416                       "String cannot be provided without an @Inject constructor or an "
417                           + "@Provides-annotated method.",
418                       "",
419                       "    String is injected at",
420                       "        [TestComponent] TestImplementation(missingBinding)",
421                       "    TestImplementation is injected at",
422                       "        [TestComponent] TestModule.bindTestInterface(implementation)",
423                       "    TestInterface is requested at",
424                       "        [TestComponent] TestComponent.testInterface()"))
425                   .onSource(component)
426                   .onLineContaining("interface TestComponent");
427             });
428   }
429 
resolvedParametersInDependencyTrace()430   @Test public void resolvedParametersInDependencyTrace() {
431     Source generic =
432         CompilerTests.javaSource("test.Generic",
433         "package test;",
434         "",
435         "import javax.inject.Inject;",
436         "import javax.inject.Provider;",
437         "",
438         "final class Generic<T> {",
439         "  @Inject Generic(T t) {}",
440         "}");
441     Source testClass =
442         CompilerTests.javaSource("test.TestClass",
443         "package test;",
444         "",
445         "import javax.inject.Inject;",
446         "import java.util.List;",
447         "",
448         "final class TestClass {",
449         "  @Inject TestClass(List list) {}",
450         "}");
451     Source usesTest =
452         CompilerTests.javaSource("test.UsesTest",
453         "package test;",
454         "",
455         "import javax.inject.Inject;",
456         "",
457         "final class UsesTest {",
458         "  @Inject UsesTest(Generic<TestClass> genericTestClass) {}",
459         "}");
460     Source component =
461         CompilerTests.javaSource("test.TestComponent",
462         "package test;",
463         "",
464         "import dagger.Component;",
465         "",
466         "@Component",
467         "interface TestComponent {",
468         "  UsesTest usesTest();",
469         "}");
470 
471     CompilerTests.daggerCompiler(generic, testClass, usesTest, component)
472         .withProcessingOptions(compilerMode.processorOptions())
473         .compile(
474             subject -> {
475               subject.hasErrorCount(1);
476               subject.hasErrorContaining(
477                   String.join(
478                       "\n",
479                       "List cannot be provided without an @Provides-annotated method.",
480                       "",
481                       "    List is injected at",
482                       "        [TestComponent] TestClass(list)",
483                       "    TestClass is injected at",
484                       "        [TestComponent] Generic(t)",
485                       "    Generic<TestClass> is injected at",
486                       "        [TestComponent] UsesTest(genericTestClass)",
487                       "    UsesTest is requested at",
488                       "        [TestComponent] TestComponent.usesTest()"));
489             });
490   }
491 
resolvedVariablesInDependencyTrace()492   @Test public void resolvedVariablesInDependencyTrace() {
493     Source generic =
494         CompilerTests.javaSource(
495             "test.Generic",
496             "package test;",
497             "",
498             "import javax.inject.Inject;",
499             "import javax.inject.Provider;",
500             "",
501             "final class Generic<T> {",
502             "  @Inject T t;",
503             "  @Inject Generic() {}",
504             "}");
505     Source testClass =
506         CompilerTests.javaSource(
507             "test.TestClass",
508             "package test;",
509             "",
510             "import javax.inject.Inject;",
511             "import java.util.List;",
512             "",
513             "final class TestClass {",
514             "  @Inject TestClass(List list) {}",
515             "}");
516     Source usesTest =
517         CompilerTests.javaSource(
518             "test.UsesTest",
519             "package test;",
520             "",
521             "import javax.inject.Inject;",
522             "",
523             "final class UsesTest {",
524             "  @Inject UsesTest(Generic<TestClass> genericTestClass) {}",
525             "}");
526     Source component =
527         CompilerTests.javaSource(
528             "test.TestComponent",
529             "package test;",
530             "",
531             "import dagger.Component;",
532             "",
533             "@Component",
534             "interface TestComponent {",
535             "  UsesTest usesTest();",
536             "}");
537 
538     CompilerTests.daggerCompiler(generic, testClass, usesTest, component)
539         .withProcessingOptions(compilerMode.processorOptions())
540         .compile(
541             subject -> {
542               subject.hasErrorCount(1);
543               subject.hasErrorContaining(
544                   String.join(
545                       "\n",
546                       "List cannot be provided without an @Provides-annotated method.",
547                       "",
548                       "    List is injected at",
549                       "        [TestComponent] TestClass(list)",
550                       "    TestClass is injected at",
551                       "        [TestComponent] Generic.t",
552                       "    Generic<TestClass> is injected at",
553                       "        [TestComponent] UsesTest(genericTestClass)",
554                       "    UsesTest is requested at",
555                       "        [TestComponent] TestComponent.usesTest()"));
556             });
557   }
558 
559   @Test
bindingUsedOnlyInSubcomponentDependsOnBindingOnlyInSubcomponent()560   public void bindingUsedOnlyInSubcomponentDependsOnBindingOnlyInSubcomponent() {
561     Source parent =
562         CompilerTests.javaSource(
563             "Parent",
564             "import dagger.Component;",
565             "",
566             "@Component(modules = ParentModule.class)",
567             "interface Parent {",
568             "  Child child();",
569             "}");
570     Source parentModule =
571         CompilerTests.javaSource(
572             "ParentModule",
573             "import dagger.Module;",
574             "import dagger.Provides;",
575             "",
576             "@Module",
577             "class ParentModule {",
578             "  @Provides static Object needsString(String string) {",
579             "    return \"needs string: \" + string;",
580             "  }",
581             "}");
582     Source child =
583         CompilerTests.javaSource(
584             "Child",
585             "import dagger.Subcomponent;",
586             "",
587             "@Subcomponent(modules = ChildModule.class)",
588             "interface Child {",
589             "  String string();",
590             "  Object needsString();",
591             "}");
592     Source childModule =
593         CompilerTests.javaSource(
594             "ChildModule",
595             "import dagger.Module;",
596             "import dagger.Provides;",
597             "",
598             "@Module",
599             "class ChildModule {",
600             "  @Provides static String string() {",
601             "    return \"child string\";",
602             "  }",
603             "}");
604 
605     CompilerTests.daggerCompiler(parent, parentModule, child, childModule)
606         .withProcessingOptions(compilerMode.processorOptions())
607         .compile(
608             subject -> {
609               subject.hasErrorCount(1);
610               subject.hasErrorContaining("String cannot be provided");
611               subject.hasErrorContaining("[Child] Child.needsString()")
612                   .onSource(parent)
613                   .onLineContaining("interface Parent");
614             });
615   }
616 
617   @Test
multibindingContributionBetweenAncestorComponentAndEntrypointComponent()618   public void multibindingContributionBetweenAncestorComponentAndEntrypointComponent() {
619     Source parent =
620         CompilerTests.javaSource(
621             "Parent",
622             "import dagger.Component;",
623             "",
624             "@Component(modules = ParentModule.class)",
625             "interface Parent {",
626             "  Child child();",
627             "}");
628     Source child =
629         CompilerTests.javaSource(
630             "Child",
631             "import dagger.Subcomponent;",
632             "",
633             "@Subcomponent(modules = ChildModule.class)",
634             "interface Child {",
635             "  Grandchild grandchild();",
636             "}");
637     Source grandchild =
638         CompilerTests.javaSource(
639             "Grandchild",
640             "import dagger.Subcomponent;",
641             "",
642             "@Subcomponent",
643             "interface Grandchild {",
644             "  Object object();",
645             "}");
646 
647     Source parentModule =
648         CompilerTests.javaSource(
649             "ParentModule",
650             "import dagger.Module;",
651             "import dagger.Provides;",
652             "import dagger.multibindings.IntoSet;",
653             "import java.util.Set;",
654             "",
655             "@Module",
656             "class ParentModule {",
657             "  @Provides static Object dependsOnSet(Set<String> strings) {",
658             "    return \"needs strings: \" + strings;",
659             "  }",
660             "",
661             "  @Provides @IntoSet static String contributesToSet() {",
662             "    return \"parent string\";",
663             "  }",
664             "",
665             "  @Provides int missingDependency(double dub) {",
666             "    return 4;",
667             "  }",
668             "}");
669     Source childModule =
670         CompilerTests.javaSource(
671             "ChildModule",
672             "import dagger.Module;",
673             "import dagger.Provides;",
674             "import dagger.multibindings.IntoSet;",
675             "",
676             "@Module",
677             "class ChildModule {",
678             "  @Provides @IntoSet static String contributesToSet(int i) {",
679             "    return \"\" + i;",
680             "  }",
681             "}");
682     CompilerTests.daggerCompiler(parent, parentModule, child, childModule, grandchild)
683         .withProcessingOptions(compilerMode.processorOptions())
684         .compile(
685             subject -> {
686               subject.hasErrorCount(1);
687               // TODO(b/243720787): Replace with CompilationResultSubject#hasErrorContainingMatch()
688               subject.hasErrorContaining(
689                   String.join(
690                       "\n",
691                       "Double cannot be provided without an @Inject constructor or an "
692                           + "@Provides-annotated method.",
693                       "",
694                       "    Double is injected at",
695                       "        [Parent] ParentModule.missingDependency(dub)",
696                       "    Integer is injected at",
697                       "        [Child] ChildModule.contributesToSet(i)",
698                       "    Set<String> is injected at",
699                       "        [Child] ParentModule.dependsOnSet(strings)",
700                       "    Object is requested at",
701                       "        [Grandchild] Grandchild.object() [Parent → Child → Grandchild]"))
702                   .onSource(parent)
703                   .onLineContaining("interface Parent");
704             });
705   }
706 
707   @Test
manyDependencies()708   public void manyDependencies() {
709     Source component =
710         CompilerTests.javaSource(
711             "test.TestComponent",
712             "package test;",
713             "",
714             "import dagger.Component;",
715             "",
716             "@Component(modules = TestModule.class)",
717             "interface TestComponent {",
718             "  Object object();",
719             "  String string();",
720             "}");
721     Source module =
722         CompilerTests.javaSource(
723             "test.TestModule",
724             "package test;",
725             "",
726             "import dagger.Binds;",
727             "import dagger.Module;",
728             "import dagger.Provides;",
729             "",
730             "@Module",
731             "abstract class TestModule {",
732             "  @Binds abstract Object object(NotBound notBound);",
733             "",
734             "  @Provides static String string(NotBound notBound, Object object) {",
735             "    return notBound.toString();",
736             "  }",
737             "}");
738     Source notBound =
739         CompilerTests.javaSource(
740             "test.NotBound", //
741             "package test;",
742             "",
743             "interface NotBound {}");
744     CompilerTests.daggerCompiler(component, module, notBound)
745         .withProcessingOptions(compilerMode.processorOptions())
746         .compile(
747             subject -> {
748               subject.hasErrorCount(1);
749               subject.hasErrorContaining(
750                   String.join(
751                       "\n",
752                       "NotBound cannot be provided without an @Provides-annotated method.",
753                       "",
754                       "    NotBound is injected at",
755                       "        [TestComponent] TestModule.object(notBound)",
756                       "    Object is requested at",
757                       "        [TestComponent] TestComponent.object()",
758                       "It is also requested at:",
759                       "    TestModule.string(notBound, …)",
760                       "The following other entry points also depend on it:",
761                       "    TestComponent.string()"))
762                   .onSource(component)
763                   .onLineContaining("interface TestComponent");
764             });
765   }
766 
767   @Test
tooManyRequests()768   public void tooManyRequests() {
769     Source foo =
770         CompilerTests.javaSource(
771             "test.Foo",
772             "package test;",
773             "",
774             "import javax.inject.Inject;",
775             "",
776             "final class Foo {",
777             "  @Inject Foo(",
778             "      String one,",
779             "      String two,",
780             "      String three,",
781             "      String four,",
782             "      String five,",
783             "      String six,",
784             "      String seven,",
785             "      String eight,",
786             "      String nine,",
787             "      String ten,",
788             "      String eleven,",
789             "      String twelve,",
790             "      String thirteen) {",
791             "  }",
792             "}");
793     Source component =
794         CompilerTests.javaSource(
795             "test.TestComponent",
796             "package test;",
797             "",
798             "import dagger.Component;",
799             "",
800             "@Component",
801             "interface TestComponent {",
802             "  String string();",
803             "  Foo foo();",
804             "}");
805 
806     CompilerTests.daggerCompiler(foo, component)
807         .withProcessingOptions(compilerMode.processorOptions())
808         .compile(
809             subject -> {
810               subject.hasErrorCount(1);
811               subject.hasErrorContaining(
812                   String.join(
813                       "\n",
814                       "String cannot be provided without an @Inject constructor or an "
815                           + "@Provides-annotated method.",
816                       "",
817                       "    String is requested at",
818                       "        [TestComponent] TestComponent.string()",
819                       "It is also requested at:",
820                       "    Foo(one, …)",
821                       "    Foo(…, two, …)",
822                       "    Foo(…, three, …)",
823                       "    Foo(…, four, …)",
824                       "    Foo(…, five, …)",
825                       "    Foo(…, six, …)",
826                       "    Foo(…, seven, …)",
827                       "    Foo(…, eight, …)",
828                       "    Foo(…, nine, …)",
829                       "    Foo(…, ten, …)",
830                       "    and 3 others",
831                       "The following other entry points also depend on it:",
832                       "    TestComponent.foo()"))
833                   .onSource(component)
834                   .onLineContaining("interface TestComponent");
835             });
836   }
837 
838   @Test
tooManyEntryPoints()839   public void tooManyEntryPoints() {
840     Source component =
841         CompilerTests.javaSource(
842             "test.TestComponent",
843             "package test;",
844             "",
845             "import dagger.Component;",
846             "",
847             "@Component",
848             "interface TestComponent {",
849             "  String string1();",
850             "  String string2();",
851             "  String string3();",
852             "  String string4();",
853             "  String string5();",
854             "  String string6();",
855             "  String string7();",
856             "  String string8();",
857             "  String string9();",
858             "  String string10();",
859             "  String string11();",
860             "  String string12();",
861             "}");
862 
863     CompilerTests.daggerCompiler(component)
864         .withProcessingOptions(compilerMode.processorOptions())
865         .compile(
866             subject -> {
867               subject.hasErrorCount(1);
868               subject.hasErrorContaining(
869                   String.join(
870                       "\n",
871                       "String cannot be provided without an @Inject constructor or an "
872                           + "@Provides-annotated method.",
873                       "",
874                       "    String is requested at",
875                       "        [TestComponent] TestComponent.string1()",
876                       "The following other entry points also depend on it:",
877                       "    TestComponent.string2()",
878                       "    TestComponent.string3()",
879                       "    TestComponent.string4()",
880                       "    TestComponent.string5()",
881                       "    TestComponent.string6()",
882                       "    TestComponent.string7()",
883                       "    TestComponent.string8()",
884                       "    TestComponent.string9()",
885                       "    TestComponent.string10()",
886                       "    TestComponent.string11()",
887                       "    and 1 other"))
888                   .onSource(component)
889                   .onLineContaining("interface TestComponent");
890             });
891   }
892 
893   @Test
missingBindingInAllComponentsAndEntryPoints()894   public void missingBindingInAllComponentsAndEntryPoints() {
895     Source parent =
896         CompilerTests.javaSource(
897             "Parent",
898             "import dagger.Component;",
899             "",
900             "@Component",
901             "interface Parent {",
902             "  Foo foo();",
903             "  Bar bar();",
904             "  Child child();",
905             "}");
906     Source child =
907         CompilerTests.javaSource(
908             "Child",
909             "import dagger.Subcomponent;",
910             "",
911             "@Subcomponent",
912             "interface Child {",
913             "  Foo foo();",
914             "  Baz baz();",
915             "}");
916     Source foo =
917         CompilerTests.javaSource(
918             "Foo",
919             "import javax.inject.Inject;",
920             "",
921             "class Foo {",
922             "  @Inject Foo(Bar bar) {}",
923             "}");
924     Source bar =
925         CompilerTests.javaSource(
926             "Bar",
927             "import javax.inject.Inject;",
928             "",
929             "class Bar {",
930             "  @Inject Bar(Baz baz) {}",
931             "}");
932     Source baz =
933         CompilerTests.javaSource("Baz", "class Baz {}");
934 
935     CompilerTests.daggerCompiler(parent, child, foo, bar, baz)
936         .withProcessingOptions(compilerMode.processorOptions())
937         .compile(
938             subject -> {
939               subject.hasErrorCount(1);
940               subject.hasErrorContaining(
941                   String.join(
942                       "\n",
943                       "Baz cannot be provided without an @Inject constructor or an "
944                           + "@Provides-annotated method.",
945                       "",
946                       "    Baz is injected at",
947                       "        [Parent] Bar(baz)",
948                       "    Bar is requested at",
949                       "        [Parent] Parent.bar()",
950                       "The following other entry points also depend on it:",
951                       "    Parent.foo()",
952                       "    Child.foo() [Parent → Child]",
953                       "    Child.baz() [Parent → Child]"))
954                   .onSource(parent)
955                   .onLineContaining("interface Parent");
956             });
957   }
958 
959   // Regression test for b/147423208 where if the same subcomponent was used
960   // in two different parts of the hierarchy and only one side had a missing binding
961   // incorrect caching during binding graph conversion might cause validation to pass
962   // incorrectly.
963   @Test
sameSubcomponentUsedInDifferentHierarchies()964   public void sameSubcomponentUsedInDifferentHierarchies() {
965     Source parent =
966         CompilerTests.javaSource("test.Parent",
967         "package test;",
968         "",
969         "import dagger.Component;",
970         "",
971         "@Component",
972         "interface Parent {",
973         "  Child1 getChild1();",
974         "  Child2 getChild2();",
975         "}");
976     Source child1 =
977         CompilerTests.javaSource("test.Child1",
978         "package test;",
979         "",
980         "import dagger.Subcomponent;",
981         "",
982         "@Subcomponent(modules = LongModule.class)",
983         "interface Child1 {",
984         "  RepeatedSub getSub();",
985         "}");
986     Source child2 =
987         CompilerTests.javaSource("test.Child2",
988         "package test;",
989         "",
990         "import dagger.Subcomponent;",
991         "",
992         "@Subcomponent",
993         "interface Child2 {",
994         "  RepeatedSub getSub();",
995         "}");
996     Source repeatedSub =
997         CompilerTests.javaSource("test.RepeatedSub",
998         "package test;",
999         "",
1000         "import dagger.Subcomponent;",
1001         "",
1002         "@Subcomponent",
1003         "interface RepeatedSub {",
1004         "  Foo getFoo();",
1005         "}");
1006     Source injectable =
1007         CompilerTests.javaSource("test.Foo",
1008         "package test;",
1009         "",
1010         "import javax.inject.Inject;",
1011         "",
1012         "class Foo {",
1013         "  @Inject Foo(Long value) {}",
1014         "}");
1015     Source module =
1016         CompilerTests.javaSource("test.LongModule",
1017         "package test;",
1018         "",
1019         "import dagger.Module;",
1020         "import dagger.Provides;",
1021         "",
1022         "@Module",
1023         "interface LongModule {",
1024         "  @Provides static Long provideLong() {",
1025         "    return 0L;",
1026         "  }",
1027         "}");
1028     CompilerTests.daggerCompiler(parent, child1, child2, repeatedSub, injectable, module)
1029         .withProcessingOptions(compilerMode.processorOptions())
1030         .compile(
1031             subject -> {
1032               subject.hasErrorCount(1);
1033               subject.hasErrorContaining("Long cannot be provided without an @Inject constructor")
1034                   .onSource(parent)
1035                   .onLineContaining("interface Parent");
1036             });
1037   }
1038 
1039   @Test
requestUnusedBindingInDifferentComponent()1040   public void requestUnusedBindingInDifferentComponent() {
1041     Source parent =
1042         CompilerTests.javaSource(
1043             "test.Parent",
1044             "package test;",
1045             "",
1046             "import dagger.Component;",
1047             "",
1048             "@Component",
1049             "interface Parent {",
1050             "  Child1 getChild1();",
1051             "  Child2 getChild2();",
1052             "}");
1053     Source child1 =
1054         CompilerTests.javaSource(
1055             "test.Child1",
1056             "package test;",
1057             "",
1058             "import dagger.Subcomponent;",
1059             "",
1060             "@Subcomponent",
1061             "interface Child1 {",
1062             "  Object getObject();",
1063             "}");
1064     Source child2 =
1065         CompilerTests.javaSource(
1066             "test.Child2",
1067             "package test;",
1068             "",
1069             "import dagger.Subcomponent;",
1070             "",
1071             "@Subcomponent(modules = Child2Module.class)",
1072             "interface Child2 {}");
1073     Source child2Module =
1074         CompilerTests.javaSource(
1075             "test.Child2Module",
1076             "package test;",
1077             "",
1078             "import dagger.Module;",
1079             "import dagger.Provides;",
1080             "",
1081             "@Module",
1082             "interface Child2Module {",
1083             "  @Provides",
1084             "  static Object provideObject() {",
1085             "    return new Object();",
1086             "  }",
1087             "}");
1088 
1089     CompilerTests.daggerCompiler(parent, child1, child2, child2Module)
1090         .withProcessingOptions(compilerMode.processorOptions())
1091         .compile(
1092             subject -> {
1093               subject.hasErrorCount(1);
1094               subject.hasErrorContaining(
1095                   String.join(
1096                       "\n",
1097                       "Object cannot be provided without an @Inject constructor or an "
1098                           + "@Provides-annotated method.",
1099                       "",
1100                       "    Object is requested at",
1101                       "        [Child1] Child1.getObject() [Parent → Child1]",
1102                       "",
1103                       "Note: Object is provided in the following other components:",
1104                       "    [Child2] Child2Module.provideObject()",
1105                       "",
1106                       "======================"));
1107             });
1108   }
1109 
1110   @Test
sameSubcomponentUsedInDifferentHierarchiesMissingBindingFromOneSide()1111   public void sameSubcomponentUsedInDifferentHierarchiesMissingBindingFromOneSide() {
1112     Source parent =
1113         CompilerTests.javaSource(
1114             "test.Parent",
1115             "package test;",
1116             "",
1117             "import dagger.Component;",
1118             "",
1119             "@Component",
1120             "interface Parent {",
1121             "  Child1 getChild1();",
1122             "  Child2 getChild2();",
1123             "}");
1124     Source child1 =
1125         CompilerTests.javaSource(
1126             "test.Child1",
1127             "package test;",
1128             "",
1129             "import dagger.Subcomponent;",
1130             "",
1131             "@Subcomponent(modules = Child1Module.class)",
1132             "interface Child1 {",
1133             "  RepeatedSub getSub();",
1134             "}");
1135     Source child2 =
1136         CompilerTests.javaSource(
1137             "test.Child2",
1138             "package test;",
1139             "",
1140             "import dagger.Subcomponent;",
1141             "",
1142             "@Subcomponent(modules = Child2Module.class)",
1143             "interface Child2 {",
1144             "  RepeatedSub getSub();",
1145             "}");
1146     Source repeatedSub =
1147         CompilerTests.javaSource(
1148             "test.RepeatedSub",
1149             "package test;",
1150             "",
1151             "import dagger.Subcomponent;",
1152             "",
1153             "@Subcomponent(modules = RepeatedSubModule.class)",
1154             "interface RepeatedSub {",
1155             "  Object getObject();",
1156             "}");
1157     Source child1Module =
1158         CompilerTests.javaSource(
1159             "test.Child1Module",
1160             "package test;",
1161             "",
1162             "import dagger.Module;",
1163             "import dagger.Provides;",
1164             "import java.util.Set;",
1165             "import dagger.multibindings.Multibinds;",
1166             "",
1167             "@Module",
1168             "interface Child1Module {",
1169             "  @Multibinds Set<Integer> multibindIntegerSet();",
1170             "}");
1171     Source child2Module =
1172         CompilerTests.javaSource(
1173             "test.Child2Module",
1174             "package test;",
1175             "",
1176             "import dagger.Module;",
1177             "import dagger.Provides;",
1178             "import java.util.Set;",
1179             "import dagger.multibindings.Multibinds;",
1180             "",
1181             "@Module",
1182             "interface Child2Module {",
1183             "  @Multibinds Set<Integer> multibindIntegerSet();",
1184             "",
1185             "  @Provides",
1186             "  static Object provideObject(Set<Integer> intSet) {",
1187             "    return new Object();",
1188             "  }",
1189             "}");
1190     Source repeatedSubModule =
1191         CompilerTests.javaSource(
1192             "test.RepeatedSubModule",
1193             "package test;",
1194             "",
1195             "import dagger.Module;",
1196             "import dagger.Provides;",
1197             "import dagger.multibindings.IntoSet;",
1198             "import java.util.Set;",
1199             "import dagger.multibindings.Multibinds;",
1200             "",
1201             "@Module",
1202             "interface RepeatedSubModule {",
1203             "  @Provides",
1204             "  @IntoSet",
1205             "  static Integer provideInt() {",
1206             "    return 9;",
1207             "  }",
1208             "}");
1209 
1210     CompilerTests.daggerCompiler(
1211             parent, child1, child2, repeatedSub, child1Module, child2Module, repeatedSubModule)
1212         .withProcessingOptions(compilerMode.processorOptions())
1213         .compile(
1214             subject -> {
1215               subject.hasErrorCount(1);
1216               subject.hasErrorContaining(
1217                   String.join(
1218                       "\n",
1219                       "Object cannot be provided without an @Inject constructor or an "
1220                           + "@Provides-annotated method.",
1221                       "",
1222                       "    Object is requested at",
1223                       "        [RepeatedSub] RepeatedSub.getObject() "
1224                           + "[Parent → Child1 → RepeatedSub]",
1225                       "",
1226                       "Note: Object is provided in the following other components:",
1227                       "    [Child2] Child2Module.provideObject(…)",
1228                       "",
1229                       "======================"));
1230             });
1231   }
1232 
1233   @Test
differentComponentPkgSameSimpleNameMissingBinding()1234   public void differentComponentPkgSameSimpleNameMissingBinding() {
1235     Source parent =
1236         CompilerTests.javaSource(
1237             "test.Parent",
1238             "package test;",
1239             "",
1240             "import dagger.Component;",
1241             "",
1242             "@Component",
1243             "interface Parent {",
1244             "  Child1 getChild1();",
1245             "  Child2 getChild2();",
1246             "}");
1247     Source child1 =
1248         CompilerTests.javaSource(
1249             "test.Child1",
1250             "package test;",
1251             "",
1252             "import dagger.Subcomponent;",
1253             "",
1254             "@Subcomponent(modules = Child1Module.class)",
1255             "interface Child1 {",
1256             "  foo.Sub getSub();",
1257             "}");
1258     Source child2 =
1259         CompilerTests.javaSource(
1260             "test.Child2",
1261             "package test;",
1262             "",
1263             "import dagger.Subcomponent;",
1264             "",
1265             "@Subcomponent(modules = Child2Module.class)",
1266             "interface Child2 {",
1267             "  bar.Sub getSub();",
1268             "}");
1269     Source sub1 =
1270         CompilerTests.javaSource(
1271             "foo.Sub",
1272             "package foo;",
1273             "",
1274             "import dagger.Subcomponent;",
1275             "",
1276             "@Subcomponent(modules = test.RepeatedSubModule.class)",
1277             "public interface Sub {",
1278             "  Object getObject();",
1279             "}");
1280     Source sub2 =
1281         CompilerTests.javaSource(
1282             "bar.Sub",
1283             "package bar;",
1284             "",
1285             "import dagger.Subcomponent;",
1286             "",
1287             "@Subcomponent(modules = test.RepeatedSubModule.class)",
1288             "public interface Sub {",
1289             "  Object getObject();",
1290             "}");
1291     Source child1Module =
1292         CompilerTests.javaSource(
1293             "test.Child1Module",
1294             "package test;",
1295             "",
1296             "import dagger.Module;",
1297             "import dagger.Provides;",
1298             "import java.util.Set;",
1299             "import dagger.multibindings.Multibinds;",
1300             "",
1301             "@Module",
1302             "interface Child1Module {",
1303             "  @Multibinds Set<Integer> multibindIntegerSet();",
1304             "}");
1305     Source child2Module =
1306         CompilerTests.javaSource(
1307             "test.Child2Module",
1308             "package test;",
1309             "",
1310             "import dagger.Module;",
1311             "import dagger.Provides;",
1312             "import java.util.Set;",
1313             "import dagger.multibindings.Multibinds;",
1314             "",
1315             "@Module",
1316             "interface Child2Module {",
1317             "  @Multibinds Set<Integer> multibindIntegerSet();",
1318             "",
1319             "  @Provides",
1320             "  static Object provideObject(Set<Integer> intSet) {",
1321             "    return new Object();",
1322             "  }",
1323             "}");
1324     Source repeatedSubModule =
1325         CompilerTests.javaSource(
1326             "test.RepeatedSubModule",
1327             "package test;",
1328             "",
1329             "import dagger.Module;",
1330             "import dagger.Provides;",
1331             "import dagger.multibindings.IntoSet;",
1332             "import java.util.Set;",
1333             "import dagger.multibindings.Multibinds;",
1334             "",
1335             "@Module",
1336             "public interface RepeatedSubModule {",
1337             "  @Provides",
1338             "  @IntoSet",
1339             "  static Integer provideInt() {",
1340             "    return 9;",
1341             "  }",
1342             "}");
1343 
1344     CompilerTests.daggerCompiler(
1345             parent, child1, child2, sub1, sub2, child1Module, child2Module, repeatedSubModule)
1346         .withProcessingOptions(compilerMode.processorOptions())
1347         .compile(
1348             subject -> {
1349               subject.hasErrorCount(1);
1350               subject.hasErrorContaining(
1351                   String.join(
1352                       "\n",
1353                       "Object cannot be provided without an @Inject constructor or an "
1354                           + "@Provides-annotated method.",
1355                       "",
1356                       "    Object is requested at",
1357                       "        [Sub] Sub.getObject() [Parent → Child1 → Sub]",
1358                       "",
1359                       "Note: Object is provided in the following other components:",
1360                       "    [Child2] Child2Module.provideObject(…)",
1361                       "",
1362                       "======================"));
1363             });
1364   }
1365 
1366   @Test
requestWildcardTypeWithNonWildcardTypeBindingProvided_failsWithMissingBinding()1367   public void requestWildcardTypeWithNonWildcardTypeBindingProvided_failsWithMissingBinding() {
1368     Source component =
1369         CompilerTests.javaSource(
1370             "test.MyComponent",
1371             "package test;",
1372             "",
1373             "import dagger.Component;",
1374             "import java.util.Set;",
1375             "",
1376             "@Component(modules = TestModule.class)",
1377             "interface MyComponent {",
1378             "  Foo getFoo();",
1379             "  Child getChild();",
1380             "}");
1381     Source child =
1382         CompilerTests.javaSource(
1383             "test.Child",
1384             "package test;",
1385             "",
1386             "import dagger.Subcomponent;",
1387             "",
1388             "@Subcomponent(modules = ChildModule.class)",
1389             "interface Child {}");
1390     Source childModule =
1391         CompilerTests.javaSource(
1392             "test.ChildModule",
1393             "package test;",
1394             "",
1395             "import dagger.Module;",
1396             "import dagger.Provides;",
1397             "import java.util.Set;",
1398             "import java.util.HashSet;",
1399             "",
1400             "@Module",
1401             "interface ChildModule {",
1402             "  @Provides",
1403             "  static Set<? extends Bar> provideBar() {",
1404             "    return new HashSet<Bar>();",
1405             "  }",
1406             "}");
1407     Source fooSrc =
1408         CompilerTests.javaSource(
1409             "test.Foo",
1410             "package test;",
1411             "",
1412             "import javax.inject.Inject;",
1413             "import java.util.Set;",
1414             "",
1415             "class Foo {",
1416             "  @Inject Foo(Set<? extends Bar> bar) {}",
1417             "}");
1418     Source barSrc =
1419         CompilerTests.javaSource("test.Bar", "package test;", "", "public interface Bar {}");
1420     Source moduleSrc =
1421         CompilerTests.javaSource(
1422             "test.TestModule",
1423             "package test;",
1424             "",
1425             "import dagger.Module;",
1426             "import dagger.Provides;",
1427             "import dagger.multibindings.ElementsIntoSet;",
1428             "import java.util.Set;",
1429             "import java.util.HashSet;",
1430             "",
1431             "@Module",
1432             "public class TestModule {",
1433             "   @ElementsIntoSet",
1434             "   @Provides",
1435             "   Set<Bar> provideBars() {",
1436             "     return new HashSet<Bar>();",
1437             "   }",
1438             "}");
1439 
1440     CompilerTests.daggerCompiler(component, child, childModule, fooSrc, barSrc, moduleSrc)
1441         .withProcessingOptions(compilerMode.processorOptions())
1442         .compile(
1443             subject -> {
1444               subject.hasErrorCount(1);
1445               subject
1446                   .hasErrorContaining(
1447                       String.join(
1448                           "\n",
1449                           "Set<? extends Bar> cannot be provided without an @Provides-annotated "
1450                               + "method.",
1451                           "",
1452                           "    Set<? extends Bar> is injected at",
1453                           "        [MyComponent] Foo(bar)",
1454                           "    Foo is requested at",
1455                           "        [MyComponent] MyComponent.getFoo()",
1456                           "",
1457                           "Note: Set<? extends Bar> is provided in the following other components:",
1458                           "    [Child] ChildModule.provideBar()",
1459                           "",
1460                           "Note: A similar binding is provided in the following other components:",
1461                           "    Set<Bar> is provided at:",
1462                           "        [MyComponent] Dagger-generated binding for Set<Bar>",
1463                           JVM_SUPPRESS_WILDCARDS_MESSAGE,
1464                           "",
1465                           "======================"))
1466                   .onSource(component)
1467                   .onLineContaining("interface MyComponent");
1468             });
1469   }
1470 
1471   @Test
1472   public void
injectParameterDoesNotSuppressWildcardGeneration_conflictsWithNonWildcardTypeBinding()1473       injectParameterDoesNotSuppressWildcardGeneration_conflictsWithNonWildcardTypeBinding() {
1474     Source component =
1475         CompilerTests.javaSource(
1476             "test.MyComponent",
1477             "package test;",
1478             "",
1479             "import dagger.Component;",
1480             "import java.util.Set;",
1481             "",
1482             "@Component(modules = TestModule.class)",
1483             "interface MyComponent {",
1484             "  Foo getFoo();",
1485             "}");
1486     Source fooSrc =
1487         CompilerTests.kotlinSource(
1488             "Foo.kt",
1489             "package test",
1490             "",
1491             "import javax.inject.Inject",
1492             "",
1493             "class Foo @Inject constructor(val bar: Set<Bar>) {}");
1494     Source barSrc =
1495         CompilerTests.javaSource("test.Bar", "package test;", "", "public interface Bar {}");
1496     Source moduleSrc =
1497         CompilerTests.javaSource(
1498             "test.TestModule",
1499             "package test;",
1500             "",
1501             "import dagger.Module;",
1502             "import dagger.Provides;",
1503             "import dagger.multibindings.ElementsIntoSet;",
1504             "import java.util.Set;",
1505             "import java.util.HashSet;",
1506             "",
1507             "@Module",
1508             "public class TestModule {",
1509             "   @ElementsIntoSet",
1510             "   @Provides",
1511             "   Set<Bar> provideBars() {",
1512             "     return new HashSet<Bar>();",
1513             "   }",
1514             "}");
1515 
1516     CompilerTests.daggerCompiler(component, fooSrc, barSrc, moduleSrc)
1517         .withProcessingOptions(compilerMode.processorOptions())
1518         .compile(
1519             subject -> {
1520               subject.hasErrorCount(1);
1521               subject
1522                   .hasErrorContaining(
1523                       String.join(
1524                           "\n",
1525                           "Set<? extends Bar> cannot be provided without an @Provides-annotated "
1526                               + "method.",
1527                           "",
1528                           "    Set<? extends Bar> is injected at",
1529                           "        [MyComponent] Foo(bar)",
1530                           "    Foo is requested at",
1531                           "        [MyComponent] MyComponent.getFoo()",
1532                           "",
1533                           "Note: A similar binding is provided in the following other components:",
1534                           "    Set<Bar> is provided at:",
1535                           "        [MyComponent] Dagger-generated binding for Set<Bar>",
1536                           JVM_SUPPRESS_WILDCARDS_MESSAGE,
1537                           "",
1538                           "======================"))
1539                   .onSource(component)
1540                   .onLineContaining("interface MyComponent");
1541             });
1542   }
1543 
1544   @Test
injectWildcardTypeWithNonWildcardTypeBindingProvided_failsWithMissingBinding()1545   public void injectWildcardTypeWithNonWildcardTypeBindingProvided_failsWithMissingBinding() {
1546     Source component =
1547         CompilerTests.javaSource(
1548             "test.MyComponent",
1549             "package test;",
1550             "",
1551             "import dagger.Component;",
1552             "import java.util.Set;",
1553             "",
1554             "@Component(modules = TestModule.class)",
1555             "interface MyComponent {",
1556             "  Foo getFoo();",
1557             "}");
1558     Source fooSrc =
1559         CompilerTests.javaSource(
1560             "test.Foo",
1561             "package test;",
1562             "",
1563             "import javax.inject.Inject;",
1564             "import java.util.Set;",
1565             "",
1566             "class Foo {",
1567             "  @Inject Set<? extends Bar> bar;",
1568             "  @Inject Foo() {}",
1569             "}");
1570     Source barSrc =
1571         CompilerTests.javaSource("test.Bar", "package test;", "", "public interface Bar {}");
1572     Source moduleSrc =
1573         CompilerTests.javaSource(
1574             "test.TestModule",
1575             "package test;",
1576             "",
1577             "import dagger.Module;",
1578             "import dagger.Provides;",
1579             "import dagger.multibindings.ElementsIntoSet;",
1580             "import java.util.Set;",
1581             "import java.util.HashSet;",
1582             "",
1583             "@Module",
1584             "public class TestModule {",
1585             "   @ElementsIntoSet",
1586             "   @Provides",
1587             "   Set<Bar> provideBars() {",
1588             "     return new HashSet<Bar>();",
1589             "   }",
1590             "}");
1591 
1592     CompilerTests.daggerCompiler(component, fooSrc, barSrc, moduleSrc)
1593         .withProcessingOptions(compilerMode.processorOptions())
1594         .compile(
1595             subject -> {
1596               subject.hasErrorCount(1);
1597               subject
1598                   .hasErrorContaining(
1599                       String.join(
1600                           "\n",
1601                           "Set<? extends Bar> cannot be provided without an @Provides-annotated "
1602                               + "method.",
1603                           "",
1604                           "    Set<? extends Bar> is injected at",
1605                           "        [MyComponent] Foo.bar",
1606                           "    Foo is requested at",
1607                           "        [MyComponent] MyComponent.getFoo()",
1608                           "",
1609                           "Note: A similar binding is provided in the following other components:",
1610                           "    Set<Bar> is provided at:",
1611                           "        [MyComponent] Dagger-generated binding for Set<Bar>",
1612                           JVM_SUPPRESS_WILDCARDS_MESSAGE,
1613                           "",
1614                           "======================"))
1615                   .onSource(component)
1616                   .onLineContaining("interface MyComponent");
1617             });
1618   }
1619 
1620   @Test
requestFinalClassWithWildcardAnnotation_missingWildcardTypeBinding()1621   public void requestFinalClassWithWildcardAnnotation_missingWildcardTypeBinding() {
1622     Source component =
1623         CompilerTests.javaSource(
1624             "test.MyComponent",
1625             "package test;",
1626             "",
1627             "import dagger.Component;",
1628             "import java.util.Set;",
1629             "",
1630             "@Component(modules = TestModule.class)",
1631             "interface MyComponent {",
1632             "  Foo getFoo();",
1633             "}");
1634     Source fooSrc =
1635         CompilerTests.kotlinSource(
1636             "test.Foo.kt",
1637             "package test",
1638             "",
1639             "import javax.inject.Inject",
1640             "",
1641             "class Foo @Inject constructor(val bar: List<Bar>) {}");
1642     Source barSrc =
1643         CompilerTests.javaSource("test.Bar", "package test;", "", "public final class Bar {}");
1644     Source moduleSrc =
1645         CompilerTests.kotlinSource(
1646             "test.TestModule.kt",
1647             "package test",
1648             "",
1649             "import dagger.Module",
1650             "import dagger.Provides",
1651             "import dagger.multibindings.ElementsIntoSet",
1652             "",
1653             "@Module",
1654             "object TestModule {",
1655             "   @Provides fun provideBars(): List<@JvmWildcard Bar> = setOf()",
1656             "}");
1657 
1658     CompilerTests.daggerCompiler(component, fooSrc, barSrc, moduleSrc)
1659         .withProcessingOptions(compilerMode.processorOptions())
1660         .compile(
1661             subject -> {
1662               subject.hasErrorCount(1);
1663               subject
1664                   .hasErrorContaining(
1665                       String.join(
1666                           "\n",
1667                           "List<Bar> cannot be provided without an @Provides-annotated method.",
1668                           "",
1669                           "    List<Bar> is injected at",
1670                           "        [MyComponent] Foo(bar)",
1671                           "    Foo is requested at",
1672                           "        [MyComponent] MyComponent.getFoo()",
1673                           "",
1674                           "Note: A similar binding is provided in the following other components:",
1675                           "    List<? extends Bar> is provided at:",
1676                           "        [MyComponent] TestModule.provideBars()",
1677                           JVM_SUPPRESS_WILDCARDS_MESSAGE,
1678                           "",
1679                           "======================"))
1680                   .onSource(component)
1681                   .onLineContaining("interface MyComponent");
1682             });
1683   }
1684 
1685   @Test
multipleTypeParameters_notSuppressWildcardType_failsWithMissingBinding()1686   public void multipleTypeParameters_notSuppressWildcardType_failsWithMissingBinding() {
1687     Source component =
1688         CompilerTests.javaSource(
1689             "test.MyComponent",
1690             "package test;",
1691             "",
1692             "import dagger.Component;",
1693             "import java.util.Set;",
1694             "",
1695             "@Component(modules = TestModule.class)",
1696             "interface MyComponent {",
1697             "  Foo getFoo();",
1698             "}");
1699     Source fooSrc =
1700         CompilerTests.kotlinSource(
1701             "test.Foo.kt",
1702             "package test",
1703             "",
1704             "import javax.inject.Inject",
1705             "",
1706             "class Foo @Inject constructor(val bar: Bar<Baz, Baz, Set<Baz>>) {}");
1707     Source barSrc =
1708         CompilerTests.kotlinSource(
1709             "test.Bar.kt", "package test", "", "class Bar<out T1, T2, T3> {}");
1710 
1711     Source bazSrc =
1712         CompilerTests.javaSource("test.Baz", "package test;", "", "public interface Baz {}");
1713 
1714     Source moduleSrc =
1715         CompilerTests.javaSource(
1716             "test.TestModule",
1717             "package test;",
1718             "",
1719             "import dagger.Module;",
1720             "import dagger.Provides;",
1721             "import java.util.Set;",
1722             "",
1723             "@Module",
1724             "public class TestModule {",
1725             "   @Provides",
1726             "   Bar<Baz, Baz, Set<Baz>> provideBar() {",
1727             "     return new Bar<Baz, Baz, Set<Baz>>();",
1728             "   }",
1729             "}");
1730 
1731     CompilerTests.daggerCompiler(component, fooSrc, barSrc, bazSrc, moduleSrc)
1732         .withProcessingOptions(compilerMode.processorOptions())
1733         .compile(
1734             subject -> {
1735               subject.hasErrorCount(1);
1736               subject
1737                   .hasErrorContaining(
1738                       String.join(
1739                           "\n",
1740                           // TODO(b/324325095): Align KSP and KAPT error message.
1741                           CompilerTests.backend(subject) == XProcessingEnv.Backend.KSP
1742                               ? "Bar<? extends Baz,Baz,Set<Baz>> cannot be provided without an "
1743                                   + "@Inject constructor or an @Provides-annotated method."
1744                               : "Bar<? extends Baz,Baz,Set<Baz>> cannot be provided without an "
1745                                   + "@Provides-annotated method.",
1746                           "",
1747                           "    Bar<? extends Baz,Baz,Set<Baz>> is injected at",
1748                           "        [MyComponent] Foo(bar)",
1749                           "    Foo is requested at",
1750                           "        [MyComponent] MyComponent.getFoo()",
1751                           "",
1752                           "Note: A similar binding is provided in the following other components:",
1753                           "    Bar<Baz,Baz,Set<Baz>> is provided at:",
1754                           "        [MyComponent] TestModule.provideBar()",
1755                           JVM_SUPPRESS_WILDCARDS_MESSAGE,
1756                           "",
1757                           "======================"))
1758                   .onSource(component)
1759                   .onLineContaining("interface MyComponent");
1760             });
1761   }
1762 
1763   @Test
missingBindingWithoutQualifier_warnAboutSimilarTypeWithQualifierExists()1764   public void missingBindingWithoutQualifier_warnAboutSimilarTypeWithQualifierExists() {
1765     Source qualifierSrc =
1766         CompilerTests.javaSource(
1767             "test.MyQualifier",
1768             "package test;",
1769             "",
1770             "import javax.inject.Qualifier;",
1771             "",
1772             "@Qualifier",
1773             "@interface MyQualifier {}");
1774     Source component =
1775         CompilerTests.javaSource(
1776             "test.MyComponent",
1777             "package test;",
1778             "",
1779             "import dagger.Component;",
1780             "import java.util.Set;",
1781             "",
1782             "@Component(modules = TestModule.class)",
1783             "interface MyComponent {",
1784             "  Foo getFoo();",
1785             "}");
1786     Source fooSrc =
1787         CompilerTests.kotlinSource(
1788             "Foo.kt",
1789             "package test",
1790             "",
1791             "import javax.inject.Inject",
1792             "",
1793             "class Foo @Inject constructor(val bar: Set<Bar>) {}");
1794     Source barSrc =
1795         CompilerTests.javaSource("test.Bar", "package test;", "", "public interface Bar {}");
1796     Source moduleSrc =
1797         CompilerTests.javaSource(
1798             "test.TestModule",
1799             "package test;",
1800             "",
1801             "import dagger.Module;",
1802             "import dagger.Provides;",
1803             "import dagger.multibindings.ElementsIntoSet;",
1804             "import java.util.Set;",
1805             "import java.util.HashSet;",
1806             "",
1807             "@Module",
1808             "public class TestModule {",
1809             "   @ElementsIntoSet",
1810             "   @Provides",
1811             "   @MyQualifier",
1812             "   Set<Bar> provideBars() {",
1813             "     return new HashSet<Bar>();",
1814             "   }",
1815             "}");
1816 
1817     CompilerTests.daggerCompiler(qualifierSrc, component, fooSrc, barSrc, moduleSrc)
1818         .withProcessingOptions(compilerMode.processorOptions())
1819         .compile(
1820             subject -> {
1821               subject.hasErrorCount(1);
1822               subject.hasErrorContaining("MissingBinding");
1823               List<DiagnosticMessage> diagnostics =
1824                   subject.getCompilationResult().getDiagnostics().get(Diagnostic.Kind.ERROR);
1825               assertThat(diagnostics).hasSize(1);
1826               assertThat(diagnostics.get(0).getMsg())
1827                   .doesNotContain("bindings with similar types exists in the graph");
1828             });
1829   }
1830 
1831   @Test
missingWildcardTypeWithObjectBound_providedRawType_warnAboutSimilarTypeExists()1832   public void missingWildcardTypeWithObjectBound_providedRawType_warnAboutSimilarTypeExists() {
1833     Source component =
1834         CompilerTests.javaSource(
1835             "test.MyComponent",
1836             "package test;",
1837             "",
1838             "import dagger.Component;",
1839             "import java.util.Set;",
1840             "",
1841             "@Component(modules = TestModule.class)",
1842             "interface MyComponent {",
1843             "  Foo getFoo();",
1844             "}");
1845     Source fooSrc =
1846         CompilerTests.kotlinSource(
1847             "test.Foo.kt",
1848             "package test",
1849             "",
1850             "import javax.inject.Inject",
1851             "",
1852             "class Foo @Inject constructor(val bar: Bar<Object>) {}");
1853     Source barSrc =
1854         CompilerTests.kotlinSource("test.Bar.kt", "package test", "", "class Bar<out T1> {}");
1855     Source moduleSrc =
1856         CompilerTests.javaSource(
1857             "test.TestModule",
1858             "package test;",
1859             "",
1860             "import dagger.Module;",
1861             "import dagger.Provides;",
1862             "import java.util.Set;",
1863             "",
1864             "@Module",
1865             "public class TestModule {",
1866             "   @Provides",
1867             "   Bar provideBar() {",
1868             "     return new Bar<Object>();",
1869             "   }",
1870             "}");
1871 
1872     CompilerTests.daggerCompiler(component, fooSrc, barSrc, moduleSrc)
1873         .withProcessingOptions(compilerMode.processorOptions())
1874         .compile(
1875             subject -> {
1876               subject.hasErrorCount(1);
1877               subject.hasErrorContaining(
1878                   String.join(
1879                       "\n",
1880                       // TODO(b/324325095): Align KSP and KAPT error message.
1881                       CompilerTests.backend(subject) == XProcessingEnv.Backend.KSP
1882                           ? "Bar<?> cannot be provided without an @Inject constructor or an "
1883                               + "@Provides-annotated method."
1884                           : "Bar<?> cannot be provided without an @Provides-annotated method.",
1885                       "",
1886                       "    Bar<?> is injected at",
1887                       "        [MyComponent] Foo(bar)",
1888                       "    Foo is requested at",
1889                       "        [MyComponent] MyComponent.getFoo()",
1890                       "",
1891                       "Note: A similar binding is provided in the following other components:",
1892                       "    Bar is provided at:",
1893                       "        [MyComponent] TestModule.provideBar()",
1894                       JVM_SUPPRESS_WILDCARDS_MESSAGE,
1895                       "",
1896                       "======================"));
1897             });
1898   }
1899 
1900   @Test
missingWildcardType_providedRawType_warnAboutSimilarTypeExists()1901   public void missingWildcardType_providedRawType_warnAboutSimilarTypeExists() {
1902     Source component =
1903         CompilerTests.javaSource(
1904             "test.MyComponent",
1905             "package test;",
1906             "",
1907             "import dagger.Component;",
1908             "import java.util.Set;",
1909             "",
1910             "@Component(modules = TestModule.class)",
1911             "interface MyComponent {",
1912             "  Foo getFoo();",
1913             "}");
1914     Source fooSrc =
1915         CompilerTests.kotlinSource(
1916             "test.Foo.kt",
1917             "package test",
1918             "",
1919             "import javax.inject.Inject",
1920             "",
1921             "class Foo @Inject constructor(val bar: Bar<String>) {}");
1922     Source barSrc =
1923         CompilerTests.kotlinSource("test.Bar.kt", "package test", "", "class Bar<out T1> {}");
1924     Source moduleSrc =
1925         CompilerTests.javaSource(
1926             "test.TestModule",
1927             "package test;",
1928             "",
1929             "import dagger.Module;",
1930             "import dagger.Provides;",
1931             "import java.util.Set;",
1932             "",
1933             "@Module",
1934             "public class TestModule {",
1935             "   @Provides",
1936             "   Bar provideBar() {",
1937             "     return new Bar<Object>();",
1938             "   }",
1939             "}");
1940 
1941     CompilerTests.daggerCompiler(component, fooSrc, barSrc, moduleSrc)
1942         .withProcessingOptions(compilerMode.processorOptions())
1943         .compile(
1944             subject -> {
1945               subject.hasErrorCount(1);
1946               subject.hasErrorContaining("MissingBinding");
1947               List<DiagnosticMessage> diagnostics =
1948                   subject.getCompilationResult().getDiagnostics().get(Diagnostic.Kind.ERROR);
1949               assertThat(diagnostics).hasSize(1);
1950               assertThat(diagnostics.get(0).getMsg())
1951                   .doesNotContain("bindings with similar types exists in the graph");
1952             });
1953   }
1954 
1955   // Regression test for b/367426609
1956   @Test
failsWithMissingBindingInGrandchild()1957   public void failsWithMissingBindingInGrandchild() {
1958     Source parent =
1959         CompilerTests.javaSource(
1960             "test.Parent",
1961             "package test;",
1962             "",
1963             "import dagger.Component;",
1964             "",
1965             "@Component(modules = ParentModule.class)",
1966             "interface Parent {",
1967             "  Child child();",
1968             "}");
1969     Source child =
1970         CompilerTests.javaSource(
1971             "test.Child",
1972             "package test;",
1973             "",
1974             "import dagger.Subcomponent;",
1975             "",
1976             "@Subcomponent(modules = ChildModule.class)",
1977             "interface Child {",
1978             "  Grandchild grandchild();",
1979             "}");
1980     Source grandchild =
1981         CompilerTests.javaSource(
1982             "test.Grandchild",
1983             "package test;",
1984             "",
1985             "import dagger.Subcomponent;",
1986             "",
1987             "@Subcomponent(modules=GrandchildModule.class)",
1988             "interface Grandchild {",
1989             // Note: it's important that Qux is first to reproduce the error in b/367426609.
1990             "  Qux getQux();",
1991             "  Foo getFoo();",
1992             "}");
1993     Source parentModule =
1994         CompilerTests.javaSource(
1995             "test.ParentModule",
1996             "package test;",
1997             "",
1998             "import dagger.BindsOptionalOf;",
1999             "import dagger.Module;",
2000             "import dagger.Provides;",
2001             "import java.util.Optional;",
2002             "",
2003             "@Module",
2004             "interface ParentModule {",
2005             "  @BindsOptionalOf",
2006             "  String optionalString();",
2007             "",
2008             // depend on an @BindsOptionalOf to force re-resolution in subcomponents.
2009             "  @Provides",
2010             "  static Foo provideFoo(Optional<String> str, Qux qux) { return null; }",
2011             "}");
2012     Source childModule =
2013         CompilerTests.javaSource(
2014             "test.ChildModule",
2015             "package test;",
2016             "",
2017             "import dagger.Module;",
2018             "import dagger.Provides;",
2019             "",
2020             "@Module",
2021             "interface ChildModule {",
2022             "  @Provides",
2023             "  static Qux provideQux() { return null; }",
2024             "}");
2025     Source grandchildModule =
2026         CompilerTests.javaSource(
2027             "test.GrandchildModule",
2028             "package test;",
2029             "",
2030             "import dagger.Module;",
2031             "import dagger.Provides;",
2032             "",
2033             "@Module",
2034             "interface GrandchildModule {",
2035             "  @Provides",
2036             "  static String provideString() { return null; }",
2037             "}");
2038     Source foo =
2039         CompilerTests.javaSource( // force one-string-per-line format
2040             "test.Foo",
2041             "package test;",
2042             "",
2043             "interface Foo {}");
2044     Source bar =
2045         CompilerTests.javaSource( // force one-string-per-line format
2046             "test.Bar",
2047             "package test;",
2048             "",
2049             "interface Bar {}");
2050     Source qux =
2051         CompilerTests.javaSource( // force one-string-per-line format
2052             "test.Qux",
2053             "package test;",
2054             "",
2055             "interface Qux {}");
2056 
2057     CompilerTests.daggerCompiler(
2058             parent, child, grandchild, parentModule, childModule, grandchildModule, foo, bar, qux)
2059         .withProcessingOptions(compilerMode.processorOptions())
2060         .compile(subject -> subject.hasErrorCount(0));
2061   }
2062 
2063   // Regression test for b/367426609
2064   @Test
failsWithMissingBindingInGrandchild_dependencyTracePresent()2065   public void failsWithMissingBindingInGrandchild_dependencyTracePresent() {
2066     Source parent =
2067         CompilerTests.javaSource(
2068             "test.Parent",
2069             "package test;",
2070             "",
2071             "import dagger.Component;",
2072             "",
2073             "@Component(modules = ParentModule.class)",
2074             "interface Parent {",
2075             "  Child child();",
2076             "}");
2077     Source child =
2078         CompilerTests.javaSource(
2079             "test.Child",
2080             "package test;",
2081             "",
2082             "import dagger.Subcomponent;",
2083             "",
2084             "@Subcomponent(modules = ChildModule.class)",
2085             "interface Child {",
2086             "  Grandchild grandchild();",
2087             "}");
2088     Source grandchild =
2089         CompilerTests.javaSource(
2090             "test.Grandchild",
2091             "package test;",
2092             "",
2093             "import dagger.Subcomponent;",
2094             "",
2095             "@Subcomponent(modules=GrandchildModule.class)",
2096             "interface Grandchild {",
2097             "  Foo getFoo();",
2098             "}");
2099     Source parentModule =
2100         CompilerTests.javaSource(
2101             "test.ParentModule",
2102             "package test;",
2103             "",
2104             "import dagger.BindsOptionalOf;",
2105             "import dagger.Module;",
2106             "import dagger.Provides;",
2107             "import java.util.Optional;",
2108             "",
2109             "@Module",
2110             "interface ParentModule {",
2111             "  @BindsOptionalOf",
2112             "  String optionalString();",
2113             "",
2114             // depend on an @BindsOptionalOf to force re-resolution in subcomponents.
2115             "  @Provides",
2116             "  static Foo provideFoo(Optional<String> str, Qux qux) { return null; }",
2117             "}");
2118     Source childModule =
2119         CompilerTests.javaSource(
2120             "test.ChildModule",
2121             "package test;",
2122             "",
2123             "import dagger.Module;",
2124             "import dagger.Provides;",
2125             "",
2126             "@Module",
2127             "interface ChildModule {",
2128             "  @Provides",
2129             "  static Qux provideQux() { return null; }",
2130             "}");
2131     Source grandchildModule =
2132         CompilerTests.javaSource(
2133             "test.GrandchildModule",
2134             "package test;",
2135             "",
2136             "import dagger.Module;",
2137             "import dagger.Provides;",
2138             "",
2139             "@Module",
2140             "interface GrandchildModule {",
2141             "  @Provides",
2142             "  static String provideString() { return null; }",
2143             "}");
2144     Source foo =
2145         CompilerTests.javaSource( // force one-string-per-line format
2146             "test.Foo",
2147             "package test;",
2148             "",
2149             "interface Foo {}");
2150     Source bar =
2151         CompilerTests.javaSource( // force one-string-per-line format
2152             "test.Bar",
2153             "package test;",
2154             "",
2155             "interface Bar {}");
2156     Source qux =
2157         CompilerTests.javaSource( // force one-string-per-line format
2158             "test.Qux",
2159             "package test;",
2160             "",
2161             "interface Qux {}");
2162 
2163     CompilerTests.daggerCompiler(
2164             parent, child, grandchild, parentModule, childModule, grandchildModule, foo, bar, qux)
2165         .withProcessingOptions(compilerMode.processorOptions())
2166         .compile(subject -> subject.hasErrorCount(0));
2167   }
2168 }
2169