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