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.base; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 21 22 import androidx.room.compiler.processing.XAnnotation; 23 import androidx.room.compiler.processing.XTypeElement; 24 import com.google.common.collect.ImmutableSet; 25 import com.google.common.collect.Sets; 26 import com.squareup.javapoet.ClassName; 27 import dagger.internal.codegen.javapoet.TypeNames; 28 import java.util.EnumSet; 29 import java.util.Optional; 30 import java.util.Set; 31 32 /** Enumeration of the kinds of modules. */ 33 public enum ModuleKind { 34 /** {@code @Module} */ 35 MODULE(TypeNames.MODULE), 36 37 /** {@code @ProducerModule} */ 38 PRODUCER_MODULE(TypeNames.PRODUCER_MODULE); 39 40 /** Returns the annotations for modules of the given kinds. */ annotationsFor(Set<ModuleKind> kinds)41 private static ImmutableSet<ClassName> annotationsFor(Set<ModuleKind> kinds) { 42 return kinds.stream().map(ModuleKind::annotation).collect(toImmutableSet()); 43 } 44 45 /** 46 * Returns the kind of an annotated element if it is annotated with one of the module {@linkplain 47 * #annotation() annotations}. 48 * 49 * @throws IllegalArgumentException if the element is annotated with more than one of the module 50 * annotations 51 */ forAnnotatedElement(XTypeElement element)52 public static Optional<ModuleKind> forAnnotatedElement(XTypeElement element) { 53 Set<ModuleKind> kinds = EnumSet.noneOf(ModuleKind.class); 54 for (ModuleKind kind : values()) { 55 if (element.hasAnnotation(kind.annotation())) { 56 kinds.add(kind); 57 } 58 } 59 60 if (kinds.size() > 1) { 61 throw new IllegalArgumentException( 62 element + " cannot be annotated with more than one of " + annotationsFor(kinds)); 63 } 64 return kinds.stream().findAny(); 65 } 66 checkIsModule(XTypeElement moduleElement)67 public static void checkIsModule(XTypeElement moduleElement) { 68 // If the type element is a Kotlin companion object, then assert it is a module if its enclosing 69 // type is a module. 70 if (moduleElement.isCompanionObject()) { 71 checkArgument(forAnnotatedElement(moduleElement.getEnclosingTypeElement()).isPresent()); 72 } else { 73 checkArgument(forAnnotatedElement(moduleElement).isPresent()); 74 } 75 } 76 77 private final ClassName moduleAnnotation; 78 ModuleKind(ClassName moduleAnnotation)79 ModuleKind(ClassName moduleAnnotation) { 80 this.moduleAnnotation = moduleAnnotation; 81 } 82 83 /** 84 * Returns the annotation mirror for this module kind on the given type. 85 * 86 * @throws IllegalArgumentException if the annotation is not present on the type 87 */ getModuleAnnotation(XTypeElement element)88 public XAnnotation getModuleAnnotation(XTypeElement element) { 89 checkArgument( 90 element.hasAnnotation(moduleAnnotation), 91 "annotation %s is not present on type %s", 92 moduleAnnotation, 93 element); 94 return element.getAnnotation(moduleAnnotation); 95 } 96 97 /** Returns the annotation that marks a module of this kind. */ annotation()98 public ClassName annotation() { 99 return moduleAnnotation; 100 } 101 102 /** Returns the kinds of modules that a module of this kind is allowed to include. */ legalIncludedModuleKinds()103 public ImmutableSet<ModuleKind> legalIncludedModuleKinds() { 104 switch (this) { 105 case MODULE: 106 return Sets.immutableEnumSet(MODULE); 107 case PRODUCER_MODULE: 108 return Sets.immutableEnumSet(MODULE, PRODUCER_MODULE); 109 } 110 throw new AssertionError(this); 111 } 112 } 113