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