• 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.common.base.Verify.verify;
20 import static com.google.common.collect.Iterables.getOnlyElement;
21 import static dagger.internal.codegen.base.ComponentCreatorAnnotation.getCreatorAnnotations;
22 import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotations;
23 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
24 import static dagger.internal.codegen.xprocessing.XTypeElements.getAllUnimplementedMethods;
25 import static dagger.internal.codegen.xprocessing.XTypes.isSubtype;
26 
27 import androidx.room.compiler.processing.XElement;
28 import androidx.room.compiler.processing.XExecutableParameterElement;
29 import androidx.room.compiler.processing.XMethodElement;
30 import androidx.room.compiler.processing.XMethodType;
31 import androidx.room.compiler.processing.XType;
32 import androidx.room.compiler.processing.XTypeElement;
33 import com.google.auto.value.AutoValue;
34 import com.google.auto.value.extension.memoized.Memoized;
35 import com.google.common.collect.ImmutableMap;
36 import com.google.common.collect.ImmutableSet;
37 import com.google.common.collect.ImmutableSetMultimap;
38 import com.google.common.collect.Maps;
39 import com.google.common.collect.Multimap;
40 import dagger.internal.codegen.base.ComponentCreatorAnnotation;
41 import dagger.internal.codegen.base.ComponentCreatorKind;
42 import dagger.internal.codegen.javapoet.TypeNames;
43 import dagger.internal.codegen.model.DependencyRequest;
44 import dagger.internal.codegen.xprocessing.XElements;
45 import java.util.List;
46 
47 /**
48  * A descriptor for a component <i>creator</i> type: that is, a type annotated with
49  * {@code @Component.Builder} (or one of the corresponding production or subcomponent versions).
50  */
51 @AutoValue
52 public abstract class ComponentCreatorDescriptor {
53 
54   /** Returns the annotation marking this creator. */
annotation()55   public abstract ComponentCreatorAnnotation annotation();
56 
57   /** The kind of this creator. */
kind()58   public final ComponentCreatorKind kind() {
59     return annotation().creatorKind();
60   }
61 
62   /** The annotated creator type. */
typeElement()63   public abstract XTypeElement typeElement();
64 
65   /** The method that creates and returns a component instance. */
factoryMethod()66   public abstract XMethodElement factoryMethod();
67 
68   /**
69    * Multimap of component requirements to setter methods that set that requirement.
70    *
71    * <p>In a valid creator, there will be exactly one element per component requirement, so this
72    * method should only be called when validating the descriptor.
73    */
unvalidatedSetterMethods()74   abstract ImmutableSetMultimap<ComponentRequirement, XMethodElement> unvalidatedSetterMethods();
75 
76   /**
77    * Multimap of component requirements to factory method parameters that set that requirement.
78    *
79    * <p>In a valid creator, there will be exactly one element per component requirement, so this
80    * method should only be called when validating the descriptor.
81    */
82   abstract ImmutableSetMultimap<ComponentRequirement, XExecutableParameterElement>
unvalidatedFactoryParameters()83       unvalidatedFactoryParameters();
84 
85   /**
86    * Multimap of component requirements to elements (methods or parameters) that set that
87    * requirement.
88    *
89    * <p>In a valid creator, there will be exactly one element per component requirement, so this
90    * method should only be called when validating the descriptor.
91    */
92   public final ImmutableSetMultimap<ComponentRequirement, XElement>
unvalidatedRequirementElements()93       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, XElement> requirementElements() {
109     return flatten(unvalidatedRequirementElements());
110   }
111 
112   /** Map of component requirements to setter methods for those requirements. */
113   @Memoized
setterMethods()114   public ImmutableMap<ComponentRequirement, XMethodElement> setterMethods() {
115     return flatten(unvalidatedSetterMethods());
116   }
117 
118   /** Map of component requirements to factory method parameters for those requirements. */
119   @Memoized
factoryParameters()120   public ImmutableMap<ComponentRequirement, XExecutableParameterElement> 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   public 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   public 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 XElement elementForRequirement(ComponentRequirement requirement) {
151     return requirementElements().get(requirement);
152   }
153 
154   /** Creates a new {@link ComponentCreatorDescriptor} for the given creator {@code type}. */
create( XTypeElement creator, DependencyRequestFactory dependencyRequestFactory)155   public static ComponentCreatorDescriptor create(
156       XTypeElement creator, DependencyRequestFactory dependencyRequestFactory) {
157     XType componentType = creator.getEnclosingTypeElement().getType();
158 
159     ImmutableSetMultimap.Builder<ComponentRequirement, XMethodElement> setterMethods =
160         ImmutableSetMultimap.builder();
161     XMethodElement factoryMethod = null;
162     for (XMethodElement method : getAllUnimplementedMethods(creator)) {
163       XMethodType resolvedMethodType = method.asMemberOf(creator.getType());
164       if (isSubtype(componentType, resolvedMethodType.getReturnType())) {
165         verify(
166             factoryMethod == null,
167             "Expected a single factory method for %s but found multiple: [%s, %s]",
168             XElements.toStableString(creator),
169             XElements.toStableString(factoryMethod),
170             XElements.toStableString(method));
171         factoryMethod = method;
172       } else {
173         XExecutableParameterElement parameter = getOnlyElement(method.getParameters());
174         XType parameterType = getOnlyElement(resolvedMethodType.getParameterTypes());
175         setterMethods.put(
176             requirement(method, parameter, parameterType, dependencyRequestFactory, method),
177             method);
178       }
179     }
180     verify(
181         factoryMethod != null,
182         "Expected a single factory method for %s but found none.",
183         XElements.toStableString(creator));
184 
185     ImmutableSetMultimap.Builder<ComponentRequirement, XExecutableParameterElement>
186         factoryParameters = ImmutableSetMultimap.builder();
187 
188     XMethodType resolvedFactoryMethodType = factoryMethod.asMemberOf(creator.getType());
189     List<XExecutableParameterElement> parameters = factoryMethod.getParameters();
190     List<XType> parameterTypes = resolvedFactoryMethodType.getParameterTypes();
191     for (int i = 0; i < parameters.size(); i++) {
192       XExecutableParameterElement parameter = parameters.get(i);
193       XType parameterType = parameterTypes.get(i);
194       factoryParameters.put(
195           requirement(
196               factoryMethod,
197               parameter,
198               parameterType,
199               dependencyRequestFactory,
200               parameter),
201           parameter);
202     }
203     // Validation should have ensured exactly one creator annotation is present on the type.
204     ComponentCreatorAnnotation annotation = getOnlyElement(getCreatorAnnotations(creator));
205     return new AutoValue_ComponentCreatorDescriptor(
206         annotation, creator, factoryMethod, setterMethods.build(), factoryParameters.build());
207   }
208 
requirement( XMethodElement method, XExecutableParameterElement parameter, XType parameterType, DependencyRequestFactory dependencyRequestFactory, XElement elementForVariableName)209   private static ComponentRequirement requirement(
210       XMethodElement method,
211       XExecutableParameterElement parameter,
212       XType parameterType,
213       DependencyRequestFactory dependencyRequestFactory,
214       XElement elementForVariableName) {
215     if (method.hasAnnotation(TypeNames.BINDS_INSTANCE)
216         || parameter.hasAnnotation(TypeNames.BINDS_INSTANCE)) {
217       DependencyRequest request =
218           dependencyRequestFactory.forRequiredResolvedVariable(parameter, parameterType);
219       return ComponentRequirement.forBoundInstance(
220           request.key(), request.isNullable(), elementForVariableName);
221     }
222 
223     return parameterType.getTypeElement().hasAnyAnnotation(moduleAnnotations())
224         ? ComponentRequirement.forModule(parameterType)
225         : ComponentRequirement.forDependency(parameterType);
226   }
227 }
228