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