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