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.hilt.processor.internal.generatesrootinput; 18 19 import static com.google.common.base.Preconditions.checkState; 20 import static com.google.common.base.Suppliers.memoize; 21 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 22 23 import com.google.common.base.Supplier; 24 import com.google.common.collect.ImmutableList; 25 import com.google.common.collect.ImmutableSet; 26 import com.squareup.javapoet.ClassName; 27 import dagger.hilt.processor.internal.ClassNames; 28 import dagger.hilt.processor.internal.ProcessorErrors; 29 import dagger.hilt.processor.internal.Processors; 30 import java.util.List; 31 import javax.annotation.processing.ProcessingEnvironment; 32 import javax.annotation.processing.RoundEnvironment; 33 import javax.lang.model.element.AnnotationMirror; 34 import javax.lang.model.element.Element; 35 import javax.lang.model.element.ElementKind; 36 import javax.lang.model.element.PackageElement; 37 import javax.lang.model.element.TypeElement; 38 import javax.lang.model.util.Elements; 39 40 /** Extracts the list of annotations annotated with {@link dagger.hilt.GeneratesRootInput}. */ 41 public final class GeneratesRootInputs { 42 static final String AGGREGATING_PACKAGE = 43 GeneratesRootInputs.class.getPackage().getName() + ".codegen"; 44 45 private final Elements elements; 46 private final Supplier<ImmutableList<ClassName>> generatesRootInputAnnotations = 47 memoize(() -> getAnnotationList()); 48 GeneratesRootInputs(ProcessingEnvironment processingEnvironment)49 public GeneratesRootInputs(ProcessingEnvironment processingEnvironment) { 50 this.elements = processingEnvironment.getElementUtils(); 51 } 52 getElementsToWaitFor(RoundEnvironment roundEnv)53 public ImmutableSet<Element> getElementsToWaitFor(RoundEnvironment roundEnv) { 54 // Processing can only take place after all dependent annotations have been processed 55 // Note: We start with ClassName rather than TypeElement because jdk8 does not treat type 56 // elements as equal across rounds. Thus, in order for RoundEnvironment#getElementsAnnotatedWith 57 // to work properly, we get new elements to ensure it works across rounds (See b/148693284). 58 return generatesRootInputAnnotations.get().stream() 59 .map(className -> elements.getTypeElement(className.toString())) 60 .filter(element -> element != null) 61 .flatMap(annotation -> roundEnv.getElementsAnnotatedWith(annotation).stream()) 62 .collect(toImmutableSet()); 63 } 64 getAnnotationList()65 private ImmutableList<ClassName> getAnnotationList() { 66 PackageElement packageElement = elements.getPackageElement(AGGREGATING_PACKAGE); 67 68 if (packageElement == null) { 69 return ImmutableList.of(); 70 } 71 72 List<? extends Element> annotationElements = packageElement.getEnclosedElements(); 73 checkState(!annotationElements.isEmpty(), "No elements Found in package %s.", packageElement); 74 75 ImmutableList.Builder<ClassName> builder = ImmutableList.builder(); 76 for (Element element : annotationElements) { 77 ProcessorErrors.checkState( 78 element.getKind() == ElementKind.CLASS, 79 element, 80 "Only classes may be in package %s. Did you add custom code in the package?", 81 packageElement); 82 83 AnnotationMirror annotationMirror = 84 Processors.getAnnotationMirror(element, ClassNames.GENERATES_ROOT_INPUT_PROPAGATED_DATA); 85 ProcessorErrors.checkState( 86 annotationMirror != null, 87 element, 88 "Classes in package %s must be annotated with @%s: %s." 89 + " Found: %s. Files in this package are generated, did you add custom code in the" 90 + " package? ", 91 packageElement, 92 ClassNames.GENERATES_ROOT_INPUT_PROPAGATED_DATA, 93 element.getSimpleName(), 94 element.getAnnotationMirrors()); 95 96 TypeElement annotation = 97 Processors.getAnnotationClassValue(elements, annotationMirror, "value"); 98 99 builder.add(ClassName.get(annotation)); 100 } 101 // This annotation was on Dagger so it couldn't be annotated with @GeneratesRootInput to be 102 // cultivated later. We have to manually add it to the list. 103 builder.add(ClassNames.PRODUCTION_COMPONENT); 104 return builder.build(); 105 } 106 } 107