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