• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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;
18 
19 import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
20 import static com.google.auto.common.MoreTypes.asTypeElements;
21 import static com.google.auto.common.MoreTypes.isTypeOf;
22 import static dagger.internal.codegen.DaggerStreams.toImmutableList;
23 import static dagger.internal.codegen.MoreAnnotationValues.asAnnotationValues;
24 import static dagger.internal.codegen.langmodel.DaggerElements.getAnyAnnotation;
25 
26 import com.google.auto.value.AutoValue;
27 import com.google.auto.value.extension.memoized.Memoized;
28 import com.google.common.collect.ImmutableList;
29 import com.google.common.collect.ImmutableSet;
30 import dagger.Component;
31 import dagger.Subcomponent;
32 import dagger.producers.ProducerModule;
33 import dagger.producers.ProductionComponent;
34 import dagger.producers.ProductionSubcomponent;
35 import java.lang.annotation.Annotation;
36 import java.util.Collection;
37 import java.util.Optional;
38 import javax.lang.model.element.AnnotationMirror;
39 import javax.lang.model.element.AnnotationValue;
40 import javax.lang.model.element.TypeElement;
41 import javax.lang.model.type.TypeMirror;
42 
43 /**
44  * A {@code @Component}, {@code @Subcomponent}, {@code @ProductionComponent}, or
45  * {@code @ProductionSubcomponent} annotation, or a {@code @Module} or {@code @ProducerModule}
46  * annotation that is being treated as a component annotation when validating full binding graphs
47  * for modules.
48  */
49 abstract class ComponentAnnotation {
50   /** The root component annotation types. */
51   private static final ImmutableSet<Class<? extends Annotation>> ROOT_COMPONENT_ANNOTATIONS =
52      ImmutableSet.of(Component.class, ProductionComponent.class);
53 
54   /** The subcomponent annotation types. */
55   private static final ImmutableSet<Class<? extends Annotation>> SUBCOMPONENT_ANNOTATIONS =
56      ImmutableSet.of(Subcomponent.class, ProductionSubcomponent.class);
57 
58   /** All component annotation types. */
59   private static final ImmutableSet<Class<? extends Annotation>> ALL_COMPONENT_ANNOTATIONS =
60      ImmutableSet.<Class<? extends Annotation>>builder()
61          .addAll(ROOT_COMPONENT_ANNOTATIONS)
62          .addAll(SUBCOMPONENT_ANNOTATIONS)
63          .build();
64 
65   /** The annotation itself. */
annotation()66   abstract AnnotationMirror annotation();
67 
68   /** The simple name of the annotation type. */
simpleName()69   String simpleName() {
70     return MoreAnnotationMirrors.simpleName(annotation()).toString();
71   }
72 
73   /**
74    * Returns {@code true} if the annotation is a {@code @Subcomponent} or
75    * {@code @ProductionSubcomponent}.
76    */
isSubcomponent()77   abstract boolean isSubcomponent();
78 
79   /**
80    * Returns {@code true} if the annotation is a {@code @ProductionComponent},
81    * {@code @ProductionSubcomponent}, or {@code @ProducerModule}.
82    */
isProduction()83   abstract boolean isProduction();
84 
85   /**
86    * Returns {@code true} if the annotation is a real component annotation and not a module
87    * annotation.
88    */
isRealComponent()89   abstract boolean isRealComponent();
90 
91   /** The values listed as {@code dependencies}. */
dependencyValues()92   abstract ImmutableList<AnnotationValue> dependencyValues();
93 
94   /** The types listed as {@code dependencies}. */
dependencyTypes()95   ImmutableList<TypeMirror> dependencyTypes() {
96     return dependencyValues().stream().map(MoreAnnotationValues::asType).collect(toImmutableList());
97   }
98 
99   /**
100    * The types listed as {@code dependencies}.
101    *
102    * @throws IllegalArgumentException if any of {@link #dependencyTypes()} are error types
103    */
dependencies()104   ImmutableList<TypeElement> dependencies() {
105     return asTypeElements(dependencyTypes()).asList();
106   }
107 
108   /** The values listed as {@code modules}. */
moduleValues()109   abstract ImmutableList<AnnotationValue> moduleValues();
110 
111   /** The types listed as {@code modules}. */
moduleTypes()112   ImmutableList<TypeMirror> moduleTypes() {
113     return moduleValues().stream().map(MoreAnnotationValues::asType).collect(toImmutableList());
114   }
115 
116   /**
117    * The types listed as {@code modules}.
118    *
119    * @throws IllegalArgumentException if any of {@link #moduleTypes()} are error types
120    */
modules()121   ImmutableSet<TypeElement> modules() {
122     return asTypeElements(moduleTypes());
123   }
124 
getAnnotationValues(String parameterName)125   protected final ImmutableList<AnnotationValue> getAnnotationValues(String parameterName) {
126     return asAnnotationValues(getAnnotationValue(annotation(), parameterName));
127   }
128 
129   /**
130    * Returns an object representing a root component annotation, not a subcomponent annotation, if
131    * one is present on {@code typeElement}.
132    */
rootComponentAnnotation(TypeElement typeElement)133   static Optional<ComponentAnnotation> rootComponentAnnotation(TypeElement typeElement) {
134     return anyComponentAnnotation(typeElement, ROOT_COMPONENT_ANNOTATIONS);
135   }
136 
137   /**
138    * Returns an object representing a subcomponent annotation, if one is present on {@code
139    * typeElement}.
140    */
subcomponentAnnotation(TypeElement typeElement)141   static Optional<ComponentAnnotation> subcomponentAnnotation(TypeElement typeElement) {
142     return anyComponentAnnotation(typeElement, SUBCOMPONENT_ANNOTATIONS);
143   }
144 
145   /**
146    * Returns an object representing a root component or subcomponent annotation, if one is present
147    * on {@code typeElement}.
148    */
anyComponentAnnotation(TypeElement typeElement)149   static Optional<ComponentAnnotation> anyComponentAnnotation(TypeElement typeElement) {
150     return anyComponentAnnotation(typeElement, ALL_COMPONENT_ANNOTATIONS);
151   }
152 
anyComponentAnnotation( TypeElement typeElement, Collection<Class<? extends Annotation>> annotations)153   private static Optional<ComponentAnnotation> anyComponentAnnotation(
154       TypeElement typeElement, Collection<Class<? extends Annotation>> annotations) {
155     return getAnyAnnotation(typeElement, annotations).map(ComponentAnnotation::componentAnnotation);
156   }
157 
158   /** Returns {@code true} if the argument is a component annotation. */
isComponentAnnotation(AnnotationMirror annotation)159   static boolean isComponentAnnotation(AnnotationMirror annotation) {
160     return ALL_COMPONENT_ANNOTATIONS.stream()
161         .anyMatch(annotationClass -> isTypeOf(annotationClass, annotation.getAnnotationType()));
162   }
163 
164   /** Creates an object representing a component or subcomponent annotation. */
componentAnnotation(AnnotationMirror annotation)165   static ComponentAnnotation componentAnnotation(AnnotationMirror annotation) {
166     RealComponentAnnotation.Builder annotationBuilder =
167         RealComponentAnnotation.builder().annotation(annotation);
168 
169     if (isTypeOf(Component.class, annotation.getAnnotationType())) {
170       return annotationBuilder.isProduction(false).isSubcomponent(false).build();
171     }
172     if (isTypeOf(Subcomponent.class, annotation.getAnnotationType())) {
173       return annotationBuilder.isProduction(false).isSubcomponent(true).build();
174     }
175     if (isTypeOf(ProductionComponent.class, annotation.getAnnotationType())) {
176       return annotationBuilder.isProduction(true).isSubcomponent(false).build();
177     }
178     if (isTypeOf(ProductionSubcomponent.class, annotation.getAnnotationType())) {
179       return annotationBuilder.isProduction(true).isSubcomponent(true).build();
180     }
181     throw new IllegalArgumentException(
182         annotation
183             + " must be a Component, Subcomponent, ProductionComponent, "
184             + "or ProductionSubcomponent annotation");
185   }
186 
187   /** Creates a fictional component annotation representing a module. */
fromModuleAnnotation(ModuleAnnotation moduleAnnotation)188   static ComponentAnnotation fromModuleAnnotation(ModuleAnnotation moduleAnnotation) {
189     return new AutoValue_ComponentAnnotation_FictionalComponentAnnotation(moduleAnnotation);
190   }
191 
192   /** The root component annotation types. */
rootComponentAnnotations()193   static ImmutableSet<Class<? extends Annotation>> rootComponentAnnotations() {
194     return ROOT_COMPONENT_ANNOTATIONS;
195   }
196 
197   /** The subcomponent annotation types. */
subcomponentAnnotations()198   static ImmutableSet<Class<? extends Annotation>> subcomponentAnnotations() {
199     return SUBCOMPONENT_ANNOTATIONS;
200   }
201 
202   /** All component annotation types. */
allComponentAnnotations()203   static ImmutableSet<Class<? extends Annotation>> allComponentAnnotations() {
204     return ALL_COMPONENT_ANNOTATIONS;
205   }
206 
207   /**
208    * An actual component annotation.
209    *
210    * @see FictionalComponentAnnotation
211    */
212   @AutoValue
213   abstract static class RealComponentAnnotation extends ComponentAnnotation {
214 
215     @Override
216     @Memoized
dependencyValues()217     ImmutableList<AnnotationValue> dependencyValues() {
218       return isSubcomponent() ? ImmutableList.of() : getAnnotationValues("dependencies");
219     }
220 
221     @Override
222     @Memoized
dependencyTypes()223     ImmutableList<TypeMirror> dependencyTypes() {
224       return super.dependencyTypes();
225     }
226 
227     @Override
228     @Memoized
dependencies()229     ImmutableList<TypeElement> dependencies() {
230       return super.dependencies();
231     }
232 
233     @Override
isRealComponent()234     boolean isRealComponent() {
235       return true;
236     }
237 
238     @Override
239     @Memoized
moduleValues()240     ImmutableList<AnnotationValue> moduleValues() {
241       return getAnnotationValues("modules");
242     }
243 
244     @Override
245     @Memoized
moduleTypes()246     ImmutableList<TypeMirror> moduleTypes() {
247       return super.moduleTypes();
248     }
249 
250     @Override
251     @Memoized
modules()252     ImmutableSet<TypeElement> modules() {
253       return super.modules();
254     }
255 
builder()256     static Builder builder() {
257       return new AutoValue_ComponentAnnotation_RealComponentAnnotation.Builder();
258     }
259 
260     @AutoValue.Builder
261     interface Builder {
annotation(AnnotationMirror annotation)262       Builder annotation(AnnotationMirror annotation);
263 
isSubcomponent(boolean isSubcomponent)264       Builder isSubcomponent(boolean isSubcomponent);
265 
isProduction(boolean isProduction)266       Builder isProduction(boolean isProduction);
267 
build()268       RealComponentAnnotation build();
269     }
270   }
271 
272   /**
273    * A fictional component annotation used to represent modules or other collections of bindings as
274    * a component.
275    */
276   @AutoValue
277   abstract static class FictionalComponentAnnotation extends ComponentAnnotation {
278 
279     @Override
annotation()280     AnnotationMirror annotation() {
281       return moduleAnnotation().annotation();
282     }
283 
284     @Override
isSubcomponent()285     boolean isSubcomponent() {
286       return false;
287     }
288 
289     @Override
isProduction()290     boolean isProduction() {
291       return moduleAnnotation().annotationClass().equals(ProducerModule.class);
292     }
293 
294     @Override
isRealComponent()295     boolean isRealComponent() {
296       return false;
297     }
298 
299     @Override
dependencyValues()300     ImmutableList<AnnotationValue> dependencyValues() {
301       return ImmutableList.of();
302     }
303 
304     @Override
moduleValues()305     ImmutableList<AnnotationValue> moduleValues() {
306       return moduleAnnotation().includesAsAnnotationValues();
307     }
308 
309     @Override
310     @Memoized
moduleTypes()311     ImmutableList<TypeMirror> moduleTypes() {
312       return super.moduleTypes();
313     }
314 
315     @Override
316     @Memoized
modules()317     ImmutableSet<TypeElement> modules() {
318       return super.modules();
319     }
320 
moduleAnnotation()321     abstract ModuleAnnotation moduleAnnotation();
322   }
323 }
324