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; 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.DaggerStreams.toImmutableList; 23 import static dagger.internal.codegen.MoreAnnotationValues.asAnnotationValues; 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 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 abstract AnnotationMirror annotation(); 49 50 /** The type of the annotation. */ 51 @Memoized annotationClass()52 Class<?> annotationClass() { 53 try { 54 return Class.forName( 55 asTypeElement(annotation().getAnnotationType()).getQualifiedName().toString()); 56 } catch (ClassNotFoundException e) { 57 AssertionError assertionError = new AssertionError(); 58 assertionError.initCause(e); 59 throw assertionError; 60 } 61 } 62 63 /** 64 * The types specified in the {@code includes} attribute. 65 * 66 * @throws IllegalArgumentException if any of the values are error types 67 */ 68 @Memoized includes()69 ImmutableList<TypeElement> includes() { 70 return includesAsAnnotationValues().stream() 71 .map(MoreAnnotationValues::asType) 72 .map(MoreTypes::asTypeElement) 73 .collect(toImmutableList()); 74 } 75 76 /** The values specified in the {@code includes} attribute. */ 77 @Memoized includesAsAnnotationValues()78 ImmutableList<AnnotationValue> includesAsAnnotationValues() { 79 return asAnnotationValues(getAnnotationValue(annotation(), "includes")); 80 } 81 82 /** 83 * The types specified in the {@code subcomponents} attribute. 84 * 85 * @throws IllegalArgumentException if any of the values are error types 86 */ 87 @Memoized subcomponents()88 ImmutableList<TypeElement> subcomponents() { 89 return subcomponentsAsAnnotationValues().stream() 90 .map(MoreAnnotationValues::asType) 91 .map(MoreTypes::asTypeElement) 92 .collect(toImmutableList()); 93 } 94 95 /** The values specified in the {@code subcomponents} attribute. */ 96 @Memoized subcomponentsAsAnnotationValues()97 ImmutableList<AnnotationValue> subcomponentsAsAnnotationValues() { 98 return asAnnotationValues(getAnnotationValue(annotation(), "subcomponents")); 99 } 100 101 /** Returns {@code true} if the argument is a {@code @Module} or {@code @ProducerModule}. */ isModuleAnnotation(AnnotationMirror annotation)102 static boolean isModuleAnnotation(AnnotationMirror annotation) { 103 return MODULE_ANNOTATIONS.stream() 104 .map(Class::getCanonicalName) 105 .anyMatch(asTypeElement(annotation.getAnnotationType()).getQualifiedName()::contentEquals); 106 } 107 108 /** The module annotation types. */ moduleAnnotations()109 static ImmutableSet<Class<? extends Annotation>> moduleAnnotations() { 110 return MODULE_ANNOTATIONS; 111 } 112 113 /** 114 * Creates an object that represents a {@code @Module} or {@code @ProducerModule}. 115 * 116 * @throws IllegalArgumentException if {@link #isModuleAnnotation(AnnotationMirror)} returns 117 * {@code false} 118 */ moduleAnnotation(AnnotationMirror annotation)119 static ModuleAnnotation moduleAnnotation(AnnotationMirror annotation) { 120 checkArgument( 121 isModuleAnnotation(annotation), 122 "%s is not a Module or ProducerModule annotation", 123 annotation); 124 return new AutoValue_ModuleAnnotation(annotation); 125 } 126 127 /** 128 * Returns an object representing the {@code @Module} or {@code @ProducerModule} annotation if one 129 * annotates {@code typeElement}. 130 */ moduleAnnotation(TypeElement typeElement)131 static Optional<ModuleAnnotation> moduleAnnotation(TypeElement typeElement) { 132 return getAnyAnnotation(typeElement, Module.class, ProducerModule.class) 133 .map(ModuleAnnotation::moduleAnnotation); 134 } 135 } 136