• 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 dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
20 import static dagger.internal.codegen.xprocessing.XAnnotations.getClassName;
21 import static dagger.internal.codegen.xprocessing.XElements.getAnyAnnotation;
22 
23 import androidx.room.compiler.processing.XAnnotation;
24 import androidx.room.compiler.processing.XElement;
25 import androidx.room.compiler.processing.XType;
26 import androidx.room.compiler.processing.XTypeElement;
27 import com.google.auto.value.AutoValue;
28 import com.google.auto.value.extension.memoized.Memoized;
29 import com.google.common.collect.ImmutableList;
30 import com.google.common.collect.ImmutableSet;
31 import com.squareup.javapoet.ClassName;
32 import dagger.internal.codegen.javapoet.TypeNames;
33 import java.util.Collection;
34 import java.util.Optional;
35 
36 /**
37  * A {@code @Component}, {@code @Subcomponent}, {@code @ProductionComponent}, or
38  * {@code @ProductionSubcomponent} annotation, or a {@code @Module} or {@code @ProducerModule}
39  * annotation that is being treated as a component annotation when validating full binding graphs
40  * for modules.
41  */
42 @AutoValue
43 public abstract class ComponentAnnotation {
44   /** The root component annotation types. */
45   private static final ImmutableSet<ClassName> ROOT_COMPONENT_ANNOTATIONS =
46       ImmutableSet.of(TypeNames.COMPONENT, TypeNames.PRODUCTION_COMPONENT);
47 
48   /** The subcomponent annotation types. */
49   private static final ImmutableSet<ClassName> SUBCOMPONENT_ANNOTATIONS =
50       ImmutableSet.of(TypeNames.SUBCOMPONENT, TypeNames.PRODUCTION_SUBCOMPONENT);
51 
52   /** All component annotation types. */
53   private static final ImmutableSet<ClassName> ALL_COMPONENT_ANNOTATIONS =
54       ImmutableSet.<ClassName>builder()
55           .addAll(ROOT_COMPONENT_ANNOTATIONS)
56           .addAll(SUBCOMPONENT_ANNOTATIONS)
57           .build();
58 
59   /** All component and creator annotation types. */
60   private static final ImmutableSet<ClassName> ALL_COMPONENT_AND_CREATOR_ANNOTATIONS =
61       ImmutableSet.<ClassName>builder()
62           .addAll(ALL_COMPONENT_ANNOTATIONS)
63           .addAll(ComponentCreatorAnnotation.allCreatorAnnotations())
64           .build();
65 
66   /** All production annotation types. */
67   private static final ImmutableSet<ClassName> PRODUCTION_ANNOTATIONS =
68       ImmutableSet.of(
69           TypeNames.PRODUCTION_COMPONENT,
70           TypeNames.PRODUCTION_SUBCOMPONENT,
71           TypeNames.PRODUCER_MODULE);
72 
73   private XAnnotation annotation;
74 
75   /** The annotation itself. */
annotation()76   public final XAnnotation annotation() {
77     return annotation;
78   }
79 
80   /** Returns the {@link ClassName} name of the annotation. */
className()81   public abstract ClassName className();
82 
83   /** The simple name of the annotation type. */
simpleName()84   public final String simpleName() {
85     return className().simpleName();
86   }
87 
88   /**
89    * Returns {@code true} if the annotation is a {@code @Subcomponent} or
90    * {@code @ProductionSubcomponent}.
91    */
isSubcomponent()92   public final boolean isSubcomponent() {
93     return SUBCOMPONENT_ANNOTATIONS.contains(className());
94   }
95 
96   /**
97    * Returns {@code true} if the annotation is a {@code @ProductionComponent},
98    * {@code @ProductionSubcomponent}, or {@code @ProducerModule}.
99    */
isProduction()100   public final boolean isProduction() {
101     return PRODUCTION_ANNOTATIONS.contains(className());
102   }
103 
104   /**
105    * Returns {@code true} if the annotation is a real component annotation and not a module
106    * annotation.
107    */
isRealComponent()108   public final boolean isRealComponent() {
109     return ALL_COMPONENT_ANNOTATIONS.contains(className());
110   }
111 
112   /** The types listed as {@code dependencies}. */
113   @Memoized
dependencyTypes()114   public ImmutableList<XType> dependencyTypes() {
115     return isRootComponent()
116         ? ImmutableList.copyOf(annotation.getAsTypeList("dependencies"))
117         : ImmutableList.of();
118   }
119 
120   /**
121    * The types listed as {@code dependencies}.
122    *
123    * @throws IllegalArgumentException if any of {@link #dependencyTypes()} are error types
124    */
125   @Memoized
dependencies()126   public ImmutableSet<XTypeElement> dependencies() {
127     return dependencyTypes().stream().map(XType::getTypeElement).collect(toImmutableSet());
128   }
129 
130   /**
131    * The types listed as {@code modules}.
132    *
133    * @throws IllegalArgumentException if any module is an error type.
134    */
135   @Memoized
modules()136   public ImmutableSet<XTypeElement> modules() {
137     return annotation.getAsTypeList(isRealComponent() ? "modules" : "includes").stream()
138         .map(XType::getTypeElement)
139         .collect(toImmutableSet());
140   }
141 
isRootComponent()142   private final boolean isRootComponent() {
143     return ROOT_COMPONENT_ANNOTATIONS.contains(className());
144   }
145 
146   /**
147    * Returns an object representing a root component annotation, not a subcomponent annotation, if
148    * one is present on {@code typeElement}.
149    */
rootComponentAnnotation( XTypeElement typeElement, DaggerSuperficialValidation superficialValidation)150   public static Optional<ComponentAnnotation> rootComponentAnnotation(
151       XTypeElement typeElement, DaggerSuperficialValidation superficialValidation) {
152     return anyComponentAnnotation(typeElement, ROOT_COMPONENT_ANNOTATIONS, superficialValidation);
153   }
154 
155   /**
156    * Returns an object representing a subcomponent annotation, if one is present on {@code
157    * typeElement}.
158    */
subcomponentAnnotation( XTypeElement typeElement, DaggerSuperficialValidation superficialValidation)159   public static Optional<ComponentAnnotation> subcomponentAnnotation(
160       XTypeElement typeElement, DaggerSuperficialValidation superficialValidation) {
161     return anyComponentAnnotation(typeElement, SUBCOMPONENT_ANNOTATIONS, superficialValidation);
162   }
163 
164   /**
165    * Returns an object representing a root component or subcomponent annotation, if one is present
166    * on {@code typeElement}.
167    */
anyComponentAnnotation( XElement element, DaggerSuperficialValidation superficialValidation)168   public static Optional<ComponentAnnotation> anyComponentAnnotation(
169       XElement element, DaggerSuperficialValidation superficialValidation) {
170     return anyComponentAnnotation(element, ALL_COMPONENT_ANNOTATIONS, superficialValidation);
171   }
172 
anyComponentAnnotation( XElement element, Collection<ClassName> annotations, DaggerSuperficialValidation superficialValidation)173   private static Optional<ComponentAnnotation> anyComponentAnnotation(
174       XElement element,
175       Collection<ClassName> annotations,
176       DaggerSuperficialValidation superficialValidation) {
177     return getAnyAnnotation(element, annotations)
178         .map(
179             annotation -> {
180               superficialValidation.validateAnnotationOf(element, annotation);
181               return create(annotation);
182             });
183   }
184 
185   /** Returns {@code true} if the argument is a component annotation. */
isComponentAnnotation(XAnnotation annotation)186   public static boolean isComponentAnnotation(XAnnotation annotation) {
187     return ALL_COMPONENT_ANNOTATIONS.contains(getClassName(annotation));
188   }
189 
190   /** Creates a fictional component annotation representing a module. */
fromModuleAnnotation(ModuleAnnotation moduleAnnotation)191   public static ComponentAnnotation fromModuleAnnotation(ModuleAnnotation moduleAnnotation) {
192     return create(moduleAnnotation.annotation());
193   }
194 
create(XAnnotation annotation)195   private static ComponentAnnotation create(XAnnotation annotation) {
196     ComponentAnnotation componentAnnotation =
197         new AutoValue_ComponentAnnotation(getClassName(annotation));
198     componentAnnotation.annotation = annotation;
199     return componentAnnotation;
200   }
201 
202   /** The root component annotation types. */
rootComponentAnnotations()203   public static ImmutableSet<ClassName> rootComponentAnnotations() {
204     return ROOT_COMPONENT_ANNOTATIONS;
205   }
206 
207   /** The subcomponent annotation types. */
subcomponentAnnotations()208   public static ImmutableSet<ClassName> subcomponentAnnotations() {
209     return SUBCOMPONENT_ANNOTATIONS;
210   }
211 
212   /** All component annotation types. */
allComponentAnnotations()213   public static ImmutableSet<ClassName> allComponentAnnotations() {
214     return ALL_COMPONENT_ANNOTATIONS;
215   }
216 
217   /** All component and creator annotation types. */
allComponentAndCreatorAnnotations()218   public static ImmutableSet<ClassName> allComponentAndCreatorAnnotations() {
219     return ALL_COMPONENT_AND_CREATOR_ANNOTATIONS;
220   }
221 }
222