1 /* 2 * Copyright (C) 2019 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.auto.common.AnnotationMirrors.getAnnotationValue; 20 import static com.google.auto.common.MoreTypes.asTypeElement; 21 import static com.google.common.base.Preconditions.checkArgument; 22 import static dagger.internal.codegen.base.MoreAnnotationValues.asAnnotationValues; 23 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; 24 import static dagger.internal.codegen.langmodel.DaggerElements.getAnyAnnotation; 25 26 import com.google.auto.common.MoreTypes; 27 import com.google.auto.value.AutoValue; 28 import com.google.auto.value.extension.memoized.Memoized; 29 import com.google.common.collect.ImmutableList; 30 import com.google.common.collect.ImmutableSet; 31 import dagger.Module; 32 import dagger.producers.ProducerModule; 33 import java.lang.annotation.Annotation; 34 import java.util.Optional; 35 import javax.lang.model.element.AnnotationMirror; 36 import javax.lang.model.element.AnnotationValue; 37 import javax.lang.model.element.TypeElement; 38 39 /** A {@code @Module} or {@code @ProducerModule} annotation. */ 40 @AutoValue 41 public abstract class ModuleAnnotation { 42 private static final ImmutableSet<Class<? extends Annotation>> MODULE_ANNOTATIONS = 43 ImmutableSet.of(Module.class, ProducerModule.class); 44 45 /** The annotation itself. */ 46 // This does not use AnnotationMirrors.equivalence() because we want the actual annotation 47 // instance. annotation()48 public abstract AnnotationMirror annotation(); 49 50 /** The simple name of the annotation. */ annotationName()51 public String annotationName() { 52 return annotation().getAnnotationType().asElement().getSimpleName().toString(); 53 } 54 55 /** 56 * The types specified in the {@code includes} attribute. 57 * 58 * @throws IllegalArgumentException if any of the values are error types 59 */ 60 @Memoized includes()61 public ImmutableList<TypeElement> includes() { 62 return includesAsAnnotationValues().stream() 63 .map(MoreAnnotationValues::asType) 64 .map(MoreTypes::asTypeElement) 65 .collect(toImmutableList()); 66 } 67 68 /** The values specified in the {@code includes} attribute. */ 69 @Memoized includesAsAnnotationValues()70 public ImmutableList<AnnotationValue> includesAsAnnotationValues() { 71 return asAnnotationValues(getAnnotationValue(annotation(), "includes")); 72 } 73 74 /** 75 * The types specified in the {@code subcomponents} attribute. 76 * 77 * @throws IllegalArgumentException if any of the values are error types 78 */ 79 @Memoized subcomponents()80 public ImmutableList<TypeElement> subcomponents() { 81 return subcomponentsAsAnnotationValues().stream() 82 .map(MoreAnnotationValues::asType) 83 .map(MoreTypes::asTypeElement) 84 .collect(toImmutableList()); 85 } 86 87 /** The values specified in the {@code subcomponents} attribute. */ 88 @Memoized subcomponentsAsAnnotationValues()89 public ImmutableList<AnnotationValue> subcomponentsAsAnnotationValues() { 90 return asAnnotationValues(getAnnotationValue(annotation(), "subcomponents")); 91 } 92 93 /** Returns {@code true} if the argument is a {@code @Module} or {@code @ProducerModule}. */ isModuleAnnotation(AnnotationMirror annotation)94 public static boolean isModuleAnnotation(AnnotationMirror annotation) { 95 return MODULE_ANNOTATIONS.stream() 96 .map(Class::getCanonicalName) 97 .anyMatch(asTypeElement(annotation.getAnnotationType()).getQualifiedName()::contentEquals); 98 } 99 100 /** The module annotation types. */ moduleAnnotations()101 public static ImmutableSet<Class<? extends Annotation>> moduleAnnotations() { 102 return MODULE_ANNOTATIONS; 103 } 104 105 /** 106 * Creates an object that represents a {@code @Module} or {@code @ProducerModule}. 107 * 108 * @throws IllegalArgumentException if {@link #isModuleAnnotation(AnnotationMirror)} returns 109 * {@code false} 110 */ moduleAnnotation(AnnotationMirror annotation)111 public static ModuleAnnotation moduleAnnotation(AnnotationMirror annotation) { 112 checkArgument( 113 isModuleAnnotation(annotation), 114 "%s is not a Module or ProducerModule annotation", 115 annotation); 116 return new AutoValue_ModuleAnnotation(annotation); 117 } 118 119 /** 120 * Returns an object representing the {@code @Module} or {@code @ProducerModule} annotation if one 121 * annotates {@code typeElement}. 122 */ moduleAnnotation(TypeElement typeElement)123 public static Optional<ModuleAnnotation> moduleAnnotation(TypeElement typeElement) { 124 return getAnyAnnotation(typeElement, Module.class, ProducerModule.class) 125 .map(ModuleAnnotation::moduleAnnotation); 126 } 127 } 128