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