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.common.base.Function;
21 import com.google.common.base.Optional;
22 import com.google.common.collect.FluentIterable;
23 import com.google.common.collect.ImmutableList;
24 import com.google.common.collect.ImmutableSet;
25 import com.google.common.collect.Iterables;
26 import com.google.common.collect.Sets;
27 import dagger.Component;
28 import dagger.Module;
29 import dagger.Subcomponent;
30 import dagger.producers.ProducerModule;
31 import dagger.producers.ProductionComponent;
32 import java.lang.annotation.Annotation;
33 import java.util.ArrayDeque;
34 import java.util.List;
35 import java.util.Queue;
36 import java.util.Set;
37 import javax.lang.model.element.AnnotationMirror;
38 import javax.lang.model.element.AnnotationValue;
39 import javax.lang.model.element.AnnotationValueVisitor;
40 import javax.lang.model.element.Element;
41 import javax.lang.model.element.TypeElement;
42 import javax.lang.model.type.DeclaredType;
43 import javax.lang.model.type.TypeKind;
44 import javax.lang.model.type.TypeMirror;
45 import javax.lang.model.util.ElementFilter;
46 import javax.lang.model.util.Elements;
47 import javax.lang.model.util.SimpleAnnotationValueVisitor6;
48 import javax.lang.model.util.SimpleTypeVisitor6;
49 import javax.lang.model.util.Types;
50 
51 import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
52 import static com.google.auto.common.MoreElements.getAnnotationMirror;
53 import static com.google.common.base.Preconditions.checkNotNull;
54 
55 /**
56  * Utility methods related to dagger configuration annotations (e.g.: {@link Component}
57  * and {@link Module}).
58  *
59  * @author Gregory Kick
60  */
61 final class ConfigurationAnnotations {
62 
isComponent(TypeElement componentDefinitionType)63   static boolean isComponent(TypeElement componentDefinitionType) {
64     return MoreElements.isAnnotationPresent(componentDefinitionType, Component.class)
65         || MoreElements.isAnnotationPresent(componentDefinitionType, ProductionComponent.class);
66   }
67 
68   private static final String MODULES_ATTRIBUTE = "modules";
69 
getComponentModules(AnnotationMirror componentAnnotation)70   static ImmutableList<TypeMirror> getComponentModules(AnnotationMirror componentAnnotation) {
71     checkNotNull(componentAnnotation);
72     return convertClassArrayToListOfTypes(componentAnnotation, MODULES_ATTRIBUTE);
73   }
74 
75   private static final String DEPENDENCIES_ATTRIBUTE = "dependencies";
76 
getComponentDependencies(AnnotationMirror componentAnnotation)77   static ImmutableList<TypeMirror> getComponentDependencies(AnnotationMirror componentAnnotation) {
78     checkNotNull(componentAnnotation);
79     return convertClassArrayToListOfTypes(componentAnnotation, DEPENDENCIES_ATTRIBUTE);
80   }
81 
82   private static final String INCLUDES_ATTRIBUTE = "includes";
83 
getModuleIncludes(AnnotationMirror moduleAnnotation)84   static ImmutableList<TypeMirror> getModuleIncludes(AnnotationMirror moduleAnnotation) {
85     checkNotNull(moduleAnnotation);
86     return convertClassArrayToListOfTypes(moduleAnnotation, INCLUDES_ATTRIBUTE);
87   }
88 
89   private static final String INJECTS_ATTRIBUTE = "injects";
90 
getModuleInjects(AnnotationMirror moduleAnnotation)91   static ImmutableList<TypeMirror> getModuleInjects(AnnotationMirror moduleAnnotation) {
92     checkNotNull(moduleAnnotation);
93     return convertClassArrayToListOfTypes(moduleAnnotation, INJECTS_ATTRIBUTE);
94   }
95 
96   /** Returns the first type that specifies this' nullability, or absent if none. */
getNullableType(Element element)97   static Optional<DeclaredType> getNullableType(Element element) {
98     List<? extends AnnotationMirror> mirrors = element.getAnnotationMirrors();
99     for (AnnotationMirror mirror : mirrors) {
100       if (mirror.getAnnotationType().asElement().getSimpleName().toString().equals("Nullable")) {
101         return Optional.of(mirror.getAnnotationType());
102       }
103     }
104     return Optional.absent();
105   }
106 
107   /**
108    * Extracts the list of types that is the value of the annotation member {@code elementName} of
109    * {@code annotationMirror}.
110    *
111    * @throws IllegalArgumentException if no such member exists on {@code annotationMirror}, or it
112    *     exists but is not an array
113    * @throws TypeNotPresentException if any of the values cannot be converted to a type
114    */
convertClassArrayToListOfTypes( AnnotationMirror annotationMirror, String elementName)115   static ImmutableList<TypeMirror> convertClassArrayToListOfTypes(
116       AnnotationMirror annotationMirror, String elementName) {
117     return TO_LIST_OF_TYPES.visit(getAnnotationValue(annotationMirror, elementName), elementName);
118   }
119 
120   private static final AnnotationValueVisitor<ImmutableList<TypeMirror>, String> TO_LIST_OF_TYPES =
121       new SimpleAnnotationValueVisitor6<ImmutableList<TypeMirror>, String>() {
122         @Override
123         public ImmutableList<TypeMirror> visitArray(
124             List<? extends AnnotationValue> vals, String elementName) {
125           return FluentIterable.from(vals)
126               .transform(
127                   new Function<AnnotationValue, TypeMirror>() {
128                     @Override
129                     public TypeMirror apply(AnnotationValue typeValue) {
130                       return TO_TYPE.visit(typeValue);
131                     }
132                   })
133               .toList();
134         }
135 
136         @Override
137         protected ImmutableList<TypeMirror> defaultAction(Object o, String elementName) {
138           throw new IllegalArgumentException(elementName + " is not an array: " + o);
139         }
140       };
141 
142   private static final AnnotationValueVisitor<TypeMirror, Void> TO_TYPE =
143       new SimpleAnnotationValueVisitor6<TypeMirror, Void>() {
144         @Override
145         public TypeMirror visitType(TypeMirror t, Void p) {
146           return t;
147         }
148 
149         @Override
150         protected TypeMirror defaultAction(Object o, Void p) {
151           throw new TypeNotPresentException(o.toString(), null);
152         }
153       };
154 
155   /**
156    * Returns the full set of modules transitively {@linkplain Module#includes included} from the
157    * given seed modules.  If a module is malformed and a type listed in {@link Module#includes}
158    * is not annotated with {@link Module}, it is ignored.
159    *
160    * @deprecated Use {@link ComponentDescriptor#transitiveModules}.
161    */
162   @Deprecated
getTransitiveModules( Types types, Elements elements, Iterable<TypeElement> seedModules)163   static ImmutableSet<TypeElement> getTransitiveModules(
164       Types types, Elements elements, Iterable<TypeElement> seedModules) {
165     TypeMirror objectType = elements.getTypeElement(Object.class.getCanonicalName()).asType();
166     Queue<TypeElement> moduleQueue = new ArrayDeque<>();
167     Iterables.addAll(moduleQueue, seedModules);
168     Set<TypeElement> moduleElements = Sets.newLinkedHashSet();
169     for (TypeElement moduleElement = moduleQueue.poll();
170         moduleElement != null;
171         moduleElement = moduleQueue.poll()) {
172       Optional<AnnotationMirror> moduleMirror = getAnnotationMirror(moduleElement, Module.class)
173           .or(getAnnotationMirror(moduleElement, ProducerModule.class));
174       if (moduleMirror.isPresent()) {
175         ImmutableSet.Builder<TypeElement> moduleDependenciesBuilder = ImmutableSet.builder();
176         moduleDependenciesBuilder.addAll(
177             MoreTypes.asTypeElements(getModuleIncludes(moduleMirror.get())));
178         // (note: we don't recurse on the parent class because we don't want the parent class as a
179         // root that the component depends on, and also because we want the dependencies rooted
180         // against this element, not the parent.)
181         addIncludesFromSuperclasses(types, moduleElement, moduleDependenciesBuilder, objectType);
182         ImmutableSet<TypeElement> moduleDependencies = moduleDependenciesBuilder.build();
183         moduleElements.add(moduleElement);
184         for (TypeElement dependencyType : moduleDependencies) {
185           if (!moduleElements.contains(dependencyType)) {
186             moduleQueue.add(dependencyType);
187           }
188         }
189       }
190     }
191     return ImmutableSet.copyOf(moduleElements);
192   }
193 
194   /** Returns the enclosed elements annotated with the given annotation type. */
enclosedBuilders(TypeElement typeElement, final Class<? extends Annotation> annotation)195   static ImmutableList<DeclaredType> enclosedBuilders(TypeElement typeElement,
196       final Class<? extends Annotation> annotation) {
197     final ImmutableList.Builder<DeclaredType> builders = ImmutableList.builder();
198     for (TypeElement element : ElementFilter.typesIn(typeElement.getEnclosedElements())) {
199       if (MoreElements.isAnnotationPresent(element, annotation)) {
200         builders.add(MoreTypes.asDeclared(element.asType()));
201       }
202     }
203     return builders.build();
204   }
205 
isSubcomponentType(TypeMirror type)206   static boolean isSubcomponentType(TypeMirror type) {
207     return type.accept(new SubcomponentDetector(), null).isPresent();
208   }
209 
210   private static final class SubcomponentDetector
211       extends SimpleTypeVisitor6<Optional<AnnotationMirror>, Void> {
212     @Override
defaultAction(TypeMirror e, Void p)213     protected Optional<AnnotationMirror> defaultAction(TypeMirror e, Void p) {
214       return Optional.absent();
215     }
216 
217     @Override
visitDeclared(DeclaredType t, Void p)218     public Optional<AnnotationMirror> visitDeclared(DeclaredType t, Void p) {
219       return MoreElements.getAnnotationMirror(t.asElement(), Subcomponent.class);
220     }
221   }
222 
223   /** Traverses includes from superclasses and adds them into the builder. */
addIncludesFromSuperclasses(Types types, TypeElement element, ImmutableSet.Builder<TypeElement> builder, TypeMirror objectType)224   private static void addIncludesFromSuperclasses(Types types, TypeElement element,
225       ImmutableSet.Builder<TypeElement> builder, TypeMirror objectType) {
226     // Also add the superclass to the queue, in case any @Module definitions were on that.
227     TypeMirror superclass = element.getSuperclass();
228     while (!types.isSameType(objectType, superclass)
229         && superclass.getKind().equals(TypeKind.DECLARED)) {
230       element = MoreElements.asType(types.asElement(superclass));
231       Optional<AnnotationMirror> moduleMirror = getAnnotationMirror(element, Module.class)
232           .or(getAnnotationMirror(element, ProducerModule.class));
233       if (moduleMirror.isPresent()) {
234         builder.addAll(MoreTypes.asTypeElements(getModuleIncludes(moduleMirror.get())));
235       }
236       superclass = element.getSuperclass();
237     }
238   }
239 
ConfigurationAnnotations()240   private ConfigurationAnnotations() {}
241 }
242