• 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.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 import static com.google.common.base.Preconditions.checkState;
22 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
23 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
24 import static dagger.internal.codegen.langmodel.DaggerTypes.isFutureType;
25 import static javax.lang.model.element.Modifier.ABSTRACT;
26 import static javax.lang.model.type.TypeKind.VOID;
27 
28 import com.google.auto.value.AutoValue;
29 import com.google.auto.value.extension.memoized.Memoized;
30 import com.google.common.base.Supplier;
31 import com.google.common.base.Suppliers;
32 import com.google.common.collect.ImmutableBiMap;
33 import com.google.common.collect.ImmutableMap;
34 import com.google.common.collect.ImmutableSet;
35 import com.google.common.collect.Maps;
36 import com.google.errorprone.annotations.CanIgnoreReturnValue;
37 import com.google.errorprone.annotations.CheckReturnValue;
38 import dagger.Component;
39 import dagger.Module;
40 import dagger.Subcomponent;
41 import dagger.internal.codegen.base.ComponentAnnotation;
42 import dagger.internal.codegen.langmodel.DaggerElements;
43 import dagger.internal.codegen.langmodel.DaggerTypes;
44 import dagger.model.DependencyRequest;
45 import dagger.model.Scope;
46 import dagger.producers.CancellationPolicy;
47 import dagger.producers.ProductionComponent;
48 import java.util.HashMap;
49 import java.util.Map;
50 import java.util.Objects;
51 import java.util.Optional;
52 import java.util.stream.Stream;
53 import javax.lang.model.element.Element;
54 import javax.lang.model.element.ExecutableElement;
55 import javax.lang.model.element.TypeElement;
56 import javax.lang.model.type.TypeMirror;
57 
58 /**
59  * A component declaration.
60  *
61  * <p>Represents one type annotated with {@code @Component}, {@code Subcomponent},
62  * {@code @ProductionComponent}, or {@code @ProductionSubcomponent}.
63  *
64  * <p>When validating bindings installed in modules, a {@link ComponentDescriptor} can also
65  * represent a synthetic component for the module, where there is an entry point for each binding in
66  * the module.
67  */
68 @AutoValue
69 public abstract class ComponentDescriptor {
70   /** The annotation that specifies that {@link #typeElement()} is a component. */
annotation()71   public abstract ComponentAnnotation annotation();
72 
73   /** Returns {@code true} if this is a subcomponent. */
isSubcomponent()74   public final boolean isSubcomponent() {
75     return annotation().isSubcomponent();
76   }
77 
78   /**
79    * Returns {@code true} if this is a production component or subcomponent, or a
80    * {@code @ProducerModule} when doing module binding validation.
81    */
isProduction()82   public final boolean isProduction() {
83     return annotation().isProduction();
84   }
85 
86   /**
87    * Returns {@code true} if this is a real component, and not a fictional one used to validate
88    * module bindings.
89    */
isRealComponent()90   public final boolean isRealComponent() {
91     return annotation().isRealComponent();
92   }
93 
94   /**
95    * The element that defines the component. This is the element to which the {@link #annotation()}
96    * was applied.
97    */
typeElement()98   public abstract TypeElement typeElement();
99 
100   /**
101    * The set of component dependencies listed in {@link Component#dependencies} or {@link
102    * ProductionComponent#dependencies()}.
103    */
dependencies()104   public abstract ImmutableSet<ComponentRequirement> dependencies();
105 
106   /** The non-abstract {@link #modules()} and the {@link #dependencies()}. */
dependenciesAndConcreteModules()107   public final ImmutableSet<ComponentRequirement> dependenciesAndConcreteModules() {
108     return Stream.concat(
109             moduleTypes().stream()
110                 .filter(dep -> !dep.getModifiers().contains(ABSTRACT))
111                 .map(module -> ComponentRequirement.forModule(module.asType())),
112             dependencies().stream())
113         .collect(toImmutableSet());
114   }
115 
116   /**
117    * The {@link ModuleDescriptor modules} declared in {@link Component#modules()} and reachable by
118    * traversing {@link Module#includes()}.
119    */
modules()120   public abstract ImmutableSet<ModuleDescriptor> modules();
121 
122   /** The types of the {@link #modules()}. */
moduleTypes()123   public final ImmutableSet<TypeElement> moduleTypes() {
124     return modules().stream().map(ModuleDescriptor::moduleElement).collect(toImmutableSet());
125   }
126 
127   /**
128    * The types for which the component will need instances if all of its bindings are used. For the
129    * types the component will need in a given binding graph, use {@link
130    * BindingGraph#componentRequirements()}.
131    *
132    * <ul>
133    *   <li>{@linkplain #modules()} modules} with concrete instance bindings
134    *   <li>Bound instances
135    *   <li>{@linkplain #dependencies() dependencies}
136    * </ul>
137    */
138   @Memoized
requirements()139   ImmutableSet<ComponentRequirement> requirements() {
140     ImmutableSet.Builder<ComponentRequirement> requirements = ImmutableSet.builder();
141     modules().stream()
142         .filter(
143             module ->
144                 module.bindings().stream().anyMatch(ContributionBinding::requiresModuleInstance))
145         .map(module -> ComponentRequirement.forModule(module.moduleElement().asType()))
146         .forEach(requirements::add);
147     requirements.addAll(dependencies());
148     requirements.addAll(
149         creatorDescriptor()
150             .map(ComponentCreatorDescriptor::boundInstanceRequirements)
151             .orElse(ImmutableSet.of()));
152     return requirements.build();
153   }
154 
155   /**
156    * This component's {@linkplain #dependencies() dependencies} keyed by each provision or
157    * production method defined by that dependency. Note that the dependencies' types are not simply
158    * the enclosing type of the method; a method may be declared by a supertype of the actual
159    * dependency.
160    */
161   public abstract ImmutableMap<ExecutableElement, ComponentRequirement>
dependenciesByDependencyMethod()162       dependenciesByDependencyMethod();
163 
164   /** The {@linkplain #dependencies() component dependency} that defines a method. */
getDependencyThatDefinesMethod(Element method)165   public final ComponentRequirement getDependencyThatDefinesMethod(Element method) {
166     checkArgument(
167         method instanceof ExecutableElement, "method must be an executable element: %s", method);
168     return checkNotNull(
169         dependenciesByDependencyMethod().get(method), "no dependency implements %s", method);
170   }
171 
172   /** The scopes of the component. */
scopes()173   public abstract ImmutableSet<Scope> scopes();
174 
175   /**
176    * All {@link Subcomponent}s which are direct children of this component. This includes
177    * subcomponents installed from {@link Module#subcomponents()} as well as subcomponent {@linkplain
178    * #childComponentsDeclaredByFactoryMethods() factory methods} and {@linkplain
179    * #childComponentsDeclaredByBuilderEntryPoints() builder methods}.
180    */
childComponents()181   public final ImmutableSet<ComponentDescriptor> childComponents() {
182     return ImmutableSet.<ComponentDescriptor>builder()
183         .addAll(childComponentsDeclaredByFactoryMethods().values())
184         .addAll(childComponentsDeclaredByBuilderEntryPoints().values())
185         .addAll(childComponentsDeclaredByModules())
186         .build();
187   }
188 
189   /**
190    * All {@linkplain Subcomponent direct child} components that are declared by a {@linkplain
191    * Module#subcomponents() module's subcomponents}.
192    */
childComponentsDeclaredByModules()193   abstract ImmutableSet<ComponentDescriptor> childComponentsDeclaredByModules();
194 
195   /**
196    * All {@linkplain Subcomponent direct child} components that are declared by a subcomponent
197    * factory method.
198    */
199   public abstract ImmutableBiMap<ComponentMethodDescriptor, ComponentDescriptor>
childComponentsDeclaredByFactoryMethods()200       childComponentsDeclaredByFactoryMethods();
201 
202   /** Returns a map of {@link #childComponents()} indexed by {@link #typeElement()}. */
203   @Memoized
childComponentsByElement()204   public ImmutableMap<TypeElement, ComponentDescriptor> childComponentsByElement() {
205     return Maps.uniqueIndex(childComponents(), ComponentDescriptor::typeElement);
206   }
207 
208   /** Returns the factory method that declares a child component. */
getFactoryMethodForChildComponent( ComponentDescriptor childComponent)209   final Optional<ComponentMethodDescriptor> getFactoryMethodForChildComponent(
210       ComponentDescriptor childComponent) {
211     return Optional.ofNullable(
212         childComponentsDeclaredByFactoryMethods().inverse().get(childComponent));
213   }
214 
215   /**
216    * All {@linkplain Subcomponent direct child} components that are declared by a subcomponent
217    * builder method.
218    */
219   abstract ImmutableBiMap<ComponentMethodDescriptor, ComponentDescriptor>
childComponentsDeclaredByBuilderEntryPoints()220       childComponentsDeclaredByBuilderEntryPoints();
221 
222   private final Supplier<ImmutableMap<TypeElement, ComponentDescriptor>>
223       childComponentsByBuilderType =
224           Suppliers.memoize(
225               () ->
226                   childComponents().stream()
227                       .filter(child -> child.creatorDescriptor().isPresent())
228                       .collect(
229                           toImmutableMap(
230                               child -> child.creatorDescriptor().get().typeElement(),
231                               child -> child)));
232 
233   /** Returns the child component with the given builder type. */
getChildComponentWithBuilderType(TypeElement builderType)234   final ComponentDescriptor getChildComponentWithBuilderType(TypeElement builderType) {
235     return checkNotNull(
236         childComponentsByBuilderType.get().get(builderType),
237         "no child component found for builder type %s",
238         builderType.getQualifiedName());
239   }
240 
componentMethods()241   public abstract ImmutableSet<ComponentMethodDescriptor> componentMethods();
242 
243   /** Returns the first component method associated with this binding request, if one exists. */
firstMatchingComponentMethod(BindingRequest request)244   public Optional<ComponentMethodDescriptor> firstMatchingComponentMethod(BindingRequest request) {
245     return Optional.ofNullable(firstMatchingComponentMethods().get(request));
246   }
247 
248   @Memoized
249   ImmutableMap<BindingRequest, ComponentMethodDescriptor>
firstMatchingComponentMethods()250       firstMatchingComponentMethods() {
251     Map<BindingRequest, ComponentMethodDescriptor> methods = new HashMap<>();
252     for (ComponentMethodDescriptor method : entryPointMethods()) {
253       methods.putIfAbsent(BindingRequest.bindingRequest(method.dependencyRequest().get()), method);
254     }
255     return ImmutableMap.copyOf(methods);
256   }
257 
258   /** The entry point methods on the component type. Each has a {@link DependencyRequest}. */
entryPointMethods()259   public final ImmutableSet<ComponentMethodDescriptor> entryPointMethods() {
260     return componentMethods()
261         .stream()
262         .filter(method -> method.dependencyRequest().isPresent())
263         .collect(toImmutableSet());
264   }
265 
266   // TODO(gak): Consider making this non-optional and revising the
267   // interaction between the spec & generation
268   /** Returns a descriptor for the creator type for this component type, if the user defined one. */
creatorDescriptor()269   public abstract Optional<ComponentCreatorDescriptor> creatorDescriptor();
270 
271   /**
272    * Returns {@code true} for components that have a creator, either because the user {@linkplain
273    * #creatorDescriptor() specified one} or because it's a top-level component with an implicit
274    * builder.
275    */
hasCreator()276   public final boolean hasCreator() {
277     return !isSubcomponent() || creatorDescriptor().isPresent();
278   }
279 
280   /**
281    * Returns the {@link CancellationPolicy} for this component, or an empty optional if either the
282    * component is not a production component or no {@code CancellationPolicy} annotation is present.
283    */
cancellationPolicy()284   public final Optional<CancellationPolicy> cancellationPolicy() {
285     return isProduction()
286         ? Optional.ofNullable(typeElement().getAnnotation(CancellationPolicy.class))
287         : Optional.empty();
288   }
289 
290   @Memoized
291   @Override
hashCode()292   public int hashCode() {
293     // TODO(b/122962745): Only use typeElement().hashCode()
294     return Objects.hash(typeElement(), annotation());
295   }
296 
297   // TODO(ronshapiro): simplify the equality semantics
298   @Override
equals(Object obj)299   public abstract boolean equals(Object obj);
300 
301   /** A component method. */
302   @AutoValue
303   public abstract static class ComponentMethodDescriptor {
304     /** The method itself. Note that this may be declared on a supertype of the component. */
methodElement()305     public abstract ExecutableElement methodElement();
306 
307     /**
308      * The dependency request for production, provision, and subcomponent creator methods. Absent
309      * for subcomponent factory methods.
310      */
dependencyRequest()311     public abstract Optional<DependencyRequest> dependencyRequest();
312 
313     /** The subcomponent for subcomponent factory methods and subcomponent creator methods. */
subcomponent()314     public abstract Optional<ComponentDescriptor> subcomponent();
315 
316     /**
317      * Returns the return type of {@link #methodElement()} as resolved in the {@link
318      * ComponentDescriptor#typeElement() component type}. If there are no type variables in the
319      * return type, this is the equivalent of {@code methodElement().getReturnType()}.
320      */
resolvedReturnType(DaggerTypes types)321     public TypeMirror resolvedReturnType(DaggerTypes types) {
322       checkState(dependencyRequest().isPresent());
323 
324       TypeMirror returnType = methodElement().getReturnType();
325       if (returnType.getKind().isPrimitive() || returnType.getKind().equals(VOID)) {
326         return returnType;
327       }
328       return BindingRequest.bindingRequest(dependencyRequest().get())
329           .requestedType(dependencyRequest().get().key().type(), types);
330     }
331 
332     /** A {@link ComponentMethodDescriptor}builder for a method. */
builder(ExecutableElement method)333     public static Builder builder(ExecutableElement method) {
334       return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor.Builder()
335           .methodElement(method);
336     }
337 
338     /** A builder of {@link ComponentMethodDescriptor}s. */
339     @AutoValue.Builder
340     @CanIgnoreReturnValue
341     public interface Builder {
342       /** @see ComponentMethodDescriptor#methodElement() */
methodElement(ExecutableElement methodElement)343       Builder methodElement(ExecutableElement methodElement);
344 
345       /** @see ComponentMethodDescriptor#dependencyRequest() */
dependencyRequest(DependencyRequest dependencyRequest)346       Builder dependencyRequest(DependencyRequest dependencyRequest);
347 
348       /** @see ComponentMethodDescriptor#subcomponent() */
subcomponent(ComponentDescriptor subcomponent)349       Builder subcomponent(ComponentDescriptor subcomponent);
350 
351       /** Builds the descriptor. */
352       @CheckReturnValue
build()353       ComponentMethodDescriptor build();
354     }
355   }
356 
357   /** No-argument methods defined on {@link Object} that are ignored for contribution. */
358   private static final ImmutableSet<String> NON_CONTRIBUTING_OBJECT_METHOD_NAMES =
359       ImmutableSet.of("toString", "hashCode", "clone", "getClass");
360 
361   /**
362    * Returns {@code true} if a method could be a component entry point but not a members-injection
363    * method.
364    */
isComponentContributionMethod(DaggerElements elements, ExecutableElement method)365   static boolean isComponentContributionMethod(DaggerElements elements, ExecutableElement method) {
366     return method.getParameters().isEmpty()
367         && !method.getReturnType().getKind().equals(VOID)
368         && !elements.getTypeElement(Object.class).equals(method.getEnclosingElement())
369         && !NON_CONTRIBUTING_OBJECT_METHOD_NAMES.contains(method.getSimpleName().toString());
370   }
371 
372   /** Returns {@code true} if a method could be a component production entry point. */
isComponentProductionMethod(DaggerElements elements, ExecutableElement method)373   static boolean isComponentProductionMethod(DaggerElements elements, ExecutableElement method) {
374     return isComponentContributionMethod(elements, method) && isFutureType(method.getReturnType());
375   }
376 }
377