• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Dagger Authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package dagger.internal.codegen;
18 
19 import static com.google.common.base.CaseFormat.LOWER_CAMEL;
20 import static com.google.common.base.CaseFormat.UPPER_CAMEL;
21 import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
22 import static com.google.common.base.Preconditions.checkArgument;
23 import static com.google.common.base.Preconditions.checkNotNull;
24 import static com.google.common.base.Preconditions.checkState;
25 import static com.squareup.javapoet.TypeSpec.classBuilder;
26 import static dagger.internal.codegen.ComponentCreatorKind.BUILDER;
27 import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
28 import static dagger.internal.codegen.serialization.ProtoSerialization.toAnnotationValue;
29 import static java.util.stream.Collectors.toList;
30 import static javax.lang.model.element.Modifier.ABSTRACT;
31 import static javax.lang.model.element.Modifier.FINAL;
32 import static javax.lang.model.element.Modifier.PUBLIC;
33 
34 import com.google.auto.value.AutoValue;
35 import com.google.common.base.Supplier;
36 import com.google.common.collect.ImmutableList;
37 import com.google.common.collect.ImmutableMap;
38 import com.google.common.collect.ImmutableSet;
39 import com.google.common.collect.LinkedHashMultimap;
40 import com.google.common.collect.ListMultimap;
41 import com.google.common.collect.Maps;
42 import com.google.common.collect.MultimapBuilder;
43 import com.google.common.collect.SetMultimap;
44 import com.google.common.collect.Sets;
45 import com.squareup.javapoet.AnnotationSpec;
46 import com.squareup.javapoet.ClassName;
47 import com.squareup.javapoet.CodeBlock;
48 import com.squareup.javapoet.FieldSpec;
49 import com.squareup.javapoet.MethodSpec;
50 import com.squareup.javapoet.TypeSpec;
51 import dagger.internal.ConfigureInitializationParameters;
52 import dagger.internal.ModifiableBinding;
53 import dagger.internal.ModifiableModule;
54 import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod;
55 import dagger.internal.codegen.javapoet.TypeSpecs;
56 import dagger.model.DependencyRequest;
57 import dagger.model.Key;
58 import dagger.model.RequestKind;
59 import java.util.ArrayList;
60 import java.util.HashMap;
61 import java.util.HashSet;
62 import java.util.LinkedHashMap;
63 import java.util.LinkedHashSet;
64 import java.util.List;
65 import java.util.Map;
66 import java.util.Optional;
67 import java.util.Set;
68 import javax.lang.model.element.Modifier;
69 import javax.lang.model.element.NestingKind;
70 import javax.lang.model.element.TypeElement;
71 import javax.lang.model.type.TypeMirror;
72 
73 /** The implementation of a component type. */
74 final class ComponentImplementation {
75   /** A type of field that this component can contain. */
76   enum FieldSpecKind {
77 
78     /** A field required by the component, e.g. module instances. */
79     COMPONENT_REQUIREMENT_FIELD,
80 
81     /**
82      * A field for the lock and cached value for {@linkplain PrivateMethodBindingExpression
83      * private-method scoped bindings}.
84      */
85     PRIVATE_METHOD_SCOPED_FIELD,
86 
87     /** A framework field for type T, e.g. {@code Provider<T>}. */
88     FRAMEWORK_FIELD,
89 
90     /** A static field that always returns an absent {@code Optional} value for the binding. */
91     ABSENT_OPTIONAL_FIELD
92   }
93 
94   /** A type of method that this component can contain. */
95   // TODO(user, dpb): Change the oder to constructor, initialize, component, then private
96   // (including MIM and AOM—why treat those separately?).
97   enum MethodSpecKind {
98     /** The component constructor. */
99     CONSTRUCTOR,
100 
101     /**
102      * In ahead-of-time subcomponents, this method coordinates the invocation of {@link
103      * #INITIALIZE_METHOD initialization methods} instead of constructors.
104      */
105     // TODO(b/117833324): try to merge this with other initialize() methods so it looks more natural
106     CONFIGURE_INITIALIZATION_METHOD,
107 
108     /** A builder method for the component. (Only used by the root component.) */
109     BUILDER_METHOD,
110 
111     /** A private method that wraps dependency expressions. */
112     PRIVATE_METHOD,
113 
114     /** An initialization method that initializes component requirements and framework types. */
115     INITIALIZE_METHOD,
116 
117     /** An implementation of a component interface method. */
118     COMPONENT_METHOD,
119 
120     /** A private method that encapsulates members injection logic for a binding. */
121     MEMBERS_INJECTION_METHOD,
122 
123     /** A static method that always returns an absent {@code Optional} value for the binding. */
124     ABSENT_OPTIONAL_METHOD,
125 
126     /**
127      * A method that encapsulates a modifiable binding. A binding is modifiable if it can change
128      * across implementations of a subcomponent. This is only relevant for ahead-of-time
129      * subcomponents.
130      */
131     MODIFIABLE_BINDING_METHOD,
132 
133     /**
134      * The {@link dagger.producers.internal.CancellationListener#onProducerFutureCancelled(boolean)}
135      * method for a production component.
136      */
137     CANCELLATION_LISTENER_METHOD,
138     ;
139   }
140 
141   /** A type of nested class that this component can contain. */
142   enum TypeSpecKind {
143     /** A factory class for a present optional binding. */
144     PRESENT_FACTORY,
145 
146     /** A class for the component creator (only used by the root component.) */
147     COMPONENT_CREATOR,
148 
149     /** A provider class for a component provision. */
150     COMPONENT_PROVISION_FACTORY,
151 
152     /** A class for the subcomponent or subcomponent builder. */
153     SUBCOMPONENT
154   }
155 
156   /**
157    * The method spec for a {@code configureInitialization} method plus details on the component
158    * requirements that its parameters are associated with.
159    */
160   @AutoValue
161   abstract static class ConfigureInitializationMethod {
162     /** Creates a new {@link ConfigureInitializationMethod}. */
create( MethodSpec spec, ImmutableSet<ComponentRequirement> parameters)163     static ConfigureInitializationMethod create(
164         MethodSpec spec, ImmutableSet<ComponentRequirement> parameters) {
165       return new AutoValue_ComponentImplementation_ConfigureInitializationMethod(spec, parameters);
166     }
167 
168     /** The spec for the method. */
spec()169     abstract MethodSpec spec();
170 
171     /**
172      * The component requirements associated with the method's parameters, in the same order as the
173      * parameters.
174      */
parameters()175     abstract ImmutableSet<ComponentRequirement> parameters();
176   }
177 
178   private final CompilerOptions compilerOptions;
179   private final ComponentDescriptor componentDescriptor;
180   private final Optional<BindingGraph> graph;
181   private final ClassName name;
182   private final NestingKind nestingKind;
183   private final boolean isAbstract;
184   private final Optional<ComponentImplementation> superclassImplementation;
185   private Optional<ComponentCreatorImplementation> creatorImplementation;
186   private final Map<TypeElement, ComponentImplementation> childImplementations = new HashMap<>();
187   private final TypeSpec.Builder component;
188   private final Optional<SubcomponentNames> subcomponentNames;
189   private final UniqueNameSet componentFieldNames = new UniqueNameSet();
190   private final UniqueNameSet componentMethodNames = new UniqueNameSet();
191   private final List<CodeBlock> initializations = new ArrayList<>();
192   private final Set<ComponentRequirement> componentRequirementParameters = new HashSet<>();
193   private final List<CodeBlock> componentRequirementInitializations = new ArrayList<>();
194   private final Map<ComponentRequirement, String> componentRequirementParameterNames =
195       new HashMap<>();
196   private final Set<Key> cancellableProducerKeys = new LinkedHashSet<>();
197   private final ListMultimap<FieldSpecKind, FieldSpec> fieldSpecsMap =
198       MultimapBuilder.enumKeys(FieldSpecKind.class).arrayListValues().build();
199   private final ListMultimap<MethodSpecKind, MethodSpec> methodSpecsMap =
200       MultimapBuilder.enumKeys(MethodSpecKind.class).arrayListValues().build();
201   private final ListMultimap<TypeSpecKind, TypeSpec> typeSpecsMap =
202       MultimapBuilder.enumKeys(TypeSpecKind.class).arrayListValues().build();
203   private final List<Supplier<TypeSpec>> switchingProviderSupplier = new ArrayList<>();
204   private final ModifiableBindingMethods modifiableBindingMethods = new ModifiableBindingMethods();
205   private final SetMultimap<BindingRequest, Key> multibindingContributionsMade =
206       LinkedHashMultimap.create();
207   private Optional<ConfigureInitializationMethod> configureInitializationMethod = Optional.empty();
208   private final Map<ComponentRequirement, String> modifiableModuleMethods = new LinkedHashMap<>();
209 
ComponentImplementation( ComponentDescriptor componentDescriptor, Optional<BindingGraph> graph, ClassName name, NestingKind nestingKind, Optional<ComponentImplementation> superclassImplementation, Optional<SubcomponentNames> subcomponentNames, CompilerOptions compilerOptions, ImmutableSet<Modifier> modifiers)210   private ComponentImplementation(
211       ComponentDescriptor componentDescriptor,
212       Optional<BindingGraph> graph,
213       ClassName name,
214       NestingKind nestingKind,
215       Optional<ComponentImplementation> superclassImplementation,
216       Optional<SubcomponentNames> subcomponentNames,
217       CompilerOptions compilerOptions,
218       ImmutableSet<Modifier> modifiers) {
219     checkName(name, nestingKind);
220     this.compilerOptions = compilerOptions;
221     this.componentDescriptor = componentDescriptor;
222     this.graph = graph;
223     this.name = name;
224     this.nestingKind = nestingKind;
225     this.isAbstract = modifiers.contains(ABSTRACT);
226     this.superclassImplementation = superclassImplementation;
227     this.component = classBuilder(name);
228     modifiers.forEach(component::addModifiers);
229     this.subcomponentNames = subcomponentNames;
230   }
231 
232   /** Returns a component implementation for a top-level component. */
topLevelComponentImplementation( BindingGraph graph, ClassName name, SubcomponentNames subcomponentNames, CompilerOptions compilerOptions)233   static ComponentImplementation topLevelComponentImplementation(
234       BindingGraph graph,
235       ClassName name,
236       SubcomponentNames subcomponentNames,
237       CompilerOptions compilerOptions) {
238     return new ComponentImplementation(
239         graph.componentDescriptor(),
240         Optional.of(graph),
241         name,
242         NestingKind.TOP_LEVEL,
243         Optional.empty(), // superclass implementation
244         Optional.of(subcomponentNames),
245         compilerOptions,
246         topLevelComponentImplementationModifiers(graph));
247   }
248 
topLevelComponentImplementationModifiers( BindingGraph graph)249   private static ImmutableSet<Modifier> topLevelComponentImplementationModifiers(
250       BindingGraph graph) {
251     ImmutableSet.Builder<Modifier> modifiers = ImmutableSet.builder();
252     if (graph.componentTypeElement().getModifiers().contains(PUBLIC)
253         || graph.componentDescriptor().isSubcomponent()) {
254       // TODO(ronshapiro): perhaps all generated components should be non-public?
255       modifiers.add(PUBLIC);
256     }
257     return modifiers.add(graph.componentDescriptor().isSubcomponent() ? ABSTRACT : FINAL).build();
258   }
259 
260   /** Returns a component implementation that is a child of the current implementation. */
childComponentImplementation( BindingGraph graph, Optional<ComponentImplementation> superclassImplementation, Modifier... modifiers)261   ComponentImplementation childComponentImplementation(
262       BindingGraph graph,
263       Optional<ComponentImplementation> superclassImplementation,
264       Modifier... modifiers) {
265     return new ComponentImplementation(
266         graph.componentDescriptor(),
267         Optional.of(graph),
268         getSubcomponentName(graph.componentDescriptor()),
269         NestingKind.MEMBER,
270         superclassImplementation,
271         subcomponentNames,
272         compilerOptions,
273         ImmutableSet.copyOf(modifiers));
274   }
275 
276   /**
277    * Returns a component implementation that models a previously compiled class. This {@link
278    * ComponentImplementation} is not used for code generation itself; it is used to determine what
279    * methods need to be implemented in a subclass implementation.
280    */
forDeserializedComponent( ComponentDescriptor componentDescriptor, ClassName name, NestingKind nestingKind, Optional<ComponentImplementation> superclassImplementation, CompilerOptions compilerOptions)281   static ComponentImplementation forDeserializedComponent(
282       ComponentDescriptor componentDescriptor,
283       ClassName name,
284       NestingKind nestingKind,
285       Optional<ComponentImplementation> superclassImplementation,
286       CompilerOptions compilerOptions) {
287     return new ComponentImplementation(
288         componentDescriptor,
289         Optional.empty(),
290         name,
291         nestingKind,
292         superclassImplementation,
293         Optional.empty(),
294         compilerOptions,
295         ImmutableSet.of(PUBLIC, ABSTRACT));
296   }
297 
298   // TODO(dpb): Just determine the nesting kind from the name.
checkName(ClassName name, NestingKind nestingKind)299   private static void checkName(ClassName name, NestingKind nestingKind) {
300     switch (nestingKind) {
301       case TOP_LEVEL:
302         checkArgument(
303             name.enclosingClassName() == null, "must be a top-level class name: %s", name);
304         break;
305 
306       case MEMBER:
307         checkNotNull(name.enclosingClassName(), "must not be a top-level class name: %s", name);
308         break;
309 
310       default:
311         throw new IllegalArgumentException(
312             "nestingKind must be TOP_LEVEL or MEMBER: " + nestingKind);
313     }
314   }
315 
316   /**
317    * Returns {@code true} if this component implementation represents a component that has already
318    * been compiled. If this returns true, the implementation will have no {@link #graph
319    * BindingGraph}.
320    */
isDeserializedImplementation()321   boolean isDeserializedImplementation() {
322     return !graph.isPresent();
323   }
324 
325   // TODO(ronshapiro): see if we can remove this method and instead inject it in the objects that
326   // need it.
327   /** Returns the binding graph for the component being generated. */
graph()328   BindingGraph graph() {
329     checkState(!isDeserializedImplementation(),
330         "A BindingGraph is not available for deserialized component implementations.");
331     return graph.get();
332   }
333 
334   /** Returns the descriptor for the component being generated. */
componentDescriptor()335   ComponentDescriptor componentDescriptor() {
336     return componentDescriptor;
337   }
338 
339   /** Returns the name of the component. */
name()340   ClassName name() {
341     return name;
342   }
343 
344   /** Returns whether or not the implementation is nested within another class. */
isNested()345   boolean isNested() {
346     return nestingKind.isNested();
347   }
348 
349   /** Returns whether or not the implementation is abstract. */
isAbstract()350   boolean isAbstract() {
351     return isAbstract;
352   }
353 
354   /** Returns the superclass implementation. */
superclassImplementation()355   Optional<ComponentImplementation> superclassImplementation() {
356     return superclassImplementation;
357   }
358 
359   /**
360    * Returns the base implementation of this component in ahead-of-time subcomponents mode. If this
361    * is the base implementation, this returns {@link Optional#empty()}.
362    */
baseImplementation()363   Optional<ComponentImplementation> baseImplementation() {
364     return superclassImplementation.isPresent()
365         ? Optional.of(Optionals.rootmostValue(this, c -> c.superclassImplementation))
366         : Optional.empty();
367   }
368 
369   /**
370    * Returns the {@link #configureInitializationMethod()} of the nearest supertype that defines one,
371    * if any.
372    *
373    * <p>Only returns a present value in {@link CompilerOptions#aheadOfTimeSubcomponents()}.
374    */
superConfigureInitializationMethod()375   Optional<ConfigureInitializationMethod> superConfigureInitializationMethod() {
376     for (Optional<ComponentImplementation> currentSuper = superclassImplementation;
377         currentSuper.isPresent();
378         currentSuper = currentSuper.get().superclassImplementation) {
379       if (currentSuper.get().configureInitializationMethod.isPresent()) {
380         return currentSuper.get().configureInitializationMethod;
381       }
382     }
383     return Optional.empty();
384   }
385 
386   /**
387    * The requirements for creating an instance of this component implementation type.
388    *
389    * <p>If this component implementation is concrete, these requirements will be in the order that
390    * the implementation's constructor takes them as parameters.
391    */
requirements()392   ImmutableSet<ComponentRequirement> requirements() {
393     // If the base implementation's creator is being generated in ahead-of-time-subcomponents
394     // mode, this uses the ComponentDescriptor's requirements() since Dagger doesn't know what
395     // modules may end being unused or owned by an ancestor component. Otherwise, we use the
396     // necessary component requirements.
397     // TODO(ronshapiro): can we remove the second condition here? Or, is it never going to be
398     // called, so we should enforce that invariant?
399     return isAbstract() && !superclassImplementation().isPresent()
400         ? componentDescriptor().requirements()
401         : graph().componentRequirements();
402   }
403 
404   /**
405    * Returns the {@link MethodSpecKind#CONFIGURE_INITIALIZATION_METHOD} of this implementation if
406    * there is one.
407    *
408    * <p>Only returns a present value in {@link CompilerOptions#aheadOfTimeSubcomponents()}.
409    */
configureInitializationMethod()410   Optional<ConfigureInitializationMethod> configureInitializationMethod() {
411     return configureInitializationMethod;
412   }
413 
414   /**
415    * Set's this component implementation's {@code configureInitialization()} method and {@linkplain
416    * #addMethod(MethodSpecKind, MethodSpec) adds the method}.
417    */
setConfigureInitializationMethod(ConfigureInitializationMethod method)418   void setConfigureInitializationMethod(ConfigureInitializationMethod method) {
419     configureInitializationMethod = Optional.of(method);
420     addMethod(
421         MethodSpecKind.CONFIGURE_INITIALIZATION_METHOD,
422         addConfigureInitializationMetadata(method));
423   }
424 
addConfigureInitializationMetadata(ConfigureInitializationMethod method)425   private MethodSpec addConfigureInitializationMetadata(ConfigureInitializationMethod method) {
426     if (!shouldEmitModifiableMetadataAnnotations()) {
427       return method.spec();
428     }
429     AnnotationSpec.Builder annotation =
430         AnnotationSpec.builder(ConfigureInitializationParameters.class);
431     for (ComponentRequirement parameter : method.parameters()) {
432       annotation.addMember("value", toAnnotationValue(parameter.toProto()));
433     }
434 
435     return method.spec().toBuilder().addAnnotation(annotation.build()).build();
436   }
437 
setCreatorImplementation(Optional<ComponentCreatorImplementation> creatorImplementation)438   void setCreatorImplementation(Optional<ComponentCreatorImplementation> creatorImplementation) {
439     checkState(
440         this.creatorImplementation == null, "setCreatorImplementation has already been called");
441     this.creatorImplementation = creatorImplementation;
442   }
443 
creatorImplementation()444   Optional<ComponentCreatorImplementation> creatorImplementation() {
445     checkState(creatorImplementation != null, "setCreatorImplementation has not been called yet");
446     return creatorImplementation;
447   }
448 
449   /**
450    * Returns the {@link ComponentCreatorImplementation} defined in the base implementation for this
451    * component, if one exists.
452    */
baseCreatorImplementation()453   Optional<ComponentCreatorImplementation> baseCreatorImplementation() {
454     return baseImplementation().flatMap(baseImpl -> baseImpl.creatorImplementation());
455   }
456 
457   /**
458    * Returns the kind of this component's creator.
459    *
460    * @throws IllegalStateException if the component has no creator
461    */
creatorKind()462   private ComponentCreatorKind creatorKind() {
463     checkState(componentDescriptor().hasCreator());
464     return componentDescriptor()
465         .creatorDescriptor()
466         .map(ComponentCreatorDescriptor::kind)
467         .orElse(BUILDER);
468   }
469 
470   /**
471    * Returns the name of the creator class for this component. It will be a sibling of this
472    * generated class unless this is a top-level component, in which case it will be nested.
473    */
getCreatorName()474   ClassName getCreatorName() {
475     return isNested()
476         ? name.peerClass(subcomponentNames().getCreatorName(componentDescriptor()))
477         : name.nestedClass(creatorKind().typeName());
478   }
479 
480   /** Returns the name of the nested implementation class for a child component. */
getSubcomponentName(ComponentDescriptor childDescriptor)481   ClassName getSubcomponentName(ComponentDescriptor childDescriptor) {
482     checkArgument(
483         componentDescriptor().childComponents().contains(childDescriptor),
484         "%s is not a child component of %s",
485         childDescriptor.typeElement(),
486         componentDescriptor().typeElement());
487     return name.nestedClass(subcomponentNames().get(childDescriptor) + "Impl");
488   }
489 
490   /**
491    * Returns the simple name of the creator implementation class for the given subcomponent creator
492    * {@link Key}.
493    */
getSubcomponentCreatorSimpleName(Key key)494   String getSubcomponentCreatorSimpleName(Key key) {
495     return subcomponentNames().getCreatorName(key);
496   }
497 
subcomponentNames()498   private SubcomponentNames subcomponentNames() {
499     checkState(
500         subcomponentNames.isPresent(),
501         "SubcomponentNames is not available for deserialized component implementations.");
502     return subcomponentNames.get();
503   }
504 
505   /** Returns the child implementation. */
childImplementation(ComponentDescriptor child)506   Optional<ComponentImplementation> childImplementation(ComponentDescriptor child) {
507     return Optional.ofNullable(childImplementations.get(child.typeElement()));
508   }
509 
510   /** Returns {@code true} if {@code type} is accessible from the generated component. */
isTypeAccessible(TypeMirror type)511   boolean isTypeAccessible(TypeMirror type) {
512     return isTypeAccessibleFrom(type, name.packageName());
513   }
514 
515   /** Adds the given super type to the component. */
addSupertype(TypeElement supertype)516   void addSupertype(TypeElement supertype) {
517     TypeSpecs.addSupertype(component, supertype);
518   }
519 
520   /** Adds the given super class to the subcomponent. */
addSuperclass(ClassName className)521   void addSuperclass(ClassName className) {
522     checkState(
523         superclassImplementation.isPresent(),
524         "Setting the superclass for component [%s] when there is no superclass implementation.",
525         name);
526     component.superclass(className);
527   }
528 
529   // TODO(dpb): Consider taking FieldSpec, and returning identical FieldSpec with unique name?
530   /** Adds the given field to the component. */
addField(FieldSpecKind fieldKind, FieldSpec fieldSpec)531   void addField(FieldSpecKind fieldKind, FieldSpec fieldSpec) {
532     fieldSpecsMap.put(fieldKind, fieldSpec);
533   }
534 
535   /** Adds the given fields to the component. */
addFields(FieldSpecKind fieldKind, Iterable<FieldSpec> fieldSpecs)536   void addFields(FieldSpecKind fieldKind, Iterable<FieldSpec> fieldSpecs) {
537     fieldSpecsMap.putAll(fieldKind, fieldSpecs);
538   }
539 
540   // TODO(dpb): Consider taking MethodSpec, and returning identical MethodSpec with unique name?
541   /** Adds the given method to the component. */
addMethod(MethodSpecKind methodKind, MethodSpec methodSpec)542   void addMethod(MethodSpecKind methodKind, MethodSpec methodSpec) {
543     methodSpecsMap.put(methodKind, methodSpec);
544   }
545 
546   /** Adds the given annotation to the component. */
addAnnotation(AnnotationSpec annotation)547   void addAnnotation(AnnotationSpec annotation) {
548     component.addAnnotation(annotation);
549   }
550 
551   /**
552    * Adds the given method to the component. In this case, the method represents an encapsulation of
553    * a modifiable binding between implementations of a subcomponent. This is only relevant for
554    * ahead-of-time subcomponents.
555    */
addModifiableBindingMethod( ModifiableBindingType type, BindingRequest request, TypeMirror returnType, MethodSpec methodSpec, boolean finalized)556   void addModifiableBindingMethod(
557       ModifiableBindingType type,
558       BindingRequest request,
559       TypeMirror returnType,
560       MethodSpec methodSpec,
561       boolean finalized) {
562     addModifiableMethod(
563         MethodSpecKind.MODIFIABLE_BINDING_METHOD, type, request, returnType, methodSpec, finalized);
564   }
565 
566   /**
567    * Adds a component method that is modifiable to the component. In this case, the method
568    * represents an encapsulation of a modifiable binding between implementations of a subcomponent.
569    * This is only relevant for ahead-of-time subcomponents.
570    */
addModifiableComponentMethod( ModifiableBindingType type, BindingRequest request, TypeMirror returnType, MethodSpec methodSpec, boolean finalized)571   void addModifiableComponentMethod(
572       ModifiableBindingType type,
573       BindingRequest request,
574       TypeMirror returnType,
575       MethodSpec methodSpec,
576       boolean finalized) {
577     addModifiableMethod(
578         MethodSpecKind.COMPONENT_METHOD, type, request, returnType, methodSpec, finalized);
579   }
580 
addModifiableMethod( MethodSpecKind methodKind, ModifiableBindingType type, BindingRequest request, TypeMirror returnType, MethodSpec methodSpec, boolean finalized)581   private void addModifiableMethod(
582       MethodSpecKind methodKind,
583       ModifiableBindingType type,
584       BindingRequest request,
585       TypeMirror returnType,
586       MethodSpec methodSpec,
587       boolean finalized) {
588     modifiableBindingMethods.addModifiableMethod(
589         type, request, returnType, methodSpec, finalized);
590     methodSpecsMap.put(methodKind, withModifiableBindingMetadata(methodSpec, type, request));
591   }
592 
593   /** Adds the implementation for the given {@link ModifiableBindingMethod} to the component. */
addImplementedModifiableBindingMethod(ModifiableBindingMethod method)594   void addImplementedModifiableBindingMethod(ModifiableBindingMethod method) {
595     modifiableBindingMethods.addReimplementedMethod(method);
596     methodSpecsMap.put(
597         MethodSpecKind.MODIFIABLE_BINDING_METHOD,
598         withModifiableBindingMetadata(method.methodSpec(), method.type(), method.request()));
599   }
600 
withModifiableBindingMetadata( MethodSpec method, ModifiableBindingType type, BindingRequest request)601   private MethodSpec withModifiableBindingMetadata(
602       MethodSpec method, ModifiableBindingType type, BindingRequest request) {
603     if (!shouldEmitModifiableMetadataAnnotations()) {
604       return method;
605     }
606     AnnotationSpec.Builder metadata =
607         AnnotationSpec.builder(ModifiableBinding.class)
608             .addMember("modifiableBindingType", "$S", type.name())
609             .addMember("bindingRequest", toAnnotationValue(request.toProto()));
610     for (Key multibindingContribution : multibindingContributionsMade.get(request)) {
611       metadata.addMember(
612           "multibindingContributions",
613           toAnnotationValue(KeyFactory.toProto(multibindingContribution)));
614     }
615     return method.toBuilder().addAnnotation(metadata.build()).build();
616   }
617 
618   /** Add's a modifiable module method to this implementation. */
addModifiableModuleMethod(ComponentRequirement module, MethodSpec method)619   void addModifiableModuleMethod(ComponentRequirement module, MethodSpec method) {
620     registerModifiableModuleMethod(module, method.name);
621     methodSpecsMap.put(
622         MethodSpecKind.MODIFIABLE_BINDING_METHOD, withModifiableModuleMetadata(module, method));
623   }
624 
625   /** Registers a modifiable module method with {@code name} for {@code module}. */
registerModifiableModuleMethod(ComponentRequirement module, String name)626   void registerModifiableModuleMethod(ComponentRequirement module, String name) {
627     checkArgument(module.kind().isModule());
628     checkState(modifiableModuleMethods.put(module, name) == null);
629   }
630 
withModifiableModuleMetadata(ComponentRequirement module, MethodSpec method)631   private MethodSpec withModifiableModuleMetadata(ComponentRequirement module, MethodSpec method) {
632     if (!shouldEmitModifiableMetadataAnnotations()) {
633       return method;
634     }
635     return method
636         .toBuilder()
637         .addAnnotation(
638             AnnotationSpec.builder(ModifiableModule.class)
639                 .addMember("value", toAnnotationValue(module.toProto()))
640                 .build())
641         .build();
642   }
643 
644   /**
645    * Returns {@code true} if the generated component should include metadata annotations with
646    * information to deserialize this {@link ComponentImplementation} in future compilations.
647    */
shouldEmitModifiableMetadataAnnotations()648   boolean shouldEmitModifiableMetadataAnnotations() {
649     return isAbstract && compilerOptions.emitModifiableMetadataAnnotations();
650   }
651 
652   /** Adds the given type to the component. */
addType(TypeSpecKind typeKind, TypeSpec typeSpec)653   void addType(TypeSpecKind typeKind, TypeSpec typeSpec) {
654     typeSpecsMap.put(typeKind, typeSpec);
655   }
656 
657   /** Adds the type generated from the given child implementation. */
addChild(ComponentDescriptor child, ComponentImplementation childImplementation)658   void addChild(ComponentDescriptor child, ComponentImplementation childImplementation) {
659     childImplementations.put(child.typeElement(), childImplementation);
660     addType(TypeSpecKind.SUBCOMPONENT, childImplementation.generate().build());
661   }
662 
663   /** Adds a {@link Supplier} for the SwitchingProvider for the component. */
addSwitchingProvider(Supplier<TypeSpec> typeSpecSupplier)664   void addSwitchingProvider(Supplier<TypeSpec> typeSpecSupplier) {
665     switchingProviderSupplier.add(typeSpecSupplier);
666   }
667 
668   /** Adds the given code block to the initialize methods of the component. */
addInitialization(CodeBlock codeBlock)669   void addInitialization(CodeBlock codeBlock) {
670     initializations.add(codeBlock);
671   }
672 
673   /**
674    * Adds the given component requirement as one that should have a parameter in the component's
675    * initialization methods.
676    */
addComponentRequirementParameter(ComponentRequirement requirement)677   void addComponentRequirementParameter(ComponentRequirement requirement) {
678     componentRequirementParameters.add(requirement);
679   }
680 
681   /**
682    * The set of component requirements that have parameters in the component's initialization
683    * methods.
684    */
getComponentRequirementParameters()685   ImmutableSet<ComponentRequirement> getComponentRequirementParameters() {
686     return ImmutableSet.copyOf(componentRequirementParameters);
687   }
688 
689   /** Adds the given code block that initializes a {@link ComponentRequirement}. */
addComponentRequirementInitialization(CodeBlock codeBlock)690   void addComponentRequirementInitialization(CodeBlock codeBlock) {
691     componentRequirementInitializations.add(codeBlock);
692   }
693 
694   /**
695    * Marks the given key of a producer as one that should have a cancellation statement in the
696    * cancellation listener method of the component.
697    */
addCancellableProducerKey(Key key)698   void addCancellableProducerKey(Key key) {
699     cancellableProducerKeys.add(key);
700   }
701 
702   /** Returns a new, unique field name for the component based on the given name. */
getUniqueFieldName(String name)703   String getUniqueFieldName(String name) {
704     return componentFieldNames.getUniqueName(name);
705   }
706 
707   /** Returns a new, unique method name for the component based on the given name. */
getUniqueMethodName(String name)708   String getUniqueMethodName(String name) {
709     return componentMethodNames.getUniqueName(name);
710   }
711 
712   /** Returns a new, unique method name for a getter method for the given request. */
getUniqueMethodName(BindingRequest request)713   String getUniqueMethodName(BindingRequest request) {
714     return uniqueMethodName(request, KeyVariableNamer.name(request.key()));
715   }
716 
uniqueMethodName(BindingRequest request, String bindingName)717   private String uniqueMethodName(BindingRequest request, String bindingName) {
718     String baseMethodName =
719         "get"
720             + LOWER_CAMEL.to(UPPER_CAMEL, bindingName)
721             + (request.isRequestKind(RequestKind.INSTANCE)
722                 ? ""
723                 : UPPER_UNDERSCORE.to(UPPER_CAMEL, request.kindName()));
724     return getUniqueMethodName(baseMethodName);
725   }
726 
727   /** Gets the parameter name to use for the given requirement for this component. */
getParameterName(ComponentRequirement requirement)728   String getParameterName(ComponentRequirement requirement) {
729     return getParameterName(requirement, requirement.variableName());
730   }
731 
732   /**
733    * Gets the parameter name to use for the given requirement for this component, starting with the
734    * given base name if no parameter name has already been selected for the requirement.
735    */
getParameterName(ComponentRequirement requirement, String baseName)736   String getParameterName(ComponentRequirement requirement, String baseName) {
737     return componentRequirementParameterNames.computeIfAbsent(
738         requirement, r -> getUniqueFieldName(baseName));
739   }
740 
741   /** Claims a new method name for the component. Does nothing if method name already exists. */
claimMethodName(CharSequence name)742   void claimMethodName(CharSequence name) {
743     componentMethodNames.claim(name);
744   }
745 
746   /** Returns the list of {@link CodeBlock}s that need to go in the initialize method. */
getInitializations()747   ImmutableList<CodeBlock> getInitializations() {
748     return ImmutableList.copyOf(initializations);
749   }
750 
751   /**
752    * Returns a list of {@link CodeBlock}s for initializing {@link ComponentRequirement}s.
753    *
754    * <p>These initializations are kept separate from {@link #getInitializations()} because they must
755    * be executed before the initializations of any framework instance initializations in a
756    * superclass implementation that may depend on the instances. We cannot use the same strategy
757    * that we use for framework instances (i.e. wrap in a {@link dagger.internal.DelegateFactory} or
758    * {@link dagger.producers.internal.DelegateProducer} since the types of these initialized fields
759    * have no interface type that we can write a proxy for.
760    */
getComponentRequirementInitializations()761   ImmutableList<CodeBlock> getComponentRequirementInitializations() {
762     return ImmutableList.copyOf(componentRequirementInitializations);
763   }
764 
765   /**
766    * Returns whether or not this component has any {@linkplain #getInitializations() initilizations}
767    * or {@linkplain #getComponentRequirementInitializations() component requirement
768    * initializations}.
769    */
hasInitializations()770   boolean hasInitializations() {
771     return !initializations.isEmpty() || !componentRequirementInitializations.isEmpty();
772   }
773 
774   /**
775    * Returns the list of producer {@link Key}s that need cancellation statements in the cancellation
776    * listener method.
777    */
getCancellableProducerKeys()778   ImmutableList<Key> getCancellableProducerKeys() {
779     Optional<ComponentImplementation> currentSuperImplementation = superclassImplementation;
780     Set<Key> cancelledKeysFromSuperclass = new HashSet<>();
781     while (currentSuperImplementation.isPresent()) {
782       cancelledKeysFromSuperclass.addAll(currentSuperImplementation.get().cancellableProducerKeys);
783       currentSuperImplementation = currentSuperImplementation.get().superclassImplementation;
784     }
785     return Sets.difference(cancellableProducerKeys, cancelledKeysFromSuperclass)
786         .immutableCopy()
787         .asList();
788   }
789 
790   /**
791    * Returns the {@link ModifiableBindingMethod}s for this subcomponent implementation and its
792    * superclasses.
793    */
getModifiableBindingMethods()794   ImmutableMap<BindingRequest, ModifiableBindingMethod> getModifiableBindingMethods() {
795     Map<BindingRequest, ModifiableBindingMethod> modifiableBindingMethodsBuilder =
796         new LinkedHashMap<>();
797     if (superclassImplementation.isPresent()) {
798       modifiableBindingMethodsBuilder.putAll(
799           Maps.filterValues(
800               superclassImplementation.get().getModifiableBindingMethods(),
801               // filters the modifiable methods of a superclass that are finalized in this component
802               method -> !modifiableBindingMethods.finalized(method)));
803     }
804     // replace superclass modifiable binding methods with any that are defined in this component
805     // implementation
806     modifiableBindingMethodsBuilder.putAll(modifiableBindingMethods.getNonFinalizedMethods());
807     return ImmutableMap.copyOf(modifiableBindingMethodsBuilder);
808   }
809 
810   /**
811    * Returns the names of every modifiable method of this implementation and any superclass
812    * implementations.
813    */
getAllModifiableMethodNames()814   ImmutableSet<String> getAllModifiableMethodNames() {
815     ImmutableSet.Builder<String> names = ImmutableSet.builder();
816     modifiableBindingMethods.allMethods().forEach(method -> names.add(method.methodSpec().name));
817     names.addAll(modifiableModuleMethods.values());
818     superclassImplementation.ifPresent(
819         superclass -> names.addAll(superclass.getAllModifiableMethodNames()));
820     return names.build();
821   }
822 
823   /**
824    * Returns the {@link ModifiableBindingMethod} for this subcomponent for the given binding, if it
825    * exists.
826    */
getModifiableBindingMethod(BindingRequest request)827   Optional<ModifiableBindingMethod> getModifiableBindingMethod(BindingRequest request) {
828     Optional<ModifiableBindingMethod> method = modifiableBindingMethods.getMethod(request);
829     if (!method.isPresent() && superclassImplementation.isPresent()) {
830       return superclassImplementation.get().getModifiableBindingMethod(request);
831     }
832     return method;
833   }
834 
835   /**
836    * Returns the {@link ModifiableBindingMethod} of a supertype for this method's {@code request},
837    * if one exists.
838    */
supertypeModifiableBindingMethod(BindingRequest request)839   Optional<ModifiableBindingMethod> supertypeModifiableBindingMethod(BindingRequest request) {
840     return superclassImplementation()
841         .flatMap(superImplementation -> superImplementation.getModifiableBindingMethod(request));
842   }
843 
844   /**
845    * Returns the names of modifiable module methods for this implementation and all inherited
846    * implementations, keyed by the corresponding module's {@link ComponentRequirement}.
847    */
getAllModifiableModuleMethods()848   ImmutableMap<ComponentRequirement, String> getAllModifiableModuleMethods() {
849     ImmutableMap.Builder<ComponentRequirement, String> methods = ImmutableMap.builder();
850     methods.putAll(modifiableModuleMethods);
851     superclassImplementation.ifPresent(
852         superclass -> methods.putAll(superclass.getAllModifiableModuleMethods()));
853     return methods.build();
854   }
855 
856   /**
857    * Returns the name of the modifiable module method for {@code module} that is inherited in this
858    * implementation, or empty if none has been defined.
859    */
supertypeModifiableModuleMethodName(ComponentRequirement module)860   Optional<String> supertypeModifiableModuleMethodName(ComponentRequirement module) {
861     checkArgument(module.kind().isModule());
862     if (!superclassImplementation.isPresent()) {
863       return Optional.empty();
864     }
865     String methodName = superclassImplementation.get().modifiableModuleMethods.get(module);
866     if (methodName == null) {
867       return superclassImplementation.get().supertypeModifiableModuleMethodName(module);
868     }
869     return Optional.of(methodName);
870   }
871 
872   /** Generates the component and returns the resulting {@link TypeSpec.Builder}. */
generate()873   TypeSpec.Builder generate() {
874     fieldSpecsMap.asMap().values().forEach(component::addFields);
875     methodSpecsMap.asMap().values().forEach(component::addMethods);
876     typeSpecsMap.asMap().values().forEach(component::addTypes);
877     switchingProviderSupplier.stream().map(Supplier::get).forEach(component::addType);
878     return component;
879   }
880 
881   /**
882    * Registers a {@ProvisionBinding} representing a multibinding as having been implemented in this
883    * component. Multibindings are modifiable across subcomponent implementations and this allows us
884    * to know whether a contribution has been made by a superclass implementation. This is only
885    * relevant for ahead-of-time subcomponents.
886    */
registerImplementedMultibinding( ContributionBinding multibinding, BindingRequest bindingRequest)887   void registerImplementedMultibinding(
888       ContributionBinding multibinding, BindingRequest bindingRequest) {
889     checkArgument(multibinding.isSyntheticMultibinding());
890     // We register a multibinding as implemented each time we request the multibinding expression,
891     // so only modify the set of contributions once.
892     if (!multibindingContributionsMade.containsKey(bindingRequest)) {
893       registerImplementedMultibindingKeys(
894           bindingRequest,
895           multibinding.dependencies().stream().map(DependencyRequest::key).collect(toList()));
896     }
897   }
898 
899   /**
900    * Registers the multibinding contributions represented by {@code keys} as having been implemented
901    * in this component. Multibindings are modifiable across subcomponent implementations and this
902    * allows us to know whether a contribution has been made by a superclass implementation. This is
903    * only relevant for ahead-of-time subcomponents.
904    */
registerImplementedMultibindingKeys(BindingRequest bindingRequest, Iterable<Key> keys)905   void registerImplementedMultibindingKeys(BindingRequest bindingRequest, Iterable<Key> keys) {
906     multibindingContributionsMade.putAll(bindingRequest, keys);
907   }
908 
909   /**
910    * Returns the set of multibinding contributions associated with all superclass implementations of
911    * a multibinding.
912    */
superclassContributionsMade(BindingRequest bindingRequest)913   ImmutableSet<Key> superclassContributionsMade(BindingRequest bindingRequest) {
914     return superclassImplementation
915         .map(s -> s.getAllMultibindingContributions(bindingRequest))
916         .orElse(ImmutableSet.of());
917   }
918 
919   /**
920    * Returns the set of multibinding contributions associated with all implementations of a
921    * multibinding.
922    */
getAllMultibindingContributions(BindingRequest bindingRequest)923   private ImmutableSet<Key> getAllMultibindingContributions(BindingRequest bindingRequest) {
924     return ImmutableSet.copyOf(
925         Sets.union(
926             multibindingContributionsMade.get(bindingRequest),
927             superclassContributionsMade(bindingRequest)));
928   }
929 }
930