• 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.asTypeElement;
21 import static com.google.common.base.Preconditions.checkArgument;
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.common.MoreTypes;
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 dagger.Module;
32 import dagger.producers.ProducerModule;
33 import java.lang.annotation.Annotation;
34 import java.util.Optional;
35 import javax.lang.model.element.AnnotationMirror;
36 import javax.lang.model.element.AnnotationValue;
37 import javax.lang.model.element.TypeElement;
38 
39 /** A {@code @Module} or {@code @ProducerModule} annotation. */
40 @AutoValue
41 abstract class ModuleAnnotation {
42   private static final ImmutableSet<Class<? extends Annotation>> MODULE_ANNOTATIONS =
43       ImmutableSet.of(Module.class, ProducerModule.class);
44 
45   /** The annotation itself. */
46   // This does not use AnnotationMirrors.equivalence() because we want the actual annotation
47   // instance.
annotation()48   abstract AnnotationMirror annotation();
49 
50   /** The type of the annotation. */
51   @Memoized
annotationClass()52   Class<?> annotationClass() {
53     try {
54       return Class.forName(
55           asTypeElement(annotation().getAnnotationType()).getQualifiedName().toString());
56     } catch (ClassNotFoundException e) {
57       AssertionError assertionError = new AssertionError();
58       assertionError.initCause(e);
59       throw assertionError;
60     }
61   }
62 
63   /**
64    * The types specified in the {@code includes} attribute.
65    *
66    * @throws IllegalArgumentException if any of the values are error types
67    */
68   @Memoized
includes()69   ImmutableList<TypeElement> includes() {
70     return includesAsAnnotationValues().stream()
71         .map(MoreAnnotationValues::asType)
72         .map(MoreTypes::asTypeElement)
73         .collect(toImmutableList());
74   }
75 
76   /** The values specified in the {@code includes} attribute. */
77   @Memoized
includesAsAnnotationValues()78   ImmutableList<AnnotationValue> includesAsAnnotationValues() {
79     return asAnnotationValues(getAnnotationValue(annotation(), "includes"));
80   }
81 
82   /**
83    * The types specified in the {@code subcomponents} attribute.
84    *
85    * @throws IllegalArgumentException if any of the values are error types
86    */
87   @Memoized
subcomponents()88   ImmutableList<TypeElement> subcomponents() {
89     return subcomponentsAsAnnotationValues().stream()
90         .map(MoreAnnotationValues::asType)
91         .map(MoreTypes::asTypeElement)
92         .collect(toImmutableList());
93   }
94 
95   /** The values specified in the {@code subcomponents} attribute. */
96   @Memoized
subcomponentsAsAnnotationValues()97   ImmutableList<AnnotationValue> subcomponentsAsAnnotationValues() {
98     return asAnnotationValues(getAnnotationValue(annotation(), "subcomponents"));
99   }
100 
101   /** Returns {@code true} if the argument is a {@code @Module} or {@code @ProducerModule}. */
isModuleAnnotation(AnnotationMirror annotation)102   static boolean isModuleAnnotation(AnnotationMirror annotation) {
103     return MODULE_ANNOTATIONS.stream()
104         .map(Class::getCanonicalName)
105         .anyMatch(asTypeElement(annotation.getAnnotationType()).getQualifiedName()::contentEquals);
106   }
107 
108   /** The module annotation types. */
moduleAnnotations()109   static ImmutableSet<Class<? extends Annotation>> moduleAnnotations() {
110     return MODULE_ANNOTATIONS;
111   }
112 
113   /**
114    * Creates an object that represents a {@code @Module} or {@code @ProducerModule}.
115    *
116    * @throws IllegalArgumentException if {@link #isModuleAnnotation(AnnotationMirror)} returns
117    *     {@code false}
118    */
moduleAnnotation(AnnotationMirror annotation)119   static ModuleAnnotation moduleAnnotation(AnnotationMirror annotation) {
120     checkArgument(
121         isModuleAnnotation(annotation),
122         "%s is not a Module or ProducerModule annotation",
123         annotation);
124     return new AutoValue_ModuleAnnotation(annotation);
125   }
126 
127   /**
128    * Returns an object representing the {@code @Module} or {@code @ProducerModule} annotation if one
129    * annotates {@code typeElement}.
130    */
moduleAnnotation(TypeElement typeElement)131   static Optional<ModuleAnnotation> moduleAnnotation(TypeElement typeElement) {
132     return getAnyAnnotation(typeElement, Module.class, ProducerModule.class)
133         .map(ModuleAnnotation::moduleAnnotation);
134   }
135 }
136