1 /* 2 * Copyright (C) 2015 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.internal.codegen; 18 19 import androidx.room.compiler.processing.util.Source; 20 import com.squareup.javapoet.MethodSpec; 21 import com.squareup.javapoet.TypeSpec; 22 import dagger.internal.codegen.javapoet.TypeNames; 23 import dagger.testing.compile.CompilerTests; 24 import dagger.testing.golden.GoldenFileRule; 25 import java.util.Collection; 26 import org.junit.Rule; 27 import org.junit.Test; 28 import org.junit.runner.RunWith; 29 import org.junit.runners.Parameterized; 30 import org.junit.runners.Parameterized.Parameters; 31 32 @RunWith(Parameterized.class) 33 public class SubcomponentValidationTest { 34 @Parameters(name = "{0}") parameters()35 public static Collection<Object[]> parameters() { 36 return CompilerMode.TEST_PARAMETERS; 37 } 38 39 private final CompilerMode compilerMode; 40 SubcomponentValidationTest(CompilerMode compilerMode)41 public SubcomponentValidationTest(CompilerMode compilerMode) { 42 this.compilerMode = compilerMode; 43 } 44 45 @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule(); 46 factoryMethod_missingModulesWithParameters()47 @Test public void factoryMethod_missingModulesWithParameters() { 48 Source componentFile = 49 CompilerTests.javaSource( 50 "test.TestComponent", 51 "package test;", 52 "", 53 "import dagger.Component;", 54 "", 55 "@Component", 56 "interface TestComponent {", 57 " ChildComponent newChildComponent();", 58 "}"); 59 Source childComponentFile = 60 CompilerTests.javaSource( 61 "test.ChildComponent", 62 "package test;", 63 "", 64 "import dagger.Subcomponent;", 65 "", 66 "@Subcomponent(modules = ModuleWithParameters.class)", 67 "interface ChildComponent {", 68 " Object object();", 69 "}"); 70 Source moduleFile = 71 CompilerTests.javaSource( 72 "test.ModuleWithParameters", 73 "package test;", 74 "", 75 "import dagger.Module;", 76 "import dagger.Provides;", 77 "", 78 "@Module", 79 "final class ModuleWithParameters {", 80 " private final Object object;", 81 "", 82 " ModuleWithParameters(Object object) {", 83 " this.object = object;", 84 " }", 85 "", 86 " @Provides Object object() {", 87 " return object;", 88 " }", 89 "}"); 90 CompilerTests.daggerCompiler(componentFile, childComponentFile, moduleFile) 91 .withProcessingOptions(compilerMode.processorOptions()) 92 .compile( 93 subject -> { 94 subject.hasErrorCount(1); 95 subject.hasErrorContaining( 96 "test.ChildComponent requires modules which have no visible default " 97 + "constructors. Add the following modules as parameters to this method: " 98 + "test.ModuleWithParameters") 99 .onSource(componentFile) 100 .onLineContaining("ChildComponent newChildComponent();"); 101 }); 102 } 103 104 @Test factoryMethod_grandchild()105 public void factoryMethod_grandchild() { 106 Source component = 107 CompilerTests.javaSource( 108 "test.TestComponent", 109 "package test;", 110 "", 111 "import dagger.Component;", 112 "", 113 "@Component", 114 "interface TestComponent {", 115 " ChildComponent newChildComponent();", 116 "}"); 117 Source childComponent = 118 CompilerTests.javaSource( 119 "test.ChildComponent", 120 "package test;", 121 "", 122 "import dagger.Subcomponent;", 123 "", 124 "@Subcomponent", 125 "interface ChildComponent {", 126 " GrandchildComponent newGrandchildComponent();", 127 "}"); 128 Source grandchildComponent = 129 CompilerTests.javaSource( 130 "test.GrandchildComponent", 131 "package test;", 132 "", 133 "import dagger.Subcomponent;", 134 "", 135 "@Subcomponent(modules = GrandchildModule.class)", 136 "interface GrandchildComponent {", 137 " Object object();", 138 "}"); 139 Source grandchildModule = 140 CompilerTests.javaSource( 141 "test.GrandchildModule", 142 "package test;", 143 "", 144 "import dagger.Module;", 145 "import dagger.Provides;", 146 "", 147 "@Module", 148 "final class GrandchildModule {", 149 " private final Object object;", 150 "", 151 " GrandchildModule(Object object) {", 152 " this.object = object;", 153 " }", 154 "", 155 " @Provides Object object() {", 156 " return object;", 157 " }", 158 "}"); 159 CompilerTests.daggerCompiler(component, childComponent, grandchildComponent, grandchildModule) 160 .withProcessingOptions(compilerMode.processorOptions()) 161 .compile( 162 subject -> { 163 subject.hasErrorCount(1); 164 subject.hasErrorContaining( 165 "[ChildComponent.newGrandchildComponent()] " 166 + "GrandchildComponent requires modules which have no visible default " 167 + "constructors. Add the following modules as parameters to this method: " 168 + "GrandchildModule") 169 .onSource(component) 170 .onLineContaining("interface TestComponent"); 171 }); 172 } 173 factoryMethod_nonModuleParameter()174 @Test public void factoryMethod_nonModuleParameter() { 175 Source componentFile = 176 CompilerTests.javaSource("test.TestComponent", 177 "package test;", 178 "", 179 "import dagger.Component;", 180 "", 181 "@Component", 182 "interface TestComponent {", 183 " ChildComponent newChildComponent(String someRandomString);", 184 "}"); 185 Source childComponentFile = 186 CompilerTests.javaSource("test.ChildComponent", 187 "package test;", 188 "", 189 "import dagger.Subcomponent;", 190 "", 191 "@Subcomponent", 192 "interface ChildComponent {}"); 193 CompilerTests.daggerCompiler(componentFile, childComponentFile) 194 .withProcessingOptions(compilerMode.processorOptions()) 195 .compile( 196 subject -> { 197 subject.hasErrorCount(1); 198 subject.hasErrorContaining( 199 "Subcomponent factory methods may only accept modules, but java.lang.String " 200 + "is not.") 201 .onSource(componentFile) 202 .onLine(7); 203 }); 204 } 205 factoryMethod_duplicateParameter()206 @Test public void factoryMethod_duplicateParameter() { 207 Source moduleFile = 208 CompilerTests.javaSource("test.TestModule", 209 "package test;", 210 "", 211 "import dagger.Module;", 212 "", 213 "@Module", 214 "final class TestModule {}"); 215 Source componentFile = 216 CompilerTests.javaSource("test.TestComponent", 217 "package test;", 218 "", 219 "import dagger.Component;", 220 "", 221 "@Component", 222 "interface TestComponent {", 223 " ChildComponent newChildComponent(TestModule testModule1, TestModule testModule2);", 224 "}"); 225 Source childComponentFile = 226 CompilerTests.javaSource("test.ChildComponent", 227 "package test;", 228 "", 229 "import dagger.Subcomponent;", 230 "", 231 "@Subcomponent(modules = TestModule.class)", 232 "interface ChildComponent {}"); 233 CompilerTests.daggerCompiler(componentFile, childComponentFile, moduleFile) 234 .withProcessingOptions(compilerMode.processorOptions()) 235 .compile( 236 subject -> { 237 subject.hasErrorCount(1); 238 subject.hasErrorContaining( 239 "A module may only occur once as an argument in a Subcomponent factory " 240 + "method, but test.TestModule was already passed.") 241 .onSource(componentFile) 242 .onLine(7); 243 }); 244 } 245 factoryMethod_superflouousModule()246 @Test public void factoryMethod_superflouousModule() { 247 Source moduleFile = 248 CompilerTests.javaSource("test.TestModule", 249 "package test;", 250 "", 251 "import dagger.Module;", 252 "", 253 "@Module", 254 "final class TestModule {}"); 255 Source componentFile = 256 CompilerTests.javaSource("test.TestComponent", 257 "package test;", 258 "", 259 "import dagger.Component;", 260 "", 261 "@Component", 262 "interface TestComponent {", 263 " ChildComponent newChildComponent(TestModule testModule);", 264 "}"); 265 Source childComponentFile = 266 CompilerTests.javaSource("test.ChildComponent", 267 "package test;", 268 "", 269 "import dagger.Subcomponent;", 270 "", 271 "@Subcomponent", 272 "interface ChildComponent {}"); 273 CompilerTests.daggerCompiler(moduleFile, componentFile, childComponentFile) 274 .withProcessingOptions(compilerMode.processorOptions()) 275 .compile( 276 subject -> { 277 subject.hasErrorCount(1); 278 subject.hasErrorContaining( 279 "test.TestModule is present as an argument to the test.ChildComponent " 280 + "factory method, but is not one of the modules used to implement the " 281 + "subcomponent.") 282 .onSource(componentFile) 283 .onLine(7); 284 }); 285 } 286 missingBinding()287 @Test public void missingBinding() { 288 Source moduleFile = 289 CompilerTests.javaSource("test.TestModule", 290 "package test;", 291 "", 292 "import dagger.Module;", 293 "import dagger.Provides;", 294 "", 295 "@Module", 296 "final class TestModule {", 297 " @Provides String provideString(int i) {", 298 " return Integer.toString(i);", 299 " }", 300 "}"); 301 Source componentFile = 302 CompilerTests.javaSource("test.TestComponent", 303 "package test;", 304 "", 305 "import dagger.Component;", 306 "", 307 "@Component", 308 "interface TestComponent {", 309 " ChildComponent newChildComponent();", 310 "}"); 311 Source childComponentFile = 312 CompilerTests.javaSource("test.ChildComponent", 313 "package test;", 314 "", 315 "import dagger.Subcomponent;", 316 "", 317 "@Subcomponent(modules = TestModule.class)", 318 "interface ChildComponent {", 319 " String string();", 320 "}"); 321 CompilerTests.daggerCompiler(moduleFile, componentFile, childComponentFile) 322 .withProcessingOptions(compilerMode.processorOptions()) 323 .compile( 324 subject -> { 325 subject.hasErrorCount(1); 326 subject.hasErrorContaining( 327 "Integer cannot be provided without an @Inject constructor or an " 328 + "@Provides-annotated method") 329 .onSource(componentFile) 330 .onLineContaining("interface TestComponent"); 331 }); 332 } 333 subcomponentOnConcreteType()334 @Test public void subcomponentOnConcreteType() { 335 Source subcomponentFile = 336 CompilerTests.javaSource("test.NotASubcomponent", 337 "package test;", 338 "", 339 "import dagger.Subcomponent;", 340 "", 341 "@Subcomponent", 342 "final class NotASubcomponent {}"); 343 CompilerTests.daggerCompiler(subcomponentFile) 344 .withProcessingOptions(compilerMode.processorOptions()) 345 .compile( 346 subject -> { 347 subject.hasErrorCount(1); 348 subject.hasErrorContaining("interface"); 349 }); 350 } 351 scopeMismatch()352 @Test public void scopeMismatch() { 353 Source componentFile = 354 CompilerTests.javaSource("test.ParentComponent", 355 "package test;", 356 "", 357 "import dagger.Component;", 358 "import javax.inject.Singleton;", 359 "", 360 "@Component", 361 "@Singleton", 362 "interface ParentComponent {", 363 " ChildComponent childComponent();", 364 "}"); 365 Source subcomponentFile = 366 CompilerTests.javaSource("test.ChildComponent", 367 "package test;", 368 "", 369 "import dagger.Subcomponent;", 370 "", 371 "@Subcomponent(modules = ChildModule.class)", 372 "interface ChildComponent {", 373 " Object object();", 374 "}"); 375 Source moduleFile = 376 CompilerTests.javaSource("test.ChildModule", 377 "package test;", 378 "", 379 "import dagger.Module;", 380 "import dagger.Provides;", 381 "import javax.inject.Singleton;", 382 "", 383 "@Module", 384 "final class ChildModule {", 385 " @Provides @Singleton Object provideObject() { return null; }", 386 "}"); 387 CompilerTests.daggerCompiler(componentFile, subcomponentFile, moduleFile) 388 .withProcessingOptions(compilerMode.processorOptions()) 389 .compile( 390 subject -> { 391 subject.hasErrorCount(1); 392 subject.hasErrorContaining("@Singleton"); 393 }); 394 } 395 396 @Test delegateFactoryNotCreatedForSubcomponentWhenProviderExistsInParent()397 public void delegateFactoryNotCreatedForSubcomponentWhenProviderExistsInParent() 398 throws Exception { 399 Source parentComponentFile = 400 CompilerTests.javaSource( 401 "test.ParentComponent", 402 "package test;", 403 "", 404 "import dagger.Component;", 405 "import javax.inject.Singleton;", 406 "", 407 "@Singleton", 408 "@Component", 409 "interface ParentComponent {", 410 " ChildComponent childComponent();", 411 " Dep1 dep1();", 412 " Dep2 dep2();", 413 "}"); 414 Source childComponentFile = 415 CompilerTests.javaSource( 416 "test.ChildComponent", 417 "package test;", 418 "", 419 "import dagger.Subcomponent;", 420 "", 421 "@Subcomponent(modules = ChildModule.class)", 422 "interface ChildComponent {", 423 " Object object();", 424 "}"); 425 Source childModuleFile = 426 CompilerTests.javaSource( 427 "test.ChildModule", 428 "package test;", 429 "", 430 "import dagger.Module;", 431 "import dagger.Provides;", 432 "", 433 "@Module", 434 "final class ChildModule {", 435 " @Provides Object provideObject(A a) { return null; }", 436 "}"); 437 Source aFile = 438 CompilerTests.javaSource( 439 "test.A", 440 "package test;", 441 "", 442 "import javax.inject.Inject;", 443 "", 444 "final class A {", 445 " @Inject public A(NeedsDep1 a, Dep1 b, Dep2 c) { }", 446 " @Inject public void methodA() { }", 447 "}"); 448 Source needsDep1File = 449 CompilerTests.javaSource( 450 "test.NeedsDep1", 451 "package test;", 452 "", 453 "import javax.inject.Inject;", 454 "", 455 "final class NeedsDep1 {", 456 " @Inject public NeedsDep1(Dep1 d) { }", 457 "}"); 458 Source dep1File = 459 CompilerTests.javaSource( 460 "test.Dep1", 461 "package test;", 462 "", 463 "import javax.inject.Inject;", 464 "import javax.inject.Singleton;", 465 "", 466 "@Singleton", 467 "final class Dep1 {", 468 " @Inject public Dep1() { }", 469 " @Inject public void dep1Method() { }", 470 "}"); 471 Source dep2File = 472 CompilerTests.javaSource( 473 "test.Dep2", 474 "package test;", 475 "", 476 "import javax.inject.Inject;", 477 "import javax.inject.Singleton;", 478 "", 479 "@Singleton", 480 "final class Dep2 {", 481 " @Inject public Dep2() { }", 482 " @Inject public void dep2Method() { }", 483 "}"); 484 485 CompilerTests.daggerCompiler( 486 parentComponentFile, 487 childComponentFile, 488 childModuleFile, 489 aFile, 490 needsDep1File, 491 dep1File, 492 dep2File) 493 .withProcessingOptions(compilerMode.processorOptions()) 494 .compile( 495 subject -> { 496 subject.hasErrorCount(0); 497 subject.generatedSource( 498 goldenFileRule.goldenSource("test/DaggerParentComponent")); 499 }); 500 } 501 502 @Test multipleSubcomponentsWithSameSimpleNamesCanExistInSameComponent()503 public void multipleSubcomponentsWithSameSimpleNamesCanExistInSameComponent() throws Exception { 504 Source parent = 505 CompilerTests.javaSource( 506 "test.ParentComponent", 507 "package test;", 508 "", 509 "import dagger.Component;", 510 "", 511 "@Component", 512 "interface ParentComponent {", 513 " Foo.Sub newInstanceSubcomponent();", 514 " NoConflict newNoConflictSubcomponent();", 515 "}"); 516 Source foo = 517 CompilerTests.javaSource( 518 "test.Foo", 519 "package test;", 520 "", 521 "import dagger.Subcomponent;", 522 "", 523 "interface Foo {", 524 " @Subcomponent interface Sub {", 525 " Bar.Sub newBarSubcomponent();", 526 " }", 527 "}"); 528 Source bar = 529 CompilerTests.javaSource( 530 "test.Bar", 531 "package test;", 532 "", 533 "import dagger.Subcomponent;", 534 "", 535 "interface Bar {", 536 " @Subcomponent interface Sub {", 537 " test.subpackage.Sub newSubcomponentInSubpackage();", 538 " }", 539 "}"); 540 Source baz = 541 CompilerTests.javaSource( 542 "test.subpackage.Sub", 543 "package test.subpackage;", 544 "", 545 "import dagger.Subcomponent;", 546 "", 547 "@Subcomponent public interface Sub {}"); 548 Source noConflict = 549 CompilerTests.javaSource( 550 "test.NoConflict", 551 "package test;", 552 "", 553 "import dagger.Subcomponent;", 554 "", 555 "@Subcomponent interface NoConflict {}"); 556 557 CompilerTests.daggerCompiler(parent, foo, bar, baz, noConflict) 558 .withProcessingOptions(compilerMode.processorOptions()) 559 .compile( 560 subject -> { 561 subject.hasErrorCount(0); 562 subject.generatedSource( 563 goldenFileRule.goldenSource("test/DaggerParentComponent")); 564 }); 565 } 566 567 @Test subcomponentSimpleNamesDisambiguated()568 public void subcomponentSimpleNamesDisambiguated() throws Exception { 569 Source parent = 570 CompilerTests.javaSource( 571 "test.ParentComponent", 572 "package test;", 573 "", 574 "import dagger.Component;", 575 "", 576 "@Component", 577 "interface ParentComponent {", 578 " Sub newSubcomponent();", 579 "}"); 580 Source sub = 581 CompilerTests.javaSource( 582 "test.Sub", 583 "package test;", 584 "", 585 "import dagger.Subcomponent;", 586 "", 587 "@Subcomponent interface Sub {", 588 " test.deep.many.levels.that.match.test.Sub newDeepSubcomponent();", 589 "}"); 590 Source deepSub = 591 CompilerTests.javaSource( 592 "test.deep.many.levels.that.match.test.Sub", 593 "package test.deep.many.levels.that.match.test;", 594 "", 595 "import dagger.Subcomponent;", 596 "", 597 "@Subcomponent public interface Sub {}"); 598 599 CompilerTests.daggerCompiler(parent, sub, deepSub) 600 .withProcessingOptions(compilerMode.processorOptions()) 601 .compile( 602 subject -> { 603 subject.hasErrorCount(0); 604 subject.generatedSource( 605 goldenFileRule.goldenSource("test/DaggerParentComponent")); 606 }); 607 } 608 609 @Test subcomponentSimpleNamesDisambiguatedInRoot()610 public void subcomponentSimpleNamesDisambiguatedInRoot() throws Exception { 611 Source parent = 612 CompilerTests.javaSource( 613 "ParentComponent", 614 "import dagger.Component;", 615 "", 616 "@Component", 617 "interface ParentComponent {", 618 " Sub newSubcomponent();", 619 "}"); 620 Source sub = 621 CompilerTests.javaSource( 622 "Sub", 623 "import dagger.Subcomponent;", 624 "", 625 "@Subcomponent interface Sub {", 626 " test.deep.many.levels.that.match.test.Sub newDeepSubcomponent();", 627 "}"); 628 Source deepSub = 629 CompilerTests.javaSource( 630 "test.deep.many.levels.that.match.test.Sub", 631 "package test.deep.many.levels.that.match.test;", 632 "", 633 "import dagger.Subcomponent;", 634 "", 635 "@Subcomponent public interface Sub {}"); 636 637 CompilerTests.daggerCompiler(parent, sub, deepSub) 638 .withProcessingOptions(compilerMode.processorOptions()) 639 .compile( 640 subject -> { 641 subject.hasErrorCount(0); 642 subject.generatedSource( 643 goldenFileRule.goldenSource("DaggerParentComponent")); 644 }); 645 } 646 647 @Test subcomponentImplNameUsesFullyQualifiedClassNameIfNecessary()648 public void subcomponentImplNameUsesFullyQualifiedClassNameIfNecessary() throws Exception { 649 Source parent = 650 CompilerTests.javaSource( 651 "test.ParentComponent", 652 "package test;", 653 "", 654 "import dagger.Component;", 655 "", 656 "@Component", 657 "interface ParentComponent {", 658 " top1.a.b.c.d.E.F.Sub top1();", 659 " top2.a.b.c.d.E.F.Sub top2();", 660 "}"); 661 Source top1 = 662 CompilerTests.javaSource( 663 "top1.a.b.c.d.E", 664 "package top1.a.b.c.d;", 665 "", 666 "import dagger.Subcomponent;", 667 "", 668 "public interface E {", 669 " interface F {", 670 " @Subcomponent interface Sub {}", 671 " }", 672 "}"); 673 Source top2 = 674 CompilerTests.javaSource( 675 "top2.a.b.c.d.E", 676 "package top2.a.b.c.d;", 677 "", 678 "import dagger.Subcomponent;", 679 "", 680 "public interface E {", 681 " interface F {", 682 " @Subcomponent interface Sub {}", 683 " }", 684 "}"); 685 686 CompilerTests.daggerCompiler(parent, top1, top2) 687 .withProcessingOptions(compilerMode.processorOptions()) 688 .compile( 689 subject -> { 690 subject.hasErrorCount(0); 691 subject.generatedSource( 692 goldenFileRule.goldenSource("test/DaggerParentComponent")); 693 }); 694 } 695 696 @Test subcomponentNamesShouldNotConflictWithParent()697 public void subcomponentNamesShouldNotConflictWithParent() 698 throws Exception { 699 Source parent = 700 CompilerTests.javaSource( 701 "test.C", 702 "package test;", 703 "", 704 "import dagger.Component;", 705 "", 706 "@Component", 707 "interface C {", 708 " test.Foo.C newInstanceC();", 709 "}"); 710 Source subcomponentWithSameSimpleNameAsParent = 711 CompilerTests.javaSource( 712 "test.Foo", 713 "package test;", 714 "", 715 "import dagger.Subcomponent;", 716 "", 717 "interface Foo {", 718 " @Subcomponent interface C {}", 719 "}"); 720 721 CompilerTests.daggerCompiler(parent, subcomponentWithSameSimpleNameAsParent) 722 .withProcessingOptions(compilerMode.processorOptions()) 723 .compile( 724 subject -> { 725 subject.hasErrorCount(0); 726 subject.generatedSource( 727 goldenFileRule.goldenSource("test/DaggerC")); 728 }); 729 } 730 731 @Test subcomponentBuilderNamesShouldNotConflict()732 public void subcomponentBuilderNamesShouldNotConflict() throws Exception { 733 Source parent = 734 CompilerTests.javaSource( 735 "test.C", 736 "package test;", 737 "", 738 "import dagger.Component;", 739 "import dagger.Subcomponent;", 740 "", 741 "@Component", 742 "interface C {", 743 " Foo.Sub.Builder fooBuilder();", 744 " Bar.Sub.Builder barBuilder();", 745 "", 746 " interface Foo {", 747 " @Subcomponent", 748 " interface Sub {", 749 " @Subcomponent.Builder", 750 " interface Builder {", 751 " Sub build();", 752 " }", 753 " }", 754 " }", 755 "", 756 " interface Bar {", 757 " @Subcomponent", 758 " interface Sub {", 759 " @Subcomponent.Builder", 760 " interface Builder {", 761 " Sub build();", 762 " }", 763 " }", 764 " }", 765 "}"); 766 767 CompilerTests.daggerCompiler(parent) 768 .withProcessingOptions(compilerMode.processorOptions()) 769 .compile( 770 subject -> { 771 subject.hasErrorCount(0); 772 subject.generatedSource( 773 goldenFileRule.goldenSource("test/DaggerC")); 774 }); 775 } 776 777 @Test duplicateBindingWithSubcomponentDeclaration()778 public void duplicateBindingWithSubcomponentDeclaration() { 779 Source module = 780 CompilerTests.javaSource( 781 "test.TestModule", 782 "package test;", 783 "", 784 "import dagger.Module;", 785 "import dagger.Provides;", 786 "", 787 "@Module(subcomponents = Sub.class)", 788 "class TestModule {", 789 " @Provides Sub.Builder providesConflictsWithModuleSubcomponents() { return null; }", 790 " @Provides Object usesSubcomponentBuilder(Sub.Builder builder) {", 791 " return new Builder().toString();", 792 " }", 793 "}"); 794 795 Source subcomponent = 796 CompilerTests.javaSource( 797 "test.Sub", 798 "package test;", 799 "", 800 "import dagger.Subcomponent;", 801 "", 802 "@Subcomponent", 803 "interface Sub {", 804 " @Subcomponent.Builder", 805 " interface Builder {", 806 " Sub build();", 807 " }", 808 "}"); 809 810 Source component = 811 CompilerTests.javaSource( 812 "test.C", 813 "package test;", 814 "", 815 "import dagger.Component;", 816 "", 817 "@Component(modules = TestModule.class)", 818 "interface C {", 819 " Object dependsOnBuilder();", 820 "}"); 821 822 CompilerTests.daggerCompiler(module, component, subcomponent) 823 .withProcessingOptions(compilerMode.processorOptions()) 824 .compile( 825 subject -> { 826 subject.hasErrorCount(1); 827 subject.hasErrorContaining("Sub.Builder is bound multiple times:"); 828 subject.hasErrorContaining( 829 "@Provides Sub.Builder TestModule.providesConflictsWithModuleSubcomponents()"); 830 subject.hasErrorContaining("@Module(subcomponents = Sub.class) for TestModule"); 831 }); 832 } 833 834 @Test subcomponentDependsOnGeneratedType()835 public void subcomponentDependsOnGeneratedType() { 836 Source parent = 837 CompilerTests.javaSource( 838 "test.Parent", 839 "package test;", 840 "", 841 "import dagger.Component;", 842 "", 843 "@Component", 844 "interface Parent {", 845 " Child.Builder childBuilder();", 846 "}"); 847 Source child = 848 CompilerTests.javaSource( 849 "test.Child", 850 "package test;", 851 "", 852 "import dagger.Subcomponent;", 853 "", 854 "@Subcomponent", 855 "interface Child extends ChildSupertype {", 856 " @Subcomponent.Builder", 857 " interface Builder {", 858 " Child build();", 859 " }", 860 "}"); 861 Source childSupertype = 862 CompilerTests.javaSource( 863 "test.ChildSupertype", 864 "package test;", 865 "", 866 "interface ChildSupertype {", 867 " GeneratedInjectType generatedType();", 868 "}"); 869 TypeSpec generatedInjectType = 870 TypeSpec.classBuilder("GeneratedInjectType") 871 .addMethod( 872 MethodSpec.constructorBuilder() 873 .addAnnotation(TypeNames.INJECT_JAVAX) 874 .build()) 875 .build(); 876 CompilerTests.daggerCompiler(parent, child, childSupertype) 877 .withProcessingOptions(compilerMode.processorOptions()) 878 .withProcessingSteps(() -> new GeneratingProcessingStep("test", generatedInjectType)) 879 .compile( 880 subject -> { 881 subject.hasErrorCount(0); 882 subject.hasWarningCount(0); 883 }); 884 } 885 } 886