• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.componentgenerator;
18 
19 import static com.google.auto.common.MoreElements.getLocalAndInheritedMethods;
20 import static com.google.auto.common.MoreTypes.asDeclared;
21 import static com.google.common.base.Preconditions.checkState;
22 import static com.squareup.javapoet.MethodSpec.constructorBuilder;
23 import static com.squareup.javapoet.MethodSpec.methodBuilder;
24 import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
25 import static dagger.internal.codegen.binding.ComponentCreatorKind.BUILDER;
26 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
27 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
28 import static dagger.internal.codegen.javapoet.CodeBlocks.parameterNames;
29 import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.BUILDER_METHOD;
30 import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.CANCELLATION_LISTENER_METHOD;
31 import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.COMPONENT_METHOD;
32 import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.CONSTRUCTOR;
33 import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.INITIALIZE_METHOD;
34 import static dagger.internal.codegen.writing.ComponentImplementation.TypeSpecKind.COMPONENT_CREATOR;
35 import static dagger.internal.codegen.writing.ComponentImplementation.TypeSpecKind.SUBCOMPONENT;
36 import static dagger.producers.CancellationPolicy.Propagation.PROPAGATE;
37 import static javax.lang.model.element.Modifier.FINAL;
38 import static javax.lang.model.element.Modifier.PRIVATE;
39 import static javax.lang.model.element.Modifier.PUBLIC;
40 import static javax.lang.model.element.Modifier.STATIC;
41 
42 import com.google.auto.common.MoreTypes;
43 import com.google.common.collect.ImmutableList;
44 import com.google.common.collect.ImmutableListMultimap;
45 import com.google.common.collect.ImmutableMap;
46 import com.google.common.collect.Iterables;
47 import com.google.common.collect.Lists;
48 import com.google.common.collect.Maps;
49 import com.google.common.collect.Multimaps;
50 import com.squareup.javapoet.ClassName;
51 import com.squareup.javapoet.CodeBlock;
52 import com.squareup.javapoet.MethodSpec;
53 import com.squareup.javapoet.ParameterSpec;
54 import com.squareup.javapoet.TypeSpec;
55 import dagger.internal.Preconditions;
56 import dagger.internal.codegen.binding.BindingGraph;
57 import dagger.internal.codegen.binding.ComponentCreatorDescriptor;
58 import dagger.internal.codegen.binding.ComponentCreatorKind;
59 import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
60 import dagger.internal.codegen.binding.ComponentRequirement;
61 import dagger.internal.codegen.binding.FrameworkType;
62 import dagger.internal.codegen.javapoet.AnnotationSpecs;
63 import dagger.internal.codegen.javapoet.CodeBlocks;
64 import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
65 import dagger.internal.codegen.langmodel.DaggerElements;
66 import dagger.internal.codegen.langmodel.DaggerTypes;
67 import dagger.internal.codegen.writing.ComponentBindingExpressions;
68 import dagger.internal.codegen.writing.ComponentCreatorImplementation;
69 import dagger.internal.codegen.writing.ComponentImplementation;
70 import dagger.internal.codegen.writing.ComponentRequirementExpressions;
71 import dagger.internal.codegen.writing.ParentComponent;
72 import dagger.model.Key;
73 import dagger.producers.internal.CancellationListener;
74 import dagger.producers.internal.Producers;
75 import java.util.Collection;
76 import java.util.List;
77 import java.util.Map;
78 import java.util.Optional;
79 import java.util.function.Function;
80 import javax.inject.Inject;
81 import javax.lang.model.element.ExecutableElement;
82 import javax.lang.model.type.DeclaredType;
83 
84 /** A builder of {@link ComponentImplementation}s. */
85 // This only needs to be public because it's referenced in an entry point.
86 public final class ComponentImplementationBuilder {
87   private static final String MAY_INTERRUPT_IF_RUNNING = "mayInterruptIfRunning";
88 
89   /**
90    * How many statements per {@code initialize()} or {@code onProducerFutureCancelled()} method
91    * before they get partitioned.
92    */
93   private static final int STATEMENTS_PER_METHOD = 100;
94 
95   private static final String CANCELLATION_LISTENER_METHOD_NAME = "onProducerFutureCancelled";
96 
97   private final Optional<ComponentImplementationBuilder> parent;
98   private final BindingGraph graph;
99   private final ComponentBindingExpressions bindingExpressions;
100   private final ComponentRequirementExpressions componentRequirementExpressions;
101   private final ComponentImplementation componentImplementation;
102   private final ComponentCreatorImplementationFactory componentCreatorImplementationFactory;
103   private final TopLevelImplementationComponent topLevelImplementationComponent;
104   private final DaggerTypes types;
105   private final DaggerElements elements;
106   private final KotlinMetadataUtil metadataUtil;
107   private boolean done;
108 
109   @Inject
ComponentImplementationBuilder( @arentComponent Optional<ComponentImplementationBuilder> parent, BindingGraph graph, ComponentBindingExpressions bindingExpressions, ComponentRequirementExpressions componentRequirementExpressions, ComponentImplementation componentImplementation, ComponentCreatorImplementationFactory componentCreatorImplementationFactory, TopLevelImplementationComponent topLevelImplementationComponent, DaggerTypes types, DaggerElements elements, KotlinMetadataUtil metadataUtil)110   ComponentImplementationBuilder(
111       @ParentComponent Optional<ComponentImplementationBuilder> parent,
112       BindingGraph graph,
113       ComponentBindingExpressions bindingExpressions,
114       ComponentRequirementExpressions componentRequirementExpressions,
115       ComponentImplementation componentImplementation,
116       ComponentCreatorImplementationFactory componentCreatorImplementationFactory,
117       TopLevelImplementationComponent topLevelImplementationComponent,
118       DaggerTypes types,
119       DaggerElements elements,
120       KotlinMetadataUtil metadataUtil) {
121     this.parent = parent;
122     this.graph = graph;
123     this.bindingExpressions = bindingExpressions;
124     this.componentRequirementExpressions = componentRequirementExpressions;
125     this.componentImplementation = componentImplementation;
126     this.componentCreatorImplementationFactory = componentCreatorImplementationFactory;
127     this.types = types;
128     this.elements = elements;
129     this.topLevelImplementationComponent = topLevelImplementationComponent;
130     this.metadataUtil = metadataUtil;
131   }
132 
133   /**
134    * Returns a {@link ComponentImplementation} for this component. This is only intended to be
135    * called once (and will throw on successive invocations). If the component must be regenerated,
136    * use a new instance.
137    */
build()138   ComponentImplementation build() {
139     checkState(
140         !done,
141         "ComponentImplementationBuilder has already built the ComponentImplementation for [%s].",
142         componentImplementation.name());
143     setSupertype();
144 
145     componentCreatorImplementationFactory.create()
146         .map(ComponentCreatorImplementation::spec)
147         .ifPresent(this::addCreatorClass);
148 
149     getLocalAndInheritedMethods(graph.componentTypeElement(), types, elements)
150         .forEach(method -> componentImplementation.claimMethodName(method.getSimpleName()));
151 
152     addFactoryMethods();
153     addInterfaceMethods();
154     addChildComponents();
155 
156     addConstructorAndInitializationMethods();
157 
158     if (graph.componentDescriptor().isProduction()) {
159       addCancellationListenerImplementation();
160     }
161 
162     done = true;
163     return componentImplementation;
164   }
165 
166   /** Set the supertype for this generated class. */
setSupertype()167   private void setSupertype() {
168     componentImplementation.addSupertype(graph.componentTypeElement());
169   }
170 
addCreatorClass(TypeSpec creator)171   private void addCreatorClass(TypeSpec creator) {
172     if (parent.isPresent()) {
173       // In an inner implementation of a subcomponent the creator is a peer class.
174       parent.get().componentImplementation.addType(SUBCOMPONENT, creator);
175     } else {
176       componentImplementation.addType(COMPONENT_CREATOR, creator);
177     }
178   }
179 
addFactoryMethods()180   private void addFactoryMethods() {
181     if (parent.isPresent()) {
182       graph.factoryMethod().ifPresent(this::createSubcomponentFactoryMethod);
183     } else {
184       createRootComponentFactoryMethod();
185     }
186   }
187 
addInterfaceMethods()188   private void addInterfaceMethods() {
189     // Each component method may have been declared by several supertypes. We want to implement
190     // only one method for each distinct signature.
191     ImmutableListMultimap<MethodSignature, ComponentMethodDescriptor> componentMethodsBySignature =
192         Multimaps.index(graph.componentDescriptor().entryPointMethods(), this::getMethodSignature);
193     for (List<ComponentMethodDescriptor> methodsWithSameSignature :
194         Multimaps.asMap(componentMethodsBySignature).values()) {
195       ComponentMethodDescriptor anyOneMethod = methodsWithSameSignature.stream().findAny().get();
196       MethodSpec methodSpec = bindingExpressions.getComponentMethod(anyOneMethod);
197 
198       componentImplementation.addMethod(COMPONENT_METHOD, methodSpec);
199     }
200   }
201 
addCancellationListenerImplementation()202   private void addCancellationListenerImplementation() {
203     componentImplementation.addSupertype(elements.getTypeElement(CancellationListener.class));
204     componentImplementation.claimMethodName(CANCELLATION_LISTENER_METHOD_NAME);
205 
206     ImmutableList<ParameterSpec> parameters =
207         ImmutableList.of(ParameterSpec.builder(boolean.class, MAY_INTERRUPT_IF_RUNNING).build());
208 
209     MethodSpec.Builder methodBuilder =
210         methodBuilder(CANCELLATION_LISTENER_METHOD_NAME)
211             .addModifiers(PUBLIC)
212             .addAnnotation(Override.class)
213             .addParameters(parameters);
214 
215     ImmutableList<CodeBlock> cancellationStatements = cancellationStatements();
216 
217     if (cancellationStatements.size() < STATEMENTS_PER_METHOD) {
218       methodBuilder.addCode(CodeBlocks.concat(cancellationStatements)).build();
219     } else {
220       ImmutableList<MethodSpec> cancelProducersMethods =
221           createPartitionedMethods(
222               "cancelProducers",
223               parameters,
224               cancellationStatements,
225               methodName -> methodBuilder(methodName).addModifiers(PRIVATE));
226       for (MethodSpec cancelProducersMethod : cancelProducersMethods) {
227         methodBuilder.addStatement("$N($L)", cancelProducersMethod, MAY_INTERRUPT_IF_RUNNING);
228         componentImplementation.addMethod(CANCELLATION_LISTENER_METHOD, cancelProducersMethod);
229       }
230     }
231 
232     cancelParentStatement().ifPresent(methodBuilder::addCode);
233 
234     componentImplementation.addMethod(CANCELLATION_LISTENER_METHOD, methodBuilder.build());
235   }
236 
cancellationStatements()237   private ImmutableList<CodeBlock> cancellationStatements() {
238     // Reversing should order cancellations starting from entry points and going down to leaves
239     // rather than the other way around. This shouldn't really matter but seems *slightly*
240     // preferable because:
241     // When a future that another future depends on is cancelled, that cancellation will propagate
242     // up the future graph toward the entry point. Cancelling in reverse order should ensure that
243     // everything that depends on a particular node has already been cancelled when that node is
244     // cancelled, so there's no need to propagate. Otherwise, when we cancel a leaf node, it might
245     // propagate through most of the graph, making most of the cancel calls that follow in the
246     // onProducerFutureCancelled method do nothing.
247     ImmutableList<Key> cancellationKeys =
248         componentImplementation.getCancellableProducerKeys().reverse();
249 
250     ImmutableList.Builder<CodeBlock> cancellationStatements = ImmutableList.builder();
251     for (Key cancellationKey : cancellationKeys) {
252       cancellationStatements.add(
253           CodeBlock.of(
254               "$T.cancel($L, $N);",
255               Producers.class,
256               bindingExpressions
257                   .getDependencyExpression(
258                       bindingRequest(cancellationKey, FrameworkType.PRODUCER_NODE),
259                       componentImplementation.name())
260                   .codeBlock(),
261               MAY_INTERRUPT_IF_RUNNING));
262     }
263     return cancellationStatements.build();
264   }
265 
cancelParentStatement()266   private Optional<CodeBlock> cancelParentStatement() {
267     if (!shouldPropagateCancellationToParent()) {
268       return Optional.empty();
269     }
270     return Optional.of(
271         CodeBlock.builder()
272             .addStatement(
273                 "$T.this.$N($N)",
274                 parent.get().componentImplementation.name(),
275                 CANCELLATION_LISTENER_METHOD_NAME,
276                 MAY_INTERRUPT_IF_RUNNING)
277             .build());
278   }
279 
shouldPropagateCancellationToParent()280   private boolean shouldPropagateCancellationToParent() {
281     return parent.isPresent()
282         && parent
283             .get()
284             .componentImplementation
285             .componentDescriptor()
286             .cancellationPolicy()
287             .map(policy -> policy.fromSubcomponents().equals(PROPAGATE))
288             .orElse(false);
289   }
290 
getMethodSignature(ComponentMethodDescriptor method)291   private MethodSignature getMethodSignature(ComponentMethodDescriptor method) {
292     return MethodSignature.forComponentMethod(
293         method, MoreTypes.asDeclared(graph.componentTypeElement().asType()), types);
294   }
295 
addChildComponents()296   private void addChildComponents() {
297     for (BindingGraph subgraph : graph.subgraphs()) {
298       componentImplementation.addType(SUBCOMPONENT, childComponent(subgraph));
299     }
300   }
301 
childComponent(BindingGraph childGraph)302   private TypeSpec childComponent(BindingGraph childGraph) {
303     return topLevelImplementationComponent
304         .currentImplementationSubcomponentBuilder()
305         .componentImplementation(subcomponent(childGraph))
306         .bindingGraph(childGraph)
307         .parentBuilder(Optional.of(this))
308         .parentBindingExpressions(Optional.of(bindingExpressions))
309         .parentRequirementExpressions(Optional.of(componentRequirementExpressions))
310         .build()
311         .componentImplementationBuilder()
312         .build()
313         .generate()
314         .build();
315   }
316 
317   /** Creates an inner subcomponent implementation. */
subcomponent(BindingGraph childGraph)318   private ComponentImplementation subcomponent(BindingGraph childGraph) {
319     return componentImplementation.childComponentImplementation(childGraph);
320   }
321 
322   /** Creates and adds the constructor and methods needed for initializing the component. */
addConstructorAndInitializationMethods()323   private void addConstructorAndInitializationMethods() {
324     MethodSpec.Builder constructor = constructorBuilder().addModifiers(PRIVATE);
325     implementInitializationMethod(constructor, initializationParameters());
326     componentImplementation.addMethod(CONSTRUCTOR, constructor.build());
327   }
328 
329   /** Adds parameters and code to the given {@code initializationMethod}. */
implementInitializationMethod( MethodSpec.Builder initializationMethod, ImmutableMap<ComponentRequirement, ParameterSpec> initializationParameters)330   private void implementInitializationMethod(
331       MethodSpec.Builder initializationMethod,
332       ImmutableMap<ComponentRequirement, ParameterSpec> initializationParameters) {
333     initializationMethod.addParameters(initializationParameters.values());
334     initializationMethod.addCode(
335         CodeBlocks.concat(componentImplementation.getComponentRequirementInitializations()));
336     addInitializeMethods(initializationMethod, initializationParameters.values().asList());
337   }
338 
339   /**
340    * Adds any necessary {@code initialize} methods to the component and adds calls to them to the
341    * given {@code callingMethod}.
342    */
addInitializeMethods( MethodSpec.Builder callingMethod, ImmutableList<ParameterSpec> parameters)343   private void addInitializeMethods(
344       MethodSpec.Builder callingMethod, ImmutableList<ParameterSpec> parameters) {
345     // TODO(cgdecker): It's not the case that each initialize() method has need for all of the
346     // given parameters. In some cases, those parameters may have already been assigned to fields
347     // which could be referenced instead. In other cases, an initialize method may just not need
348     // some of the parameters because the set of initializations in that partition does not
349     // include any reference to them. Right now, the Dagger code has no way of getting that
350     // information because, among other things, componentImplementation.getImplementations() just
351     // returns a bunch of CodeBlocks with no semantic information. Additionally, we may not know
352     // yet whether a field will end up needing to be created for a specific requirement, and we
353     // don't want to create a field that ends up only being used during initialization.
354     CodeBlock args = parameterNames(parameters);
355     ImmutableList<MethodSpec> methods =
356         createPartitionedMethods(
357             "initialize",
358             makeFinal(parameters),
359             componentImplementation.getInitializations(),
360             methodName ->
361                 methodBuilder(methodName)
362                     .addModifiers(PRIVATE)
363                     /* TODO(gak): Strictly speaking, we only need the suppression here if we are
364                      * also initializing a raw field in this method, but the structure of this
365                      * code makes it awkward to pass that bit through.  This will be cleaned up
366                      * when we no longer separate fields and initialization as we do now. */
367                     .addAnnotation(AnnotationSpecs.suppressWarnings(UNCHECKED)));
368     for (MethodSpec method : methods) {
369       callingMethod.addStatement("$N($L)", method, args);
370       componentImplementation.addMethod(INITIALIZE_METHOD, method);
371     }
372   }
373 
374   /**
375    * Creates one or more methods, all taking the given {@code parameters}, which partition the given
376    * list of {@code statements} among themselves such that no method has more than {@code
377    * STATEMENTS_PER_METHOD} statements in it and such that the returned methods, if called in order,
378    * will execute the {@code statements} in the given order.
379    */
createPartitionedMethods( String methodName, Iterable<ParameterSpec> parameters, List<CodeBlock> statements, Function<String, MethodSpec.Builder> methodBuilderCreator)380   private ImmutableList<MethodSpec> createPartitionedMethods(
381       String methodName,
382       Iterable<ParameterSpec> parameters,
383       List<CodeBlock> statements,
384       Function<String, MethodSpec.Builder> methodBuilderCreator) {
385     return Lists.partition(statements, STATEMENTS_PER_METHOD).stream()
386         .map(
387             partition ->
388                 methodBuilderCreator
389                     .apply(componentImplementation.getUniqueMethodName(methodName))
390                     .addParameters(parameters)
391                     .addCode(CodeBlocks.concat(partition))
392                     .build())
393         .collect(toImmutableList());
394   }
395 
396   /** Returns the given parameters with a final modifier added. */
makeFinal(Collection<ParameterSpec> parameters)397   private final ImmutableList<ParameterSpec> makeFinal(Collection<ParameterSpec> parameters) {
398     return parameters.stream()
399         .map(param -> param.toBuilder().addModifiers(FINAL).build())
400         .collect(toImmutableList());
401   }
402 
403   /**
404    * Returns the parameters for the constructor as a map from the requirement the parameter fulfills
405    * to the spec for the parameter.
406    */
initializationParameters()407   private final ImmutableMap<ComponentRequirement, ParameterSpec> initializationParameters() {
408     Map<ComponentRequirement, ParameterSpec> parameters;
409     if (componentImplementation.componentDescriptor().hasCreator()) {
410       parameters = Maps.toMap(graph.componentRequirements(), ComponentRequirement::toParameterSpec);
411     } else if (graph.factoryMethod().isPresent()) {
412       parameters = getFactoryMethodParameters(graph);
413     } else {
414       throw new AssertionError(
415           "Expected either a component creator or factory method but found neither.");
416     }
417 
418     return renameParameters(parameters);
419   }
420 
421   /**
422    * Renames the given parameters to guarantee their names do not conflict with fields in the
423    * component to ensure that a parameter is never referenced where a reference to a field was
424    * intended.
425    */
426   // TODO(cgdecker): This is a bit kludgy; it would be preferable to either qualify the field
427   // references with "this." or "super." when needed to disambiguate between field and parameter,
428   // but that would require more context than is currently available when the code referencing a
429   // field is generated.
renameParameters( Map<ComponentRequirement, ParameterSpec> parameters)430   private ImmutableMap<ComponentRequirement, ParameterSpec> renameParameters(
431       Map<ComponentRequirement, ParameterSpec> parameters) {
432     return ImmutableMap.copyOf(
433         Maps.transformEntries(
434             parameters,
435             (requirement, parameter) ->
436                 renameParameter(
437                     parameter,
438                     componentImplementation.getParameterName(requirement, parameter.name))));
439   }
440 
renameParameter(ParameterSpec parameter, String newName)441   private ParameterSpec renameParameter(ParameterSpec parameter, String newName) {
442     return ParameterSpec.builder(parameter.type, newName)
443         .addAnnotations(parameter.annotations)
444         .addModifiers(parameter.modifiers)
445         .build();
446   }
447 
createRootComponentFactoryMethod()448   private void createRootComponentFactoryMethod() {
449     checkState(!parent.isPresent());
450     // Top-level components have a static method that returns a builder or factory for the
451     // component. If the user defined a @Component.Builder or @Component.Factory, an
452     // implementation of their type is returned. Otherwise, an autogenerated Builder type is
453     // returned.
454     // TODO(cgdecker): Replace this abomination with a small class?
455     // Better yet, change things so that an autogenerated builder type has a descriptor of sorts
456     // just like a user-defined creator type.
457     ComponentCreatorKind creatorKind;
458     ClassName creatorType;
459     String factoryMethodName;
460     boolean noArgFactoryMethod;
461     Optional<ComponentCreatorDescriptor> creatorDescriptor =
462         graph.componentDescriptor().creatorDescriptor();
463     if (creatorDescriptor.isPresent()) {
464       ComponentCreatorDescriptor descriptor = creatorDescriptor.get();
465       creatorKind = descriptor.kind();
466       creatorType = ClassName.get(descriptor.typeElement());
467       factoryMethodName = descriptor.factoryMethod().getSimpleName().toString();
468       noArgFactoryMethod = descriptor.factoryParameters().isEmpty();
469     } else {
470       creatorKind = BUILDER;
471       creatorType = componentImplementation.getCreatorName();
472       factoryMethodName = "build";
473       noArgFactoryMethod = true;
474     }
475 
476     MethodSpec creatorFactoryMethod =
477         methodBuilder(creatorKind.methodName())
478             .addModifiers(PUBLIC, STATIC)
479             .returns(creatorType)
480             .addStatement("return new $T()", componentImplementation.getCreatorName())
481             .build();
482     componentImplementation.addMethod(BUILDER_METHOD, creatorFactoryMethod);
483     if (noArgFactoryMethod && canInstantiateAllRequirements()) {
484       componentImplementation.addMethod(
485           BUILDER_METHOD,
486           methodBuilder("create")
487               .returns(ClassName.get(graph.componentTypeElement()))
488               .addModifiers(PUBLIC, STATIC)
489               .addStatement("return new $L().$L()", creatorKind.typeName(), factoryMethodName)
490               .build());
491     }
492   }
493 
494   /** {@code true} if all of the graph's required dependencies can be automatically constructed */
canInstantiateAllRequirements()495   private boolean canInstantiateAllRequirements() {
496     return !Iterables.any(
497         graph.componentRequirements(),
498         dependency -> dependency.requiresAPassedInstance(elements, types, metadataUtil));
499   }
500 
createSubcomponentFactoryMethod(ExecutableElement factoryMethod)501   private void createSubcomponentFactoryMethod(ExecutableElement factoryMethod) {
502     checkState(parent.isPresent());
503     Collection<ParameterSpec> params = getFactoryMethodParameters(graph).values();
504     MethodSpec.Builder method = MethodSpec.overriding(factoryMethod, parentType(), types);
505     params.forEach(
506         param -> method.addStatement("$T.checkNotNull($N)", Preconditions.class, param));
507     method.addStatement(
508         "return new $T($L)", componentImplementation.name(), parameterNames(params));
509 
510     parent.get().componentImplementation.addMethod(COMPONENT_METHOD, method.build());
511   }
512 
parentType()513   private DeclaredType parentType() {
514     return asDeclared(parent.get().graph.componentTypeElement().asType());
515   }
516   /**
517    * Returns the map of {@link ComponentRequirement}s to {@link ParameterSpec}s for the given
518    * graph's factory method.
519    */
getFactoryMethodParameters( BindingGraph graph)520   private static Map<ComponentRequirement, ParameterSpec> getFactoryMethodParameters(
521       BindingGraph graph) {
522     return Maps.transformValues(graph.factoryMethodParameters(), ParameterSpec::get);
523   }
524 }
525