• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 Google, Inc.
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 package dagger.internal.codegen;
17 
18 import com.google.auto.common.MoreElements;
19 import com.google.auto.common.MoreTypes;
20 import com.google.auto.value.AutoValue;
21 import com.google.common.base.Optional;
22 import com.google.common.base.Predicate;
23 import com.google.common.collect.FluentIterable;
24 import com.google.common.collect.ImmutableList;
25 import com.google.common.collect.ImmutableMap;
26 import com.google.common.collect.ImmutableSet;
27 import com.google.common.util.concurrent.ListenableFuture;
28 import dagger.Component;
29 import dagger.Lazy;
30 import dagger.MembersInjector;
31 import dagger.Module;
32 import dagger.Subcomponent;
33 import dagger.producers.ProductionComponent;
34 import java.lang.annotation.Annotation;
35 import java.util.EnumSet;
36 import java.util.LinkedHashSet;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Set;
40 import java.util.concurrent.Executor;
41 import javax.inject.Provider;
42 import javax.lang.model.element.AnnotationMirror;
43 import javax.lang.model.element.ExecutableElement;
44 import javax.lang.model.element.TypeElement;
45 import javax.lang.model.type.DeclaredType;
46 import javax.lang.model.type.ExecutableType;
47 import javax.lang.model.type.TypeMirror;
48 import javax.lang.model.util.ElementFilter;
49 import javax.lang.model.util.Elements;
50 import javax.lang.model.util.Types;
51 
52 import static com.google.auto.common.MoreElements.getAnnotationMirror;
53 import static com.google.auto.common.MoreElements.isAnnotationPresent;
54 import static com.google.common.base.Preconditions.checkArgument;
55 import static com.google.common.base.Verify.verify;
56 import static com.google.common.collect.Iterables.getOnlyElement;
57 import static dagger.internal.codegen.ConfigurationAnnotations.enclosedBuilders;
58 import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies;
59 import static dagger.internal.codegen.ConfigurationAnnotations.getComponentModules;
60 import static dagger.internal.codegen.ConfigurationAnnotations.isComponent;
61 import static javax.lang.model.type.TypeKind.DECLARED;
62 import static javax.lang.model.type.TypeKind.VOID;
63 
64 /**
65  * The logical representation of a {@link Component} or {@link ProductionComponent} definition.
66  *
67  * @author Gregory Kick
68  * @since 2.0
69  */
70 @AutoValue
71 abstract class ComponentDescriptor {
ComponentDescriptor()72   ComponentDescriptor() {}
73 
74   enum Kind {
75     COMPONENT(Component.class, Component.Builder.class, true),
76     SUBCOMPONENT(Subcomponent.class, Subcomponent.Builder.class, false),
77     PRODUCTION_COMPONENT(ProductionComponent.class, ProductionComponent.Builder.class, true);
78 
79     private final Class<? extends Annotation> annotationType;
80     private final Class<? extends Annotation> builderType;
81     private final boolean isTopLevel;
82 
83     /**
84      * Returns the kind of an annotated element if it is annotated with one of the
85      * {@linkplain #annotationType() annotation types}.
86      *
87      * @throws IllegalArgumentException if the element is annotated with more than one of the
88      *     annotation types
89      */
forAnnotatedElement(TypeElement element)90     static Optional<Kind> forAnnotatedElement(TypeElement element) {
91       Set<Kind> kinds = EnumSet.noneOf(Kind.class);
92       for (Kind kind : values()) {
93         if (MoreElements.isAnnotationPresent(element, kind.annotationType())) {
94           kinds.add(kind);
95         }
96       }
97       checkArgument(
98           kinds.size() <= 1, "%s cannot be annotated with more than one of %s", element, kinds);
99       return Optional.fromNullable(getOnlyElement(kinds, null));
100     }
101 
Kind( Class<? extends Annotation> annotationType, Class<? extends Annotation> builderType, boolean isTopLevel)102     Kind(
103         Class<? extends Annotation> annotationType,
104         Class<? extends Annotation> builderType,
105         boolean isTopLevel) {
106       this.annotationType = annotationType;
107       this.builderType = builderType;
108       this.isTopLevel = isTopLevel;
109     }
110 
annotationType()111     Class<? extends Annotation> annotationType() {
112       return annotationType;
113     }
114 
builderAnnotationType()115     Class<? extends Annotation> builderAnnotationType() {
116       return builderType;
117     }
118 
isTopLevel()119     boolean isTopLevel() {
120       return isTopLevel;
121     }
122   }
123 
kind()124   abstract Kind kind();
125 
componentAnnotation()126   abstract AnnotationMirror componentAnnotation();
127 
128   /**
129    * The type (interface or abstract class) that defines the component. This is the element to which
130    * the {@link Component} annotation was applied.
131    */
componentDefinitionType()132   abstract TypeElement componentDefinitionType();
133 
134   /**
135    * The set of component dependencies listed in {@link Component#dependencies}.
136    */
dependencies()137   abstract ImmutableSet<TypeElement> dependencies();
138 
139   /**
140    * The set of {@link ModuleDescriptor modules} declared directly in {@link Component#modules}.
141    * Use {@link #transitiveModules} to get the full set of modules available upon traversing
142    * {@link Module#includes}.
143    */
modules()144   abstract ImmutableSet<ModuleDescriptor> modules();
145 
146   /**
147    * Returns the set of {@link ModuleDescriptor modules} declared in {@link Component#modules} and
148    * those reachable by traversing {@link Module#includes}.
149    *
150    * <p>Note that for subcomponents this <em>will not</em> include descriptors for any modules that
151    * are declared in parent components.
152    */
transitiveModules()153   ImmutableSet<ModuleDescriptor> transitiveModules() {
154     Set<ModuleDescriptor> transitiveModules = new LinkedHashSet<>();
155     for (ModuleDescriptor module : modules()) {
156       addTransitiveModules(transitiveModules, module);
157     }
158     return ImmutableSet.copyOf(transitiveModules);
159   }
160 
transitiveModuleTypes()161   ImmutableSet<TypeElement> transitiveModuleTypes() {
162     return FluentIterable.from(transitiveModules())
163         .transform(ModuleDescriptor.getModuleElement())
164         .toSet();
165   }
166 
addTransitiveModules( Set<ModuleDescriptor> transitiveModules, ModuleDescriptor module)167   private static Set<ModuleDescriptor> addTransitiveModules(
168       Set<ModuleDescriptor> transitiveModules, ModuleDescriptor module) {
169     if (transitiveModules.add(module)) {
170       for (ModuleDescriptor includedModule : module.includedModules()) {
171         addTransitiveModules(transitiveModules, includedModule);
172       }
173     }
174     return transitiveModules;
175   }
176 
177   /**
178    * An index of the type to which this component holds a reference (the type listed in
179    * {@link Component#dependencies} or {@link ProductionComponent#dependencies} as opposed to the
180    * enclosing type) for each method from a component dependency that can be used for binding.
181    */
dependencyMethodIndex()182   abstract ImmutableMap<ExecutableElement, TypeElement> dependencyMethodIndex();
183 
184   /**
185    * The element representing {@link Executor}, if it should be a dependency of this component.
186    */
executorDependency()187   abstract Optional<TypeElement> executorDependency();
188 
189   /**
190    * The scope of the component.
191    */
scope()192   abstract Scope scope();
193 
subcomponents()194   abstract ImmutableMap<ComponentMethodDescriptor, ComponentDescriptor> subcomponents();
195 
componentMethods()196   abstract ImmutableSet<ComponentMethodDescriptor> componentMethods();
197 
198   // TODO(gak): Consider making this non-optional and revising the
199   // interaction between the spec & generation
builderSpec()200   abstract Optional<BuilderSpec> builderSpec();
201 
202   @AutoValue
203   static abstract class ComponentMethodDescriptor {
kind()204     abstract ComponentMethodKind kind();
dependencyRequest()205     abstract Optional<DependencyRequest> dependencyRequest();
methodElement()206     abstract ExecutableElement methodElement();
207 
208     /**
209      * A predicate that passes for {@link ComponentMethodDescriptor}s of a given kind.
210      */
isOfKind(final ComponentMethodKind kind)211     static Predicate<ComponentMethodDescriptor> isOfKind(final ComponentMethodKind kind) {
212       return new Predicate<ComponentMethodDescriptor>() {
213         @Override
214         public boolean apply(ComponentMethodDescriptor descriptor) {
215           return kind.equals(descriptor.kind());
216         }
217       };
218     }
219   }
220 
221   enum ComponentMethodKind {
222     PROVISON,
223     PRODUCTION,
224     MEMBERS_INJECTION,
225     SUBCOMPONENT,
226     SUBCOMPONENT_BUILDER,
227   }
228 
229   @AutoValue
230   static abstract class BuilderSpec {
231     abstract TypeElement builderDefinitionType();
232     abstract Map<TypeElement, ExecutableElement> methodMap();
233     abstract ExecutableElement buildMethod();
234     abstract TypeMirror componentType();
235   }
236 
237   static final class Factory {
238     private final Elements elements;
239     private final Types types;
240     private final DependencyRequest.Factory dependencyRequestFactory;
241     private final ModuleDescriptor.Factory moduleDescriptorFactory;
242 
243     Factory(
244         Elements elements,
245         Types types,
246         DependencyRequest.Factory dependencyRequestFactory,
247         ModuleDescriptor.Factory moduleDescriptorFactory) {
248       this.elements = elements;
249       this.types = types;
250       this.dependencyRequestFactory = dependencyRequestFactory;
251       this.moduleDescriptorFactory = moduleDescriptorFactory;
252     }
253 
254     /**
255      * Returns a component descriptor for a type annotated with either {@link Component @Component}
256      * or {@link ProductionComponent @ProductionComponent}.
257      */
258     ComponentDescriptor forComponent(TypeElement componentDefinitionType) {
259       Optional<Kind> kind = Kind.forAnnotatedElement(componentDefinitionType);
260       checkArgument(
261           kind.isPresent() && kind.get().isTopLevel(),
262           "%s must be annotated with @Component or @ProductionComponent",
263           componentDefinitionType);
264       return create(componentDefinitionType, kind.get());
265     }
266 
267     private ComponentDescriptor create(TypeElement componentDefinitionType, Kind kind) {
268       DeclaredType declaredComponentType = MoreTypes.asDeclared(componentDefinitionType.asType());
269       AnnotationMirror componentMirror =
270           getAnnotationMirror(componentDefinitionType, kind.annotationType())
271               .or(getAnnotationMirror(componentDefinitionType, Subcomponent.class))
272               .get();
273       ImmutableSet<TypeElement> componentDependencyTypes =
274           isComponent(componentDefinitionType)
275               ? MoreTypes.asTypeElements(getComponentDependencies(componentMirror))
276               : ImmutableSet.<TypeElement>of();
277 
278       ImmutableMap.Builder<ExecutableElement, TypeElement> dependencyMethodIndex =
279           ImmutableMap.builder();
280 
281       for (TypeElement componentDependency : componentDependencyTypes) {
282         List<ExecutableElement> dependencyMethods =
283             ElementFilter.methodsIn(elements.getAllMembers(componentDependency));
284         for (ExecutableElement dependencyMethod : dependencyMethods) {
285           if (isComponentContributionMethod(elements, dependencyMethod)) {
286             dependencyMethodIndex.put(dependencyMethod, componentDependency);
287           }
288         }
289       }
290 
291       Optional<TypeElement> executorDependency =
292           kind.equals(Kind.PRODUCTION_COMPONENT)
293               ? Optional.of(elements.getTypeElement(Executor.class.getCanonicalName()))
294               : Optional.<TypeElement>absent();
295 
296       ImmutableSet.Builder<ModuleDescriptor> modules = ImmutableSet.builder();
297       for (TypeMirror moduleIncludesType : getComponentModules(componentMirror)) {
298         modules.add(moduleDescriptorFactory.create(MoreTypes.asTypeElement(moduleIncludesType)));
299       }
300       if (kind.equals(Kind.PRODUCTION_COMPONENT)) {
301         modules.add(descriptorForMonitoringModule(componentDefinitionType));
302       }
303 
304       ImmutableSet<ExecutableElement> unimplementedMethods =
305           Util.getUnimplementedMethods(elements, componentDefinitionType);
306 
307       ImmutableSet.Builder<ComponentMethodDescriptor> componentMethodsBuilder =
308           ImmutableSet.builder();
309 
310       ImmutableMap.Builder<ComponentMethodDescriptor, ComponentDescriptor> subcomponentDescriptors =
311           ImmutableMap.builder();
312       for (ExecutableElement componentMethod : unimplementedMethods) {
313         ExecutableType resolvedMethod =
314             MoreTypes.asExecutable(types.asMemberOf(declaredComponentType, componentMethod));
315         ComponentMethodDescriptor componentMethodDescriptor =
316             getDescriptorForComponentMethod(componentDefinitionType, kind, componentMethod);
317         componentMethodsBuilder.add(componentMethodDescriptor);
318         switch (componentMethodDescriptor.kind()) {
319           case SUBCOMPONENT:
320             subcomponentDescriptors.put(
321                 componentMethodDescriptor,
322                 create(
323                     MoreElements.asType(MoreTypes.asElement(resolvedMethod.getReturnType())),
324                     Kind.SUBCOMPONENT));
325             break;
326           case SUBCOMPONENT_BUILDER:
327             subcomponentDescriptors.put(
328                 componentMethodDescriptor,
329                 create(
330                     MoreElements.asType(
331                         MoreTypes.asElement(resolvedMethod.getReturnType()).getEnclosingElement()),
332                     Kind.SUBCOMPONENT));
333             break;
334           default: // nothing special to do for other methods.
335         }
336 
337       }
338 
339       ImmutableList<DeclaredType> enclosedBuilders = kind.builderAnnotationType() == null
340           ? ImmutableList.<DeclaredType>of()
341           : enclosedBuilders(componentDefinitionType, kind.builderAnnotationType());
342       Optional<DeclaredType> builderType =
343           Optional.fromNullable(getOnlyElement(enclosedBuilders, null));
344 
345       Scope scope = Scope.scopeOf(componentDefinitionType);
346       return new AutoValue_ComponentDescriptor(
347           kind,
348           componentMirror,
349           componentDefinitionType,
350           componentDependencyTypes,
351           modules.build(),
352           dependencyMethodIndex.build(),
353           executorDependency,
354           scope,
355           subcomponentDescriptors.build(),
356           componentMethodsBuilder.build(),
357           createBuilderSpec(builderType));
358     }
359 
360     private ComponentMethodDescriptor getDescriptorForComponentMethod(TypeElement componentElement,
361         Kind componentKind,
362         ExecutableElement componentMethod) {
363       ExecutableType resolvedComponentMethod = MoreTypes.asExecutable(types.asMemberOf(
364           MoreTypes.asDeclared(componentElement.asType()), componentMethod));
365       TypeMirror returnType = resolvedComponentMethod.getReturnType();
366       if (returnType.getKind().equals(DECLARED)) {
367         if (MoreTypes.isTypeOf(Provider.class, returnType)
368             || MoreTypes.isTypeOf(Lazy.class, returnType)) {
369           return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
370               ComponentMethodKind.PROVISON,
371               Optional.of(dependencyRequestFactory.forComponentProvisionMethod(componentMethod,
372                   resolvedComponentMethod)),
373               componentMethod);
374         } else if (MoreTypes.isTypeOf(MembersInjector.class, returnType)) {
375           return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
376               ComponentMethodKind.MEMBERS_INJECTION,
377               Optional.of(dependencyRequestFactory.forComponentMembersInjectionMethod(
378                   componentMethod,
379                   resolvedComponentMethod)),
380               componentMethod);
381         } else if (isAnnotationPresent(MoreTypes.asElement(returnType), Subcomponent.class)) {
382           return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
383               ComponentMethodKind.SUBCOMPONENT,
384               Optional.<DependencyRequest>absent(),
385               componentMethod);
386         } else if (isAnnotationPresent(MoreTypes.asElement(returnType),
387             Subcomponent.Builder.class)) {
388           return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
389               ComponentMethodKind.SUBCOMPONENT_BUILDER,
390               Optional.<DependencyRequest>absent(),
391               componentMethod);
392         }
393       }
394 
395       // a typical provision method
396       if (componentMethod.getParameters().isEmpty()
397           && !componentMethod.getReturnType().getKind().equals(VOID)) {
398         switch (componentKind) {
399           case COMPONENT:
400           case SUBCOMPONENT:
401             return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
402                 ComponentMethodKind.PROVISON,
403                 Optional.of(dependencyRequestFactory.forComponentProvisionMethod(componentMethod,
404                     resolvedComponentMethod)),
405                 componentMethod);
406           case PRODUCTION_COMPONENT:
407             return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
408                 ComponentMethodKind.PRODUCTION,
409                 Optional.of(dependencyRequestFactory.forComponentProductionMethod(componentMethod,
410                     resolvedComponentMethod)),
411                 componentMethod);
412           default:
413             throw new AssertionError();
414         }
415       }
416 
417       List<? extends TypeMirror> parameterTypes = resolvedComponentMethod.getParameterTypes();
418       if (parameterTypes.size() == 1
419           && (returnType.getKind().equals(VOID)
420               || MoreTypes.equivalence().equivalent(returnType, parameterTypes.get(0)))) {
421         return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
422             ComponentMethodKind.MEMBERS_INJECTION,
423             Optional.of(dependencyRequestFactory.forComponentMembersInjectionMethod(
424                 componentMethod,
425                 resolvedComponentMethod)),
426             componentMethod);
427       }
428 
429       throw new IllegalArgumentException("not a valid component method: " + componentMethod);
430     }
431 
432     private Optional<BuilderSpec> createBuilderSpec(Optional<DeclaredType> builderType) {
433       if (!builderType.isPresent()) {
434         return Optional.absent();
435       }
436       TypeElement element = MoreTypes.asTypeElement(builderType.get());
437       ImmutableSet<ExecutableElement> methods = Util.getUnimplementedMethods(elements, element);
438       ImmutableMap.Builder<TypeElement, ExecutableElement> map = ImmutableMap.builder();
439       ExecutableElement buildMethod = null;
440       for (ExecutableElement method : methods) {
441         if (method.getParameters().isEmpty()) {
442           buildMethod = method;
443         } else {
444           ExecutableType resolved =
445               MoreTypes.asExecutable(types.asMemberOf(builderType.get(), method));
446           map.put(MoreTypes.asTypeElement(getOnlyElement(resolved.getParameterTypes())), method);
447         }
448       }
449       verify(buildMethod != null); // validation should have ensured this.
450       return Optional.<BuilderSpec>of(new AutoValue_ComponentDescriptor_BuilderSpec(element,
451           map.build(), buildMethod, element.getEnclosingElement().asType()));
452     }
453 
454     /**
455      * Returns a descriptor for a generated module that handles monitoring for production
456      * components. This module is generated in the {@link MonitoringModuleProcessingStep}.
457      *
458      * @throws TypeNotPresentException if the module has not been generated yet. This will cause the
459      *     processor to retry in a later processing round.
460      */
461     private ModuleDescriptor descriptorForMonitoringModule(TypeElement componentDefinitionType) {
462       String generatedMonitorModuleName =
463           SourceFiles.generatedMonitoringModuleName(componentDefinitionType).canonicalName();
464       TypeElement monitoringModule = elements.getTypeElement(generatedMonitorModuleName);
465       if (monitoringModule == null) {
466         throw new TypeNotPresentException(generatedMonitorModuleName, null);
467       }
468       return moduleDescriptorFactory.create(monitoringModule);
469     }
470   }
471 
472   static boolean isComponentContributionMethod(Elements elements, ExecutableElement method) {
473     return method.getParameters().isEmpty()
474         && !method.getReturnType().getKind().equals(VOID)
475         && !elements.getTypeElement(Object.class.getCanonicalName())
476             .equals(method.getEnclosingElement());
477   }
478 
479   static boolean isComponentProductionMethod(Elements elements, ExecutableElement method) {
480     return isComponentContributionMethod(elements, method)
481         && MoreTypes.isTypeOf(ListenableFuture.class, method.getReturnType());
482   }
483 }
484