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