1 /* 2 * Copyright (C) 2014 Google, Inc. 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 package dagger.internal.codegen; 17 18 import com.google.auto.common.MoreElements; 19 import com.google.auto.common.MoreTypes; 20 import com.google.common.base.Function; 21 import com.google.common.base.Optional; 22 import com.google.common.collect.FluentIterable; 23 import com.google.common.collect.ImmutableList; 24 import com.google.common.collect.ImmutableSet; 25 import com.google.common.collect.Iterables; 26 import com.google.common.collect.Sets; 27 import dagger.Component; 28 import dagger.Module; 29 import dagger.Subcomponent; 30 import dagger.producers.ProducerModule; 31 import dagger.producers.ProductionComponent; 32 import java.lang.annotation.Annotation; 33 import java.util.ArrayDeque; 34 import java.util.List; 35 import java.util.Queue; 36 import java.util.Set; 37 import javax.lang.model.element.AnnotationMirror; 38 import javax.lang.model.element.AnnotationValue; 39 import javax.lang.model.element.AnnotationValueVisitor; 40 import javax.lang.model.element.Element; 41 import javax.lang.model.element.TypeElement; 42 import javax.lang.model.type.DeclaredType; 43 import javax.lang.model.type.TypeKind; 44 import javax.lang.model.type.TypeMirror; 45 import javax.lang.model.util.ElementFilter; 46 import javax.lang.model.util.Elements; 47 import javax.lang.model.util.SimpleAnnotationValueVisitor6; 48 import javax.lang.model.util.SimpleTypeVisitor6; 49 import javax.lang.model.util.Types; 50 51 import static com.google.auto.common.AnnotationMirrors.getAnnotationValue; 52 import static com.google.auto.common.MoreElements.getAnnotationMirror; 53 import static com.google.common.base.Preconditions.checkNotNull; 54 55 /** 56 * Utility methods related to dagger configuration annotations (e.g.: {@link Component} 57 * and {@link Module}). 58 * 59 * @author Gregory Kick 60 */ 61 final class ConfigurationAnnotations { 62 isComponent(TypeElement componentDefinitionType)63 static boolean isComponent(TypeElement componentDefinitionType) { 64 return MoreElements.isAnnotationPresent(componentDefinitionType, Component.class) 65 || MoreElements.isAnnotationPresent(componentDefinitionType, ProductionComponent.class); 66 } 67 68 private static final String MODULES_ATTRIBUTE = "modules"; 69 getComponentModules(AnnotationMirror componentAnnotation)70 static ImmutableList<TypeMirror> getComponentModules(AnnotationMirror componentAnnotation) { 71 checkNotNull(componentAnnotation); 72 return convertClassArrayToListOfTypes(componentAnnotation, MODULES_ATTRIBUTE); 73 } 74 75 private static final String DEPENDENCIES_ATTRIBUTE = "dependencies"; 76 getComponentDependencies(AnnotationMirror componentAnnotation)77 static ImmutableList<TypeMirror> getComponentDependencies(AnnotationMirror componentAnnotation) { 78 checkNotNull(componentAnnotation); 79 return convertClassArrayToListOfTypes(componentAnnotation, DEPENDENCIES_ATTRIBUTE); 80 } 81 82 private static final String INCLUDES_ATTRIBUTE = "includes"; 83 getModuleIncludes(AnnotationMirror moduleAnnotation)84 static ImmutableList<TypeMirror> getModuleIncludes(AnnotationMirror moduleAnnotation) { 85 checkNotNull(moduleAnnotation); 86 return convertClassArrayToListOfTypes(moduleAnnotation, INCLUDES_ATTRIBUTE); 87 } 88 89 private static final String INJECTS_ATTRIBUTE = "injects"; 90 getModuleInjects(AnnotationMirror moduleAnnotation)91 static ImmutableList<TypeMirror> getModuleInjects(AnnotationMirror moduleAnnotation) { 92 checkNotNull(moduleAnnotation); 93 return convertClassArrayToListOfTypes(moduleAnnotation, INJECTS_ATTRIBUTE); 94 } 95 96 /** Returns the first type that specifies this' nullability, or absent if none. */ getNullableType(Element element)97 static Optional<DeclaredType> getNullableType(Element element) { 98 List<? extends AnnotationMirror> mirrors = element.getAnnotationMirrors(); 99 for (AnnotationMirror mirror : mirrors) { 100 if (mirror.getAnnotationType().asElement().getSimpleName().toString().equals("Nullable")) { 101 return Optional.of(mirror.getAnnotationType()); 102 } 103 } 104 return Optional.absent(); 105 } 106 107 /** 108 * Extracts the list of types that is the value of the annotation member {@code elementName} of 109 * {@code annotationMirror}. 110 * 111 * @throws IllegalArgumentException if no such member exists on {@code annotationMirror}, or it 112 * exists but is not an array 113 * @throws TypeNotPresentException if any of the values cannot be converted to a type 114 */ convertClassArrayToListOfTypes( AnnotationMirror annotationMirror, String elementName)115 static ImmutableList<TypeMirror> convertClassArrayToListOfTypes( 116 AnnotationMirror annotationMirror, String elementName) { 117 return TO_LIST_OF_TYPES.visit(getAnnotationValue(annotationMirror, elementName), elementName); 118 } 119 120 private static final AnnotationValueVisitor<ImmutableList<TypeMirror>, String> TO_LIST_OF_TYPES = 121 new SimpleAnnotationValueVisitor6<ImmutableList<TypeMirror>, String>() { 122 @Override 123 public ImmutableList<TypeMirror> visitArray( 124 List<? extends AnnotationValue> vals, String elementName) { 125 return FluentIterable.from(vals) 126 .transform( 127 new Function<AnnotationValue, TypeMirror>() { 128 @Override 129 public TypeMirror apply(AnnotationValue typeValue) { 130 return TO_TYPE.visit(typeValue); 131 } 132 }) 133 .toList(); 134 } 135 136 @Override 137 protected ImmutableList<TypeMirror> defaultAction(Object o, String elementName) { 138 throw new IllegalArgumentException(elementName + " is not an array: " + o); 139 } 140 }; 141 142 private static final AnnotationValueVisitor<TypeMirror, Void> TO_TYPE = 143 new SimpleAnnotationValueVisitor6<TypeMirror, Void>() { 144 @Override 145 public TypeMirror visitType(TypeMirror t, Void p) { 146 return t; 147 } 148 149 @Override 150 protected TypeMirror defaultAction(Object o, Void p) { 151 throw new TypeNotPresentException(o.toString(), null); 152 } 153 }; 154 155 /** 156 * Returns the full set of modules transitively {@linkplain Module#includes included} from the 157 * given seed modules. If a module is malformed and a type listed in {@link Module#includes} 158 * is not annotated with {@link Module}, it is ignored. 159 * 160 * @deprecated Use {@link ComponentDescriptor#transitiveModules}. 161 */ 162 @Deprecated getTransitiveModules( Types types, Elements elements, Iterable<TypeElement> seedModules)163 static ImmutableSet<TypeElement> getTransitiveModules( 164 Types types, Elements elements, Iterable<TypeElement> seedModules) { 165 TypeMirror objectType = elements.getTypeElement(Object.class.getCanonicalName()).asType(); 166 Queue<TypeElement> moduleQueue = new ArrayDeque<>(); 167 Iterables.addAll(moduleQueue, seedModules); 168 Set<TypeElement> moduleElements = Sets.newLinkedHashSet(); 169 for (TypeElement moduleElement = moduleQueue.poll(); 170 moduleElement != null; 171 moduleElement = moduleQueue.poll()) { 172 Optional<AnnotationMirror> moduleMirror = getAnnotationMirror(moduleElement, Module.class) 173 .or(getAnnotationMirror(moduleElement, ProducerModule.class)); 174 if (moduleMirror.isPresent()) { 175 ImmutableSet.Builder<TypeElement> moduleDependenciesBuilder = ImmutableSet.builder(); 176 moduleDependenciesBuilder.addAll( 177 MoreTypes.asTypeElements(getModuleIncludes(moduleMirror.get()))); 178 // (note: we don't recurse on the parent class because we don't want the parent class as a 179 // root that the component depends on, and also because we want the dependencies rooted 180 // against this element, not the parent.) 181 addIncludesFromSuperclasses(types, moduleElement, moduleDependenciesBuilder, objectType); 182 ImmutableSet<TypeElement> moduleDependencies = moduleDependenciesBuilder.build(); 183 moduleElements.add(moduleElement); 184 for (TypeElement dependencyType : moduleDependencies) { 185 if (!moduleElements.contains(dependencyType)) { 186 moduleQueue.add(dependencyType); 187 } 188 } 189 } 190 } 191 return ImmutableSet.copyOf(moduleElements); 192 } 193 194 /** Returns the enclosed elements annotated with the given annotation type. */ enclosedBuilders(TypeElement typeElement, final Class<? extends Annotation> annotation)195 static ImmutableList<DeclaredType> enclosedBuilders(TypeElement typeElement, 196 final Class<? extends Annotation> annotation) { 197 final ImmutableList.Builder<DeclaredType> builders = ImmutableList.builder(); 198 for (TypeElement element : ElementFilter.typesIn(typeElement.getEnclosedElements())) { 199 if (MoreElements.isAnnotationPresent(element, annotation)) { 200 builders.add(MoreTypes.asDeclared(element.asType())); 201 } 202 } 203 return builders.build(); 204 } 205 isSubcomponentType(TypeMirror type)206 static boolean isSubcomponentType(TypeMirror type) { 207 return type.accept(new SubcomponentDetector(), null).isPresent(); 208 } 209 210 private static final class SubcomponentDetector 211 extends SimpleTypeVisitor6<Optional<AnnotationMirror>, Void> { 212 @Override defaultAction(TypeMirror e, Void p)213 protected Optional<AnnotationMirror> defaultAction(TypeMirror e, Void p) { 214 return Optional.absent(); 215 } 216 217 @Override visitDeclared(DeclaredType t, Void p)218 public Optional<AnnotationMirror> visitDeclared(DeclaredType t, Void p) { 219 return MoreElements.getAnnotationMirror(t.asElement(), Subcomponent.class); 220 } 221 } 222 223 /** Traverses includes from superclasses and adds them into the builder. */ addIncludesFromSuperclasses(Types types, TypeElement element, ImmutableSet.Builder<TypeElement> builder, TypeMirror objectType)224 private static void addIncludesFromSuperclasses(Types types, TypeElement element, 225 ImmutableSet.Builder<TypeElement> builder, TypeMirror objectType) { 226 // Also add the superclass to the queue, in case any @Module definitions were on that. 227 TypeMirror superclass = element.getSuperclass(); 228 while (!types.isSameType(objectType, superclass) 229 && superclass.getKind().equals(TypeKind.DECLARED)) { 230 element = MoreElements.asType(types.asElement(superclass)); 231 Optional<AnnotationMirror> moduleMirror = getAnnotationMirror(element, Module.class) 232 .or(getAnnotationMirror(element, ProducerModule.class)); 233 if (moduleMirror.isPresent()) { 234 builder.addAll(MoreTypes.asTypeElements(getModuleIncludes(moduleMirror.get()))); 235 } 236 superclass = element.getSuperclass(); 237 } 238 } 239 ConfigurationAnnotations()240 private ConfigurationAnnotations() {} 241 } 242