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