• 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.collect.Iterables.consumingIterable;
22 import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotation;
23 import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
24 import static dagger.internal.codegen.base.MoreAnnotationMirrors.getTypeListValue;
25 import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.subcomponentCreatorAnnotations;
26 import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
27 import static javax.lang.model.util.ElementFilter.typesIn;
28 
29 import com.google.auto.common.MoreElements;
30 import com.google.auto.common.MoreTypes;
31 import com.google.common.collect.ImmutableList;
32 import com.google.common.collect.ImmutableSet;
33 import com.google.common.collect.Iterables;
34 import com.google.common.collect.Sets;
35 import dagger.Component;
36 import dagger.Module;
37 import dagger.internal.codegen.langmodel.DaggerElements;
38 import dagger.internal.codegen.langmodel.DaggerTypes;
39 import java.lang.annotation.Annotation;
40 import java.util.ArrayDeque;
41 import java.util.List;
42 import java.util.Optional;
43 import java.util.Queue;
44 import java.util.Set;
45 import javax.lang.model.element.AnnotationMirror;
46 import javax.lang.model.element.Element;
47 import javax.lang.model.element.TypeElement;
48 import javax.lang.model.type.DeclaredType;
49 import javax.lang.model.type.TypeKind;
50 import javax.lang.model.type.TypeMirror;
51 
52 /**
53  * Utility methods related to dagger configuration annotations (e.g.: {@link Component} and {@link
54  * Module}).
55  */
56 public final class ConfigurationAnnotations {
57 
getSubcomponentCreator(TypeElement subcomponent)58   public static Optional<TypeElement> getSubcomponentCreator(TypeElement subcomponent) {
59     checkArgument(subcomponentAnnotation(subcomponent).isPresent());
60     for (TypeElement nestedType : typesIn(subcomponent.getEnclosedElements())) {
61       if (isSubcomponentCreator(nestedType)) {
62         return Optional.of(nestedType);
63       }
64     }
65     return Optional.empty();
66   }
67 
isSubcomponentCreator(Element element)68   static boolean isSubcomponentCreator(Element element) {
69     return isAnyAnnotationPresent(element, subcomponentCreatorAnnotations());
70   }
71 
72   // Dagger 1 support.
getModuleInjects(AnnotationMirror moduleAnnotation)73   public static ImmutableList<TypeMirror> getModuleInjects(AnnotationMirror moduleAnnotation) {
74     checkNotNull(moduleAnnotation);
75     return getTypeListValue(moduleAnnotation, "injects");
76   }
77 
78   /** Returns the first type that specifies this' nullability, or empty if none. */
getNullableType(Element element)79   public static Optional<DeclaredType> getNullableType(Element element) {
80     List<? extends AnnotationMirror> mirrors = element.getAnnotationMirrors();
81     for (AnnotationMirror mirror : mirrors) {
82       if (mirror.getAnnotationType().asElement().getSimpleName().contentEquals("Nullable")) {
83         return Optional.of(mirror.getAnnotationType());
84       }
85     }
86     return Optional.empty();
87   }
88 
89   /**
90    * Returns the full set of modules transitively {@linkplain Module#includes included} from the
91    * given seed modules. If a module is malformed and a type listed in {@link Module#includes} is
92    * not annotated with {@link Module}, it is ignored.
93    *
94    * @deprecated Use {@link ComponentDescriptor#modules()}.
95    */
96   @Deprecated
getTransitiveModules( DaggerTypes types, DaggerElements elements, Iterable<TypeElement> seedModules)97   public static ImmutableSet<TypeElement> getTransitiveModules(
98       DaggerTypes types, DaggerElements elements, Iterable<TypeElement> seedModules) {
99     TypeMirror objectType = elements.getTypeElement(Object.class).asType();
100     Queue<TypeElement> moduleQueue = new ArrayDeque<>();
101     Iterables.addAll(moduleQueue, seedModules);
102     Set<TypeElement> moduleElements = Sets.newLinkedHashSet();
103     for (TypeElement moduleElement : consumingIterable(moduleQueue)) {
104       moduleAnnotation(moduleElement)
105           .ifPresent(
106               moduleAnnotation -> {
107                 ImmutableSet.Builder<TypeElement> moduleDependenciesBuilder =
108                     ImmutableSet.builder();
109                 moduleDependenciesBuilder.addAll(moduleAnnotation.includes());
110                 // We don't recur on the parent class because we don't want the parent class as a
111                 // root that the component depends on, and also because we want the dependencies
112                 // rooted against this element, not the parent.
113                 addIncludesFromSuperclasses(
114                     types, moduleElement, moduleDependenciesBuilder, objectType);
115                 ImmutableSet<TypeElement> moduleDependencies = moduleDependenciesBuilder.build();
116                 moduleElements.add(moduleElement);
117                 for (TypeElement dependencyType : moduleDependencies) {
118                   if (!moduleElements.contains(dependencyType)) {
119                     moduleQueue.add(dependencyType);
120                   }
121                 }
122               });
123     }
124     return ImmutableSet.copyOf(moduleElements);
125   }
126 
127   /** Returns the enclosed types annotated with the given annotation. */
enclosedAnnotatedTypes( TypeElement typeElement, Class<? extends Annotation> annotation)128   public static ImmutableList<DeclaredType> enclosedAnnotatedTypes(
129       TypeElement typeElement, Class<? extends Annotation> annotation) {
130     final ImmutableList.Builder<DeclaredType> builders = ImmutableList.builder();
131     for (TypeElement element : typesIn(typeElement.getEnclosedElements())) {
132       if (MoreElements.isAnnotationPresent(element, annotation)) {
133         builders.add(MoreTypes.asDeclared(element.asType()));
134       }
135     }
136     return builders.build();
137   }
138 
139   /** Traverses includes from superclasses and adds them into the builder. */
addIncludesFromSuperclasses( DaggerTypes types, TypeElement element, ImmutableSet.Builder<TypeElement> builder, TypeMirror objectType)140   private static void addIncludesFromSuperclasses(
141       DaggerTypes types,
142       TypeElement element,
143       ImmutableSet.Builder<TypeElement> builder,
144       TypeMirror objectType) {
145     // Also add the superclass to the queue, in case any @Module definitions were on that.
146     TypeMirror superclass = element.getSuperclass();
147     while (!types.isSameType(objectType, superclass)
148         && superclass.getKind().equals(TypeKind.DECLARED)) {
149       element = MoreElements.asType(types.asElement(superclass));
150       moduleAnnotation(element)
151           .ifPresent(moduleAnnotation -> builder.addAll(moduleAnnotation.includes()));
152       superclass = element.getSuperclass();
153     }
154   }
155 
ConfigurationAnnotations()156   private ConfigurationAnnotations() {}
157 }
158