Home | History | Annotate | Download | only in codegen
      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 
     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 
     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 
     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 
     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 
     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. */
     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    */
    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
    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. */
    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 
    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
    213     protected Optional<AnnotationMirror> defaultAction(TypeMirror e, Void p) {
    214       return Optional.absent();
    215     }
    216 
    217     @Override
    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. */
    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 
    240   private ConfigurationAnnotations() {}
    241 }
    242