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