1 /* 2 * Copyright (C) 2015 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 dagger.internal.codegen.DaggerStreams.toImmutableSet; 21 import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror; 22 23 import com.google.auto.common.MoreElements; 24 import com.google.common.collect.ImmutableSet; 25 import com.google.common.collect.Sets; 26 import dagger.Module; 27 import dagger.producers.ProducerModule; 28 import java.lang.annotation.Annotation; 29 import java.util.EnumSet; 30 import java.util.Optional; 31 import java.util.Set; 32 import javax.lang.model.element.AnnotationMirror; 33 import javax.lang.model.element.TypeElement; 34 35 /** Enumeration of the kinds of modules. */ 36 enum ModuleKind { 37 /** {@code @Module} */ 38 MODULE(Module.class), 39 40 /** {@code @ProducerModule} */ 41 PRODUCER_MODULE(ProducerModule.class); 42 43 /** Returns the annotations for modules of the given kinds. */ annotationsFor(Set<ModuleKind> kinds)44 static ImmutableSet<Class<? extends Annotation>> annotationsFor(Set<ModuleKind> kinds) { 45 return kinds.stream().map(ModuleKind::annotation).collect(toImmutableSet()); 46 } 47 48 /** 49 * Returns the kind of an annotated element if it is annotated with one of the module {@linkplain 50 * #annotation() annotations}. 51 * 52 * @throws IllegalArgumentException if the element is annotated with more than one of the module 53 * annotations 54 */ forAnnotatedElement(TypeElement element)55 static Optional<ModuleKind> forAnnotatedElement(TypeElement element) { 56 Set<ModuleKind> kinds = EnumSet.noneOf(ModuleKind.class); 57 for (ModuleKind kind : values()) { 58 if (MoreElements.isAnnotationPresent(element, kind.annotation())) { 59 kinds.add(kind); 60 } 61 } 62 63 if (kinds.size() > 1) { 64 throw new IllegalArgumentException( 65 element + " cannot be annotated with more than one of " + annotationsFor(kinds)); 66 } 67 return kinds.stream().findAny(); 68 } 69 checkIsModule(TypeElement moduleElement)70 static void checkIsModule(TypeElement moduleElement) { 71 checkArgument(forAnnotatedElement(moduleElement).isPresent()); 72 } 73 74 private final Class<? extends Annotation> moduleAnnotation; 75 ModuleKind(Class<? extends Annotation> moduleAnnotation)76 ModuleKind(Class<? extends Annotation> moduleAnnotation) { 77 this.moduleAnnotation = moduleAnnotation; 78 } 79 80 /** 81 * Returns the annotation mirror for this module kind on the given type. 82 * 83 * @throws IllegalArgumentException if the annotation is not present on the type 84 */ getModuleAnnotation(TypeElement element)85 AnnotationMirror getModuleAnnotation(TypeElement element) { 86 Optional<AnnotationMirror> result = getAnnotationMirror(element, moduleAnnotation); 87 checkArgument( 88 result.isPresent(), "annotation %s is not present on type %s", moduleAnnotation, element); 89 return result.get(); 90 } 91 92 /** Returns the annotation that marks a module of this kind. */ annotation()93 Class<? extends Annotation> annotation() { 94 return moduleAnnotation; 95 } 96 97 /** Returns the kinds of modules that a module of this kind is allowed to include. */ legalIncludedModuleKinds()98 ImmutableSet<ModuleKind> legalIncludedModuleKinds() { 99 switch (this) { 100 case MODULE: 101 return Sets.immutableEnumSet(MODULE); 102 case PRODUCER_MODULE: 103 return Sets.immutableEnumSet(MODULE, PRODUCER_MODULE); 104 } 105 throw new AssertionError(this); 106 } 107 } 108