1 /* 2 * Copyright (C) 2014 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.binding; 18 19 import static androidx.room.compiler.processing.XElementKt.isMethod; 20 import static androidx.room.compiler.processing.XTypeKt.isVoid; 21 import static com.google.common.base.Preconditions.checkArgument; 22 import static com.google.common.base.Preconditions.checkNotNull; 23 import static com.google.common.base.Preconditions.checkState; 24 import static com.google.common.collect.Iterables.getOnlyElement; 25 import static dagger.internal.codegen.base.ComponentAnnotation.rootComponentAnnotation; 26 import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotation; 27 import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotations; 28 import static dagger.internal.codegen.base.ComponentCreatorAnnotation.creatorAnnotationsFor; 29 import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation; 30 import static dagger.internal.codegen.base.Scopes.productionScope; 31 import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent; 32 import static dagger.internal.codegen.binding.ConfigurationAnnotations.enclosedAnnotatedTypes; 33 import static dagger.internal.codegen.binding.ConfigurationAnnotations.isSubcomponentCreator; 34 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap; 35 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 36 import static dagger.internal.codegen.javapoet.TypeNames.isFutureType; 37 import static dagger.internal.codegen.xprocessing.XElements.getSimpleName; 38 import static dagger.internal.codegen.xprocessing.XTypeElements.getAllUnimplementedMethods; 39 import static dagger.internal.codegen.xprocessing.XTypes.isDeclared; 40 41 import androidx.room.compiler.processing.XElement; 42 import androidx.room.compiler.processing.XMethodElement; 43 import androidx.room.compiler.processing.XMethodType; 44 import androidx.room.compiler.processing.XProcessingEnv; 45 import androidx.room.compiler.processing.XType; 46 import androidx.room.compiler.processing.XTypeElement; 47 import com.google.auto.value.AutoValue; 48 import com.google.auto.value.extension.memoized.Memoized; 49 import com.google.common.base.Supplier; 50 import com.google.common.base.Suppliers; 51 import com.google.common.collect.HashMultimap; 52 import com.google.common.collect.ImmutableBiMap; 53 import com.google.common.collect.ImmutableMap; 54 import com.google.common.collect.ImmutableSet; 55 import com.google.common.collect.Maps; 56 import com.google.errorprone.annotations.CanIgnoreReturnValue; 57 import com.google.errorprone.annotations.CheckReturnValue; 58 import com.squareup.javapoet.TypeName; 59 import dagger.Component; 60 import dagger.Module; 61 import dagger.Subcomponent; 62 import dagger.internal.codegen.base.ClearableCache; 63 import dagger.internal.codegen.base.ComponentAnnotation; 64 import dagger.internal.codegen.base.DaggerSuperficialValidation; 65 import dagger.internal.codegen.base.ModuleAnnotation; 66 import dagger.internal.codegen.javapoet.TypeNames; 67 import dagger.internal.codegen.model.DependencyRequest; 68 import dagger.internal.codegen.model.Scope; 69 import dagger.internal.codegen.xprocessing.XTypeElements; 70 import java.util.HashMap; 71 import java.util.Map; 72 import java.util.Objects; 73 import java.util.Optional; 74 import java.util.stream.Stream; 75 import javax.inject.Inject; 76 import javax.inject.Singleton; 77 78 /** 79 * A component declaration. 80 * 81 * <p>Represents one type annotated with {@code @Component}, {@code Subcomponent}, 82 * {@code @ProductionComponent}, or {@code @ProductionSubcomponent}. 83 * 84 * <p>When validating bindings installed in modules, a {@link ComponentDescriptor} can also 85 * represent a synthetic component for the module, where there is an entry point for each binding in 86 * the module. 87 */ 88 @CheckReturnValue 89 @AutoValue 90 public abstract class ComponentDescriptor { 91 private BindingFactory bindingFactory; 92 93 /** The annotation that specifies that {@link #typeElement()} is a component. */ annotation()94 public abstract ComponentAnnotation annotation(); 95 96 /** 97 * The element that defines the component. This is the element to which the {@link #annotation()} 98 * was applied. 99 */ typeElement()100 public abstract XTypeElement typeElement(); 101 102 /** 103 * The set of component dependencies listed in {@link Component#dependencies} or {@link 104 * dagger.producers.ProductionComponent#dependencies()}. 105 */ dependencies()106 public abstract ImmutableSet<ComponentRequirement> dependencies(); 107 108 /** 109 * The {@link ModuleDescriptor modules} declared in {@link Component#modules()} and reachable by 110 * traversing {@link Module#includes()}. 111 */ modules()112 public abstract ImmutableSet<ModuleDescriptor> modules(); 113 114 /** The scopes of the component. */ scopes()115 public abstract ImmutableSet<Scope> scopes(); 116 117 /** 118 * All {@linkplain Subcomponent direct child} components that are declared by a {@linkplain 119 * Module#subcomponents() module's subcomponents}. 120 */ childComponentsDeclaredByModules()121 abstract ImmutableSet<ComponentDescriptor> childComponentsDeclaredByModules(); 122 123 /** 124 * All {@linkplain Subcomponent direct child} components that are declared by a subcomponent 125 * factory method. 126 */ 127 public abstract ImmutableBiMap<ComponentMethodDescriptor, ComponentDescriptor> childComponentsDeclaredByFactoryMethods()128 childComponentsDeclaredByFactoryMethods(); 129 130 /** 131 * All {@linkplain Subcomponent direct child} components that are declared by a subcomponent 132 * builder method. 133 */ 134 abstract ImmutableMap<ComponentMethodDescriptor, ComponentDescriptor> childComponentsDeclaredByBuilderEntryPoints()135 childComponentsDeclaredByBuilderEntryPoints(); 136 componentMethods()137 public abstract ImmutableSet<ComponentMethodDescriptor> componentMethods(); 138 139 /** Returns a descriptor for the creator type for this component type, if the user defined one. */ creatorDescriptor()140 public abstract Optional<ComponentCreatorDescriptor> creatorDescriptor(); 141 142 /** Returns {@code true} if this is a subcomponent. */ isSubcomponent()143 public final boolean isSubcomponent() { 144 return annotation().isSubcomponent(); 145 } 146 147 /** 148 * Returns {@code true} if this is a production component or subcomponent, or a 149 * {@code @ProducerModule} when doing module binding validation. 150 */ isProduction()151 public final boolean isProduction() { 152 return annotation().isProduction(); 153 } 154 155 /** 156 * Returns {@code true} if this is a real component, and not a fictional one used to validate 157 * module bindings. 158 */ isRealComponent()159 public final boolean isRealComponent() { 160 return annotation().isRealComponent(); 161 } 162 163 /** The non-abstract {@link #modules()} and the {@link #dependencies()}. */ dependenciesAndConcreteModules()164 public final ImmutableSet<ComponentRequirement> dependenciesAndConcreteModules() { 165 return Stream.concat( 166 moduleTypes().stream() 167 .filter(dep -> !dep.isAbstract()) 168 .map(module -> ComponentRequirement.forModule(module.getType())), 169 dependencies().stream()) 170 .collect(toImmutableSet()); 171 } 172 173 /** The types of the {@link #modules()}. */ moduleTypes()174 public final ImmutableSet<XTypeElement> moduleTypes() { 175 return modules().stream().map(ModuleDescriptor::moduleElement).collect(toImmutableSet()); 176 } 177 178 /** 179 * The types for which the component will need instances if all of its bindings are used. For the 180 * types the component will need in a given binding graph, use {@link 181 * BindingGraph#componentRequirements()}. 182 * 183 * <ul> 184 * <li>{@linkplain #modules()} modules} with concrete instance bindings 185 * <li>Bound instances 186 * <li>{@linkplain #dependencies() dependencies} 187 * </ul> 188 */ 189 @Memoized requirements()190 ImmutableSet<ComponentRequirement> requirements() { 191 ImmutableSet.Builder<ComponentRequirement> requirements = ImmutableSet.builder(); 192 modules().stream() 193 .filter( 194 module -> 195 module.bindings().stream().anyMatch(ContributionBinding::requiresModuleInstance)) 196 .map(module -> ComponentRequirement.forModule(module.moduleElement().getType())) 197 .forEach(requirements::add); 198 requirements.addAll(dependencies()); 199 requirements.addAll( 200 creatorDescriptor() 201 .map(ComponentCreatorDescriptor::boundInstanceRequirements) 202 .orElse(ImmutableSet.of())); 203 return requirements.build(); 204 } 205 206 /** 207 * Returns this component's dependencies keyed by its provision/production method. 208 * 209 * <p>Note that the dependencies' types are not simply the enclosing type of the method; a method 210 * may be declared by a supertype of the actual dependency. 211 */ 212 @Memoized dependenciesByDependencyMethod()213 public ImmutableMap<XMethodElement, ComponentRequirement> dependenciesByDependencyMethod() { 214 ImmutableMap.Builder<XMethodElement, ComponentRequirement> builder = ImmutableMap.builder(); 215 for (ComponentRequirement componentDependency : dependencies()) { 216 XTypeElements.getAllMethods(componentDependency.typeElement()).stream() 217 .filter(ComponentDescriptor::isComponentContributionMethod) 218 .forEach(method -> builder.put(method, componentDependency)); 219 } 220 return builder.buildOrThrow(); 221 } 222 223 /** The {@linkplain #dependencies() component dependency} that defines a method. */ getDependencyThatDefinesMethod(XElement method)224 public final ComponentRequirement getDependencyThatDefinesMethod(XElement method) { 225 checkArgument(isMethod(method), "method must be an executable element: %s", method); 226 checkState( 227 dependenciesByDependencyMethod().containsKey(method), 228 "no dependency implements %s", 229 method); 230 return dependenciesByDependencyMethod().get(method); 231 } 232 233 /** 234 * All {@link Subcomponent}s which are direct children of this component. This includes 235 * subcomponents installed from {@link Module#subcomponents()} as well as subcomponent {@linkplain 236 * #childComponentsDeclaredByFactoryMethods() factory methods} and {@linkplain 237 * #childComponentsDeclaredByBuilderEntryPoints() builder methods}. 238 */ childComponents()239 public final ImmutableSet<ComponentDescriptor> childComponents() { 240 return ImmutableSet.<ComponentDescriptor>builder() 241 .addAll(childComponentsDeclaredByFactoryMethods().values()) 242 .addAll(childComponentsDeclaredByBuilderEntryPoints().values()) 243 .addAll(childComponentsDeclaredByModules()) 244 .build(); 245 } 246 247 /** Returns a map of {@link #childComponents()} indexed by {@link #typeElement()}. */ 248 @Memoized childComponentsByElement()249 public ImmutableMap<XTypeElement, ComponentDescriptor> childComponentsByElement() { 250 return Maps.uniqueIndex(childComponents(), ComponentDescriptor::typeElement); 251 } 252 253 /** Returns the factory method that declares a child component. */ getFactoryMethodForChildComponent( ComponentDescriptor childComponent)254 final Optional<ComponentMethodDescriptor> getFactoryMethodForChildComponent( 255 ComponentDescriptor childComponent) { 256 return Optional.ofNullable( 257 childComponentsDeclaredByFactoryMethods().inverse().get(childComponent)); 258 } 259 260 private final Supplier<ImmutableMap<XTypeElement, ComponentDescriptor>> 261 childComponentsByBuilderType = 262 Suppliers.memoize( 263 () -> 264 childComponents().stream() 265 .filter(child -> child.creatorDescriptor().isPresent()) 266 .collect( 267 toImmutableMap( 268 child -> child.creatorDescriptor().get().typeElement(), 269 child -> child))); 270 271 /** Returns the child component with the given builder type. */ getChildComponentWithBuilderType(XTypeElement builderType)272 final ComponentDescriptor getChildComponentWithBuilderType(XTypeElement builderType) { 273 return checkNotNull( 274 childComponentsByBuilderType.get().get(builderType), 275 "no child component found for builder type %s", 276 builderType.getQualifiedName()); 277 } 278 279 /** The entry point methods on the component type. Each has a {@link DependencyRequest}. */ entryPointMethods()280 public final ImmutableSet<ComponentMethodDescriptor> entryPointMethods() { 281 return componentMethods().stream() 282 .filter(method -> method.dependencyRequest().isPresent()) 283 .collect(toImmutableSet()); 284 } 285 286 /** 287 * Returns {@code true} for components that have a creator, either because the user {@linkplain 288 * #creatorDescriptor() specified one} or because it's a top-level component with an implicit 289 * builder. 290 */ hasCreator()291 public final boolean hasCreator() { 292 return !isSubcomponent() || creatorDescriptor().isPresent(); 293 } 294 295 /** 296 * Returns the {@link CancellationPolicy} for this component, or an empty optional if either the 297 * component is not a production component or no {@code CancellationPolicy} annotation is present. 298 */ cancellationPolicy()299 public final Optional<CancellationPolicy> cancellationPolicy() { 300 return isProduction() 301 // TODO(bcorso): Get values from XAnnotation instead of using CancellationPolicy directly. 302 ? Optional.ofNullable(typeElement().getAnnotation(TypeNames.CANCELLATION_POLICY)) 303 .map(CancellationPolicy::from) 304 : Optional.empty(); 305 } 306 307 /** Returns the bindings for the component. */ 308 @Memoized bindings()309 public ImmutableSet<ContributionBinding> bindings() { 310 ImmutableSet.Builder<ContributionBinding> builder = ImmutableSet.builder(); 311 componentBinding().ifPresent(builder::add); 312 return builder 313 .addAll(componentDependencyBindings()) 314 .addAll(boundInstanceBindings()) 315 .addAll(subcomponentCreatorBindings()) 316 .addAll(moduleBindings()) 317 .build(); 318 } 319 320 /** Returns the binding for the component, itself, if this is a real component. */ 321 @Memoized componentBinding()322 Optional<ContributionBinding> componentBinding() { 323 return isRealComponent() 324 ? Optional.of(bindingFactory.componentBinding(typeElement())) 325 : Optional.empty(); 326 } 327 328 /** Returns the bindings for the component dependency and those contributed by its methods. */ 329 @Memoized componentDependencyBindings()330 ImmutableSet<ContributionBinding> componentDependencyBindings() { 331 ImmutableSet.Builder<ContributionBinding> builder = ImmutableSet.builder(); 332 for (ComponentRequirement dependency : dependencies()) { 333 builder.add(bindingFactory.componentDependencyBinding(dependency)); 334 335 // Within a component dependency, we want to allow the same method to appear multiple 336 // times assuming it is the exact same method. We do this by tracking a set of bindings 337 // we've already added with the binding element removed since that is the only thing 338 // allowed to differ. 339 HashMultimap<String, ContributionBinding> dedupeBindings = HashMultimap.create(); 340 XTypeElements.getAllMethods(dependency.typeElement()).stream() 341 // MembersInjection methods aren't "provided" explicitly, so ignore them. 342 .filter(ComponentDescriptor::isComponentContributionMethod) 343 .forEach( 344 method -> { 345 ContributionBinding binding = 346 isProduction() && isComponentProductionMethod(method) 347 ? bindingFactory.componentDependencyProductionMethodBinding(method) 348 : bindingFactory.componentDependencyProvisionMethodBinding(method); 349 if (dedupeBindings.put( 350 getSimpleName(method), 351 // Remove the binding element since we know that will be different, but 352 // everything else we want to be the same to consider it a duplicate. 353 binding.toBuilder().clearBindingElement().build())) { 354 builder.add(binding); 355 } 356 }); 357 } 358 return builder.build(); 359 } 360 361 /** Returns the {@code @BindsInstance} bindings required to create this component. */ 362 @Memoized boundInstanceBindings()363 ImmutableSet<ContributionBinding> boundInstanceBindings() { 364 return creatorDescriptor().isPresent() 365 ? creatorDescriptor().get().boundInstanceRequirements().stream() 366 .map( 367 requirement -> 368 bindingFactory.boundInstanceBinding( 369 requirement, 370 creatorDescriptor().get().elementForRequirement(requirement))) 371 .collect(toImmutableSet()) 372 : ImmutableSet.of(); 373 } 374 375 /** Returns the subcomponent creator bindings for this component. */ 376 @Memoized subcomponentCreatorBindings()377 ImmutableSet<ContributionBinding> subcomponentCreatorBindings() { 378 ImmutableSet.Builder<ContributionBinding> builder = ImmutableSet.builder(); 379 childComponentsDeclaredByBuilderEntryPoints() 380 .forEach( 381 (builderEntryPoint, childComponent) -> { 382 if (!childComponentsDeclaredByModules().contains(childComponent)) { 383 builder.add( 384 bindingFactory.subcomponentCreatorBinding( 385 builderEntryPoint.methodElement(), typeElement())); 386 } 387 }); 388 return builder.build(); 389 } 390 391 @Memoized moduleBindings()392 ImmutableSet<ContributionBinding> moduleBindings() { 393 return modules().stream() 394 .map(ModuleDescriptor::bindings) 395 .flatMap(ImmutableSet::stream) 396 .collect(toImmutableSet()); 397 } 398 399 @Memoized delegateDeclarations()400 public ImmutableSet<DelegateDeclaration> delegateDeclarations() { 401 return modules().stream() 402 .map(ModuleDescriptor::delegateDeclarations) 403 .flatMap(ImmutableSet::stream) 404 .collect(toImmutableSet()); 405 } 406 407 @Memoized multibindingDeclarations()408 public ImmutableSet<MultibindingDeclaration> multibindingDeclarations() { 409 return modules().stream() 410 .map(ModuleDescriptor::multibindingDeclarations) 411 .flatMap(ImmutableSet::stream) 412 .collect(toImmutableSet()); 413 } 414 415 @Memoized optionalBindingDeclarations()416 public ImmutableSet<OptionalBindingDeclaration> optionalBindingDeclarations() { 417 return modules().stream() 418 .map(ModuleDescriptor::optionalDeclarations) 419 .flatMap(ImmutableSet::stream) 420 .collect(toImmutableSet()); 421 } 422 423 @Memoized subcomponentDeclarations()424 public ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations() { 425 return modules().stream() 426 .map(ModuleDescriptor::subcomponentDeclarations) 427 .flatMap(ImmutableSet::stream) 428 .collect(toImmutableSet()); 429 } 430 431 @Memoized 432 @Override hashCode()433 public int hashCode() { 434 // TODO(b/122962745): Only use typeElement().hashCode() 435 return Objects.hash(typeElement(), annotation()); 436 } 437 438 // TODO(ronshapiro): simplify the equality semantics 439 @Override equals(Object obj)440 public abstract boolean equals(Object obj); 441 442 /** A component method. */ 443 @AutoValue 444 public abstract static class ComponentMethodDescriptor { 445 /** The method itself. Note that this may be declared on a supertype of the component. */ methodElement()446 public abstract XMethodElement methodElement(); 447 448 /** 449 * The dependency request for production, provision, and subcomponent creator methods. Absent 450 * for subcomponent factory methods. 451 */ dependencyRequest()452 public abstract Optional<DependencyRequest> dependencyRequest(); 453 454 /** The subcomponent for subcomponent factory methods and subcomponent creator methods. */ subcomponent()455 public abstract Optional<ComponentDescriptor> subcomponent(); 456 457 /** A {@link ComponentMethodDescriptor}builder for a method. */ builder(XMethodElement method)458 public static Builder builder(XMethodElement method) { 459 return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor.Builder() 460 .methodElement(method); 461 } 462 463 /** A builder of {@link ComponentMethodDescriptor}s. */ 464 @AutoValue.Builder 465 public interface Builder { 466 /** @see ComponentMethodDescriptor#methodElement() */ methodElement(XMethodElement methodElement)467 Builder methodElement(XMethodElement methodElement); 468 469 /** 470 * @see ComponentMethodDescriptor#dependencyRequest() 471 */ 472 @CanIgnoreReturnValue // TODO(kak): remove this once open-source checkers understand AutoValue dependencyRequest(DependencyRequest dependencyRequest)473 Builder dependencyRequest(DependencyRequest dependencyRequest); 474 475 /** 476 * @see ComponentMethodDescriptor#subcomponent() 477 */ 478 @CanIgnoreReturnValue // TODO(kak): remove this once open-source checkers understand AutoValue subcomponent(ComponentDescriptor subcomponent)479 Builder subcomponent(ComponentDescriptor subcomponent); 480 481 /** Builds the descriptor. */ build()482 ComponentMethodDescriptor build(); 483 } 484 } 485 486 /** No-argument methods defined on {@link Object} that are ignored for contribution. */ 487 private static final ImmutableSet<String> NON_CONTRIBUTING_OBJECT_METHOD_NAMES = 488 ImmutableSet.of("toString", "hashCode", "clone", "getClass"); 489 490 /** 491 * Returns {@code true} if a method could be a component entry point but not a members-injection 492 * method. 493 */ isComponentContributionMethod(XMethodElement method)494 private static boolean isComponentContributionMethod(XMethodElement method) { 495 return method.getParameters().isEmpty() 496 && !isVoid(method.getReturnType()) 497 && !method.getEnclosingElement().getClassName().equals(TypeName.OBJECT) 498 && !NON_CONTRIBUTING_OBJECT_METHOD_NAMES.contains(getSimpleName(method)); 499 } 500 501 /** Returns {@code true} if a method could be a component production entry point. */ isComponentProductionMethod(XMethodElement method)502 private static boolean isComponentProductionMethod(XMethodElement method) { 503 return isComponentContributionMethod(method) && isFutureType(method.getReturnType()); 504 } 505 506 /** A factory for creating a {@link ComponentDescriptor}. */ 507 @Singleton 508 public static final class Factory implements ClearableCache { 509 private final XProcessingEnv processingEnv; 510 private final BindingFactory bindingFactory; 511 private final DependencyRequestFactory dependencyRequestFactory; 512 private final ModuleDescriptor.Factory moduleDescriptorFactory; 513 private final InjectionAnnotations injectionAnnotations; 514 private final DaggerSuperficialValidation superficialValidation; 515 private final Map<XTypeElement, ComponentDescriptor> cache = new HashMap<>(); 516 517 @Inject Factory( XProcessingEnv processingEnv, BindingFactory bindingFactory, DependencyRequestFactory dependencyRequestFactory, ModuleDescriptor.Factory moduleDescriptorFactory, InjectionAnnotations injectionAnnotations, DaggerSuperficialValidation superficialValidation)518 Factory( 519 XProcessingEnv processingEnv, 520 BindingFactory bindingFactory, 521 DependencyRequestFactory dependencyRequestFactory, 522 ModuleDescriptor.Factory moduleDescriptorFactory, 523 InjectionAnnotations injectionAnnotations, 524 DaggerSuperficialValidation superficialValidation) { 525 this.processingEnv = processingEnv; 526 this.bindingFactory = bindingFactory; 527 this.dependencyRequestFactory = dependencyRequestFactory; 528 this.moduleDescriptorFactory = moduleDescriptorFactory; 529 this.injectionAnnotations = injectionAnnotations; 530 this.superficialValidation = superficialValidation; 531 } 532 533 /** Returns a descriptor for a root component type. */ rootComponentDescriptor(XTypeElement typeElement)534 public ComponentDescriptor rootComponentDescriptor(XTypeElement typeElement) { 535 Optional<ComponentAnnotation> annotation = 536 rootComponentAnnotation(typeElement, superficialValidation); 537 checkArgument(annotation.isPresent(), "%s must have a component annotation", typeElement); 538 return create(typeElement, annotation.get()); 539 } 540 541 /** Returns a descriptor for a subcomponent type. */ subcomponentDescriptor(XTypeElement typeElement)542 public ComponentDescriptor subcomponentDescriptor(XTypeElement typeElement) { 543 Optional<ComponentAnnotation> annotation = 544 subcomponentAnnotation(typeElement, superficialValidation); 545 checkArgument(annotation.isPresent(), "%s must have a subcomponent annotation", typeElement); 546 return create(typeElement, annotation.get()); 547 } 548 549 /** 550 * Returns a descriptor for a fictional component based on a module type in order to validate 551 * its bindings. 552 */ moduleComponentDescriptor(XTypeElement typeElement)553 public ComponentDescriptor moduleComponentDescriptor(XTypeElement typeElement) { 554 Optional<ModuleAnnotation> annotation = moduleAnnotation(typeElement, superficialValidation); 555 checkArgument(annotation.isPresent(), "%s must have a module annotation", typeElement); 556 return create(typeElement, ComponentAnnotation.fromModuleAnnotation(annotation.get())); 557 } 558 create( XTypeElement typeElement, ComponentAnnotation componentAnnotation)559 private ComponentDescriptor create( 560 XTypeElement typeElement, ComponentAnnotation componentAnnotation) { 561 return reentrantComputeIfAbsent( 562 cache, typeElement, unused -> createUncached(typeElement, componentAnnotation)); 563 } 564 createUncached( XTypeElement typeElement, ComponentAnnotation componentAnnotation)565 private ComponentDescriptor createUncached( 566 XTypeElement typeElement, ComponentAnnotation componentAnnotation) { 567 ImmutableSet<ComponentRequirement> componentDependencies = 568 componentAnnotation.dependencyTypes().stream() 569 .map(ComponentRequirement::forDependency) 570 .collect(toImmutableSet()); 571 572 // Start with the component's modules. For fictional components built from a module, start 573 // with that module. 574 ImmutableSet<XTypeElement> modules = 575 componentAnnotation.isRealComponent() 576 ? componentAnnotation.modules() 577 : ImmutableSet.of(typeElement); 578 579 ImmutableSet<ModuleDescriptor> transitiveModules = 580 moduleDescriptorFactory.transitiveModules(modules); 581 582 ImmutableSet.Builder<ComponentMethodDescriptor> componentMethodsBuilder = 583 ImmutableSet.builder(); 584 ImmutableBiMap.Builder<ComponentMethodDescriptor, ComponentDescriptor> 585 subcomponentsByFactoryMethod = ImmutableBiMap.builder(); 586 ImmutableMap.Builder<ComponentMethodDescriptor, ComponentDescriptor> 587 subcomponentsByBuilderMethod = ImmutableBiMap.builder(); 588 if (componentAnnotation.isRealComponent()) { 589 for (XMethodElement componentMethod : getAllUnimplementedMethods(typeElement)) { 590 ComponentMethodDescriptor componentMethodDescriptor = 591 getDescriptorForComponentMethod(componentAnnotation, typeElement, componentMethod); 592 componentMethodsBuilder.add(componentMethodDescriptor); 593 componentMethodDescriptor 594 .subcomponent() 595 .ifPresent( 596 subcomponent -> { 597 // If the dependency request is present, that means the method returns the 598 // subcomponent factory. 599 if (componentMethodDescriptor.dependencyRequest().isPresent()) { 600 subcomponentsByBuilderMethod.put(componentMethodDescriptor, subcomponent); 601 } else { 602 subcomponentsByFactoryMethod.put(componentMethodDescriptor, subcomponent); 603 } 604 }); 605 } 606 } 607 608 // Validation should have ensured that this set will have at most one element. 609 ImmutableSet<XTypeElement> enclosedCreators = 610 enclosedAnnotatedTypes(typeElement, creatorAnnotationsFor(componentAnnotation)); 611 Optional<ComponentCreatorDescriptor> creatorDescriptor = 612 enclosedCreators.isEmpty() 613 ? Optional.empty() 614 : Optional.of( 615 ComponentCreatorDescriptor.create( 616 getOnlyElement(enclosedCreators), dependencyRequestFactory)); 617 618 ImmutableSet<Scope> scopes = injectionAnnotations.getScopes(typeElement); 619 if (componentAnnotation.isProduction()) { 620 scopes = 621 ImmutableSet.<Scope>builder() 622 .addAll(scopes).add(productionScope(processingEnv)) 623 .build(); 624 } 625 626 ImmutableSet<ComponentDescriptor> subcomponentsFromModules = 627 transitiveModules.stream() 628 .flatMap(transitiveModule -> transitiveModule.subcomponentDeclarations().stream()) 629 .map(SubcomponentDeclaration::subcomponentType) 630 .map(this::subcomponentDescriptor) 631 .collect(toImmutableSet()); 632 633 ComponentDescriptor componentDescriptor = 634 new AutoValue_ComponentDescriptor( 635 componentAnnotation, 636 typeElement, 637 componentDependencies, 638 transitiveModules, 639 scopes, 640 subcomponentsFromModules, 641 subcomponentsByFactoryMethod.buildOrThrow(), 642 subcomponentsByBuilderMethod.buildOrThrow(), 643 componentMethodsBuilder.build(), 644 creatorDescriptor); 645 componentDescriptor.bindingFactory = bindingFactory; 646 return componentDescriptor; 647 } 648 getDescriptorForComponentMethod( ComponentAnnotation componentAnnotation, XTypeElement componentElement, XMethodElement componentMethod)649 private ComponentMethodDescriptor getDescriptorForComponentMethod( 650 ComponentAnnotation componentAnnotation, 651 XTypeElement componentElement, 652 XMethodElement componentMethod) { 653 ComponentMethodDescriptor.Builder descriptor = 654 ComponentMethodDescriptor.builder(componentMethod); 655 656 XMethodType resolvedComponentMethod = componentMethod.asMemberOf(componentElement.getType()); 657 XType returnType = resolvedComponentMethod.getReturnType(); 658 if (isDeclared(returnType) 659 && !injectionAnnotations.getQualifier(componentMethod).isPresent()) { 660 XTypeElement returnTypeElement = returnType.getTypeElement(); 661 if (returnTypeElement.hasAnyAnnotation(subcomponentAnnotations())) { 662 // It's a subcomponent factory method. There is no dependency request, and there could be 663 // any number of parameters. Just return the descriptor. 664 return descriptor.subcomponent(subcomponentDescriptor(returnTypeElement)).build(); 665 } 666 if (isSubcomponentCreator(returnTypeElement)) { 667 descriptor.subcomponent( 668 subcomponentDescriptor(returnTypeElement.getEnclosingTypeElement())); 669 } 670 } 671 672 switch (componentMethod.getParameters().size()) { 673 case 0: 674 checkArgument( 675 !isVoid(returnType), "component method cannot be void: %s", componentMethod); 676 descriptor.dependencyRequest( 677 componentAnnotation.isProduction() 678 ? dependencyRequestFactory.forComponentProductionMethod( 679 componentMethod, resolvedComponentMethod) 680 : dependencyRequestFactory.forComponentProvisionMethod( 681 componentMethod, resolvedComponentMethod)); 682 break; 683 684 case 1: 685 checkArgument( 686 isVoid(returnType) 687 // TODO(bcorso): Replace this with isSameType()? 688 || returnType 689 .getTypeName() 690 .equals(resolvedComponentMethod.getParameterTypes().get(0).getTypeName()), 691 "members injection method must return void or parameter type: %s", 692 componentMethod); 693 descriptor.dependencyRequest( 694 dependencyRequestFactory.forComponentMembersInjectionMethod( 695 componentMethod, resolvedComponentMethod)); 696 break; 697 698 default: 699 throw new IllegalArgumentException( 700 "component method has too many parameters: " + componentMethod); 701 } 702 703 return descriptor.build(); 704 } 705 706 @Override clearCache()707 public void clearCache() { 708 cache.clear(); 709 } 710 } 711 } 712