1 /* 2 * Copyright (C) 2014 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.common.base.Preconditions.checkArgument; 20 import static com.google.common.base.Preconditions.checkNotNull; 21 import static com.google.common.collect.Iterables.consumingIterable; 22 import static dagger.internal.codegen.ComponentAnnotation.subcomponentAnnotation; 23 import static dagger.internal.codegen.ComponentCreatorAnnotation.subcomponentCreatorAnnotations; 24 import static dagger.internal.codegen.ModuleAnnotation.moduleAnnotation; 25 import static dagger.internal.codegen.MoreAnnotationMirrors.getTypeListValue; 26 import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent; 27 import static javax.lang.model.util.ElementFilter.typesIn; 28 29 import com.google.auto.common.MoreElements; 30 import com.google.auto.common.MoreTypes; 31 import com.google.common.collect.ImmutableList; 32 import com.google.common.collect.ImmutableSet; 33 import com.google.common.collect.Iterables; 34 import com.google.common.collect.Sets; 35 import dagger.Component; 36 import dagger.Module; 37 import dagger.internal.codegen.langmodel.DaggerElements; 38 import dagger.internal.codegen.langmodel.DaggerTypes; 39 import java.lang.annotation.Annotation; 40 import java.util.ArrayDeque; 41 import java.util.List; 42 import java.util.Optional; 43 import java.util.Queue; 44 import java.util.Set; 45 import javax.lang.model.element.AnnotationMirror; 46 import javax.lang.model.element.Element; 47 import javax.lang.model.element.TypeElement; 48 import javax.lang.model.type.DeclaredType; 49 import javax.lang.model.type.TypeKind; 50 import javax.lang.model.type.TypeMirror; 51 52 /** 53 * Utility methods related to dagger configuration annotations (e.g.: {@link Component} 54 * and {@link Module}). 55 */ 56 final class ConfigurationAnnotations { 57 getSubcomponentCreator(TypeElement subcomponent)58 static Optional<TypeElement> getSubcomponentCreator(TypeElement subcomponent) { 59 checkArgument(subcomponentAnnotation(subcomponent).isPresent()); 60 for (TypeElement nestedType : typesIn(subcomponent.getEnclosedElements())) { 61 if (isSubcomponentCreator(nestedType)) { 62 return Optional.of(nestedType); 63 } 64 } 65 return Optional.empty(); 66 } 67 isSubcomponentCreator(Element element)68 static boolean isSubcomponentCreator(Element element) { 69 return isAnyAnnotationPresent(element, subcomponentCreatorAnnotations()); 70 } 71 72 // Dagger 1 support. getModuleInjects(AnnotationMirror moduleAnnotation)73 static ImmutableList<TypeMirror> getModuleInjects(AnnotationMirror moduleAnnotation) { 74 checkNotNull(moduleAnnotation); 75 return getTypeListValue(moduleAnnotation, "injects"); 76 } 77 78 /** Returns the first type that specifies this' nullability, or empty if none. */ getNullableType(Element element)79 static Optional<DeclaredType> getNullableType(Element element) { 80 List<? extends AnnotationMirror> mirrors = element.getAnnotationMirrors(); 81 for (AnnotationMirror mirror : mirrors) { 82 if (mirror.getAnnotationType().asElement().getSimpleName().contentEquals("Nullable")) { 83 return Optional.of(mirror.getAnnotationType()); 84 } 85 } 86 return Optional.empty(); 87 } 88 89 /** 90 * Returns the full set of modules transitively {@linkplain Module#includes included} from the 91 * given seed modules. If a module is malformed and a type listed in {@link Module#includes} is 92 * not annotated with {@link Module}, it is ignored. 93 * 94 * @deprecated Use {@link ComponentDescriptor#modules()}. 95 */ 96 @Deprecated getTransitiveModules( DaggerTypes types, DaggerElements elements, Iterable<TypeElement> seedModules)97 static ImmutableSet<TypeElement> getTransitiveModules( 98 DaggerTypes types, DaggerElements elements, Iterable<TypeElement> seedModules) { 99 TypeMirror objectType = elements.getTypeElement(Object.class).asType(); 100 Queue<TypeElement> moduleQueue = new ArrayDeque<>(); 101 Iterables.addAll(moduleQueue, seedModules); 102 Set<TypeElement> moduleElements = Sets.newLinkedHashSet(); 103 for (TypeElement moduleElement : consumingIterable(moduleQueue)) { 104 moduleAnnotation(moduleElement) 105 .ifPresent( 106 moduleAnnotation -> { 107 ImmutableSet.Builder<TypeElement> moduleDependenciesBuilder = 108 ImmutableSet.builder(); 109 moduleDependenciesBuilder.addAll(moduleAnnotation.includes()); 110 // We don't recur on the parent class because we don't want the parent class as a 111 // root that the component depends on, and also because we want the dependencies 112 // rooted against this element, not the parent. 113 addIncludesFromSuperclasses( 114 types, moduleElement, moduleDependenciesBuilder, objectType); 115 ImmutableSet<TypeElement> moduleDependencies = moduleDependenciesBuilder.build(); 116 moduleElements.add(moduleElement); 117 for (TypeElement dependencyType : moduleDependencies) { 118 if (!moduleElements.contains(dependencyType)) { 119 moduleQueue.add(dependencyType); 120 } 121 } 122 }); 123 } 124 return ImmutableSet.copyOf(moduleElements); 125 } 126 127 /** Returns the enclosed types annotated with the given annotation. */ enclosedAnnotatedTypes( TypeElement typeElement, Class<? extends Annotation> annotation)128 static ImmutableList<DeclaredType> enclosedAnnotatedTypes( 129 TypeElement typeElement, Class<? extends Annotation> annotation) { 130 final ImmutableList.Builder<DeclaredType> builders = ImmutableList.builder(); 131 for (TypeElement element : typesIn(typeElement.getEnclosedElements())) { 132 if (MoreElements.isAnnotationPresent(element, annotation)) { 133 builders.add(MoreTypes.asDeclared(element.asType())); 134 } 135 } 136 return builders.build(); 137 } 138 139 /** Traverses includes from superclasses and adds them into the builder. */ addIncludesFromSuperclasses( DaggerTypes types, TypeElement element, ImmutableSet.Builder<TypeElement> builder, TypeMirror objectType)140 private static void addIncludesFromSuperclasses( 141 DaggerTypes types, 142 TypeElement element, 143 ImmutableSet.Builder<TypeElement> builder, 144 TypeMirror objectType) { 145 // Also add the superclass to the queue, in case any @Module definitions were on that. 146 TypeMirror superclass = element.getSuperclass(); 147 while (!types.isSameType(objectType, superclass) 148 && superclass.getKind().equals(TypeKind.DECLARED)) { 149 element = MoreElements.asType(types.asElement(superclass)); 150 moduleAnnotation(element) 151 .ifPresent(moduleAnnotation -> builder.addAll(moduleAnnotation.includes())); 152 superclass = element.getSuperclass(); 153 } 154 } 155 ConfigurationAnnotations()156 private ConfigurationAnnotations() {} 157 } 158