• 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;
18 
19 import static com.google.auto.common.MoreElements.isAnnotationPresent;
20 import static com.google.auto.common.MoreTypes.asTypeElement;
21 import static com.google.common.base.Verify.verify;
22 import static com.google.common.collect.Iterables.getOnlyElement;
23 import static dagger.internal.codegen.ComponentCreatorAnnotation.getCreatorAnnotations;
24 import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
25 import static dagger.internal.codegen.ModuleAnnotation.moduleAnnotation;
26 
27 import com.google.auto.common.MoreTypes;
28 import com.google.auto.value.AutoValue;
29 import com.google.auto.value.extension.memoized.Memoized;
30 import com.google.common.collect.ImmutableMap;
31 import com.google.common.collect.ImmutableSet;
32 import com.google.common.collect.ImmutableSetMultimap;
33 import com.google.common.collect.Maps;
34 import com.google.common.collect.Multimap;
35 import dagger.BindsInstance;
36 import dagger.internal.codegen.langmodel.DaggerElements;
37 import dagger.internal.codegen.langmodel.DaggerTypes;
38 import dagger.model.DependencyRequest;
39 import java.util.List;
40 import javax.lang.model.element.Element;
41 import javax.lang.model.element.ExecutableElement;
42 import javax.lang.model.element.TypeElement;
43 import javax.lang.model.element.VariableElement;
44 import javax.lang.model.type.DeclaredType;
45 import javax.lang.model.type.ExecutableType;
46 import javax.lang.model.type.TypeMirror;
47 
48 /**
49  * A descriptor for a component <i>creator</i> type: that is, a type annotated with
50  * {@code @Component.Builder} (or one of the corresponding production or subcomponent versions).
51  */
52 @AutoValue
53 abstract class ComponentCreatorDescriptor {
54 
55   /** Returns the annotation marking this creator. */
annotation()56   abstract ComponentCreatorAnnotation annotation();
57 
58   /** The kind of this creator. */
kind()59   final ComponentCreatorKind kind() {
60     return annotation().creatorKind();
61   }
62 
63   /** The annotated creator type. */
typeElement()64   abstract TypeElement typeElement();
65 
66   /** The method that creates and returns a component instance. */
factoryMethod()67   abstract ExecutableElement factoryMethod();
68 
69   /**
70    * Multimap of component requirements to setter methods that set that requirement.
71    *
72    * <p>In a valid creator, there will be exactly one element per component requirement, so this
73    * method should only be called when validating the descriptor.
74    */
unvalidatedSetterMethods()75   abstract ImmutableSetMultimap<ComponentRequirement, ExecutableElement> unvalidatedSetterMethods();
76 
77   /**
78    * Multimap of component requirements to factory method parameters that set that requirement.
79    *
80    * <p>In a valid creator, there will be exactly one element per component requirement, so this
81    * method should only be called when validating the descriptor.
82    */
83   abstract ImmutableSetMultimap<ComponentRequirement, VariableElement>
unvalidatedFactoryParameters()84       unvalidatedFactoryParameters();
85 
86   /**
87    * Multimap of component requirements to elements (methods or parameters) that set that
88    * requirement.
89    *
90    * <p>In a valid creator, there will be exactly one element per component requirement, so this
91    * method should only be called when validating the descriptor.
92    */
unvalidatedRequirementElements()93   final ImmutableSetMultimap<ComponentRequirement, Element> unvalidatedRequirementElements() {
94     // ComponentCreatorValidator ensures that there are either setter methods or factory method
95     // parameters, but not both, so we can cheat a little here since we know that only one of
96     // the two multimaps will be non-empty.
97     return ImmutableSetMultimap.copyOf( // no actual copy
98         unvalidatedSetterMethods().isEmpty()
99             ? unvalidatedFactoryParameters()
100             : unvalidatedSetterMethods());
101   }
102 
103   /**
104    * Map of component requirements to elements (setter methods or factory method parameters) that
105    * set them.
106    */
107   @Memoized
requirementElements()108   ImmutableMap<ComponentRequirement, Element> requirementElements() {
109     return flatten(unvalidatedRequirementElements());
110   }
111 
112   /** Map of component requirements to setter methods for those requirements. */
113   @Memoized
setterMethods()114   ImmutableMap<ComponentRequirement, ExecutableElement> setterMethods() {
115     return flatten(unvalidatedSetterMethods());
116   }
117 
118   /** Map of component requirements to factory method parameters for those requirements. */
119   @Memoized
factoryParameters()120   ImmutableMap<ComponentRequirement, VariableElement> factoryParameters() {
121     return flatten(unvalidatedFactoryParameters());
122   }
123 
flatten(Multimap<K, V> multimap)124   private static <K, V> ImmutableMap<K, V> flatten(Multimap<K, V> multimap) {
125     return ImmutableMap.copyOf(
126         Maps.transformValues(multimap.asMap(), values -> getOnlyElement(values)));
127   }
128 
129   /** Returns the set of component requirements this creator allows the user to set. */
userSettableRequirements()130   final ImmutableSet<ComponentRequirement> userSettableRequirements() {
131     // Note: they should have been validated at the point this is used, so this set is valid.
132     return unvalidatedRequirementElements().keySet();
133   }
134 
135   /** Returns the set of requirements for modules and component dependencies for this creator. */
moduleAndDependencyRequirements()136   final ImmutableSet<ComponentRequirement> moduleAndDependencyRequirements() {
137     return userSettableRequirements().stream()
138         .filter(requirement -> !requirement.isBoundInstance())
139         .collect(toImmutableSet());
140   }
141 
142   /** Returns the set of bound instance requirements for this creator. */
boundInstanceRequirements()143   final ImmutableSet<ComponentRequirement> boundInstanceRequirements() {
144     return userSettableRequirements().stream()
145         .filter(ComponentRequirement::isBoundInstance)
146         .collect(toImmutableSet());
147   }
148 
149   /** Returns the element in this creator that sets the given {@code requirement}. */
elementForRequirement(ComponentRequirement requirement)150   final Element elementForRequirement(ComponentRequirement requirement) {
151     return requirementElements().get(requirement);
152   }
153 
154   /** Creates a new {@link ComponentCreatorDescriptor} for the given creator {@code type}. */
create( DeclaredType type, DaggerElements elements, DaggerTypes types, DependencyRequestFactory dependencyRequestFactory)155   static ComponentCreatorDescriptor create(
156       DeclaredType type,
157       DaggerElements elements,
158       DaggerTypes types,
159       DependencyRequestFactory dependencyRequestFactory) {
160     TypeElement typeElement = asTypeElement(type);
161     TypeMirror componentType = typeElement.getEnclosingElement().asType();
162 
163     ImmutableSetMultimap.Builder<ComponentRequirement, ExecutableElement> setterMethods =
164         ImmutableSetMultimap.builder();
165 
166     ExecutableElement factoryMethod = null;
167     for (ExecutableElement method : elements.getUnimplementedMethods(typeElement)) {
168       ExecutableType resolvedMethodType = MoreTypes.asExecutable(types.asMemberOf(type, method));
169 
170       if (types.isSubtype(componentType, resolvedMethodType.getReturnType())) {
171         factoryMethod = method;
172       } else {
173         VariableElement parameter = getOnlyElement(method.getParameters());
174         TypeMirror parameterType = getOnlyElement(resolvedMethodType.getParameterTypes());
175         setterMethods.put(
176             requirement(method, parameter, parameterType, dependencyRequestFactory, method),
177             method);
178       }
179     }
180     verify(factoryMethod != null); // validation should have ensured this.
181 
182     ImmutableSetMultimap.Builder<ComponentRequirement, VariableElement> factoryParameters =
183         ImmutableSetMultimap.builder();
184 
185     ExecutableType resolvedFactoryMethodType =
186         MoreTypes.asExecutable(types.asMemberOf(type, factoryMethod));
187     List<? extends VariableElement> parameters = factoryMethod.getParameters();
188     List<? extends TypeMirror> parameterTypes = resolvedFactoryMethodType.getParameterTypes();
189     for (int i = 0; i < parameters.size(); i++) {
190       VariableElement parameter = parameters.get(i);
191       TypeMirror parameterType = parameterTypes.get(i);
192       factoryParameters.put(
193           requirement(factoryMethod, parameter, parameterType, dependencyRequestFactory, parameter),
194           parameter);
195     }
196 
197     // Validation should have ensured exactly one creator annotation is present on the type.
198     ComponentCreatorAnnotation annotation = getOnlyElement(getCreatorAnnotations(typeElement));
199     return new AutoValue_ComponentCreatorDescriptor(
200         annotation, typeElement, factoryMethod, setterMethods.build(), factoryParameters.build());
201   }
202 
requirement( ExecutableElement method, VariableElement parameter, TypeMirror type, DependencyRequestFactory dependencyRequestFactory, Element elementForVariableName)203   private static ComponentRequirement requirement(
204       ExecutableElement method,
205       VariableElement parameter,
206       TypeMirror type,
207       DependencyRequestFactory dependencyRequestFactory,
208       Element elementForVariableName) {
209     if (isAnnotationPresent(method, BindsInstance.class)
210         || isAnnotationPresent(parameter, BindsInstance.class)) {
211       DependencyRequest request =
212           dependencyRequestFactory.forRequiredResolvedVariable(parameter, type);
213       String variableName = elementForVariableName.getSimpleName().toString();
214       return ComponentRequirement.forBoundInstance(
215           request.key(), request.isNullable(), variableName);
216     }
217 
218     return moduleAnnotation(asTypeElement(type)).isPresent()
219         ? ComponentRequirement.forModule(type)
220         : ComponentRequirement.forDependency(type);
221   }
222 }
223