• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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