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; 18 19 import static androidx.room.compiler.processing.XElementKt.isTypeElement; 20 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; 21 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 22 import static dagger.internal.codegen.xprocessing.XElements.asTypeElement; 23 24 import androidx.room.compiler.processing.XElement; 25 import androidx.room.compiler.processing.XTypeElement; 26 import com.google.common.base.Preconditions; 27 import com.google.common.collect.ImmutableList; 28 import com.google.common.collect.ImmutableSet; 29 import com.squareup.javapoet.AnnotationSpec; 30 import com.squareup.javapoet.ClassName; 31 import dagger.internal.codegen.xprocessing.XElements; 32 33 /** Helper methods for defining components and the component hierarchy. */ 34 public final class Components { 35 /** Returns the {@link dagger.hilt.InstallIn} components for a given element. */ getComponents(XElement element)36 public static ImmutableSet<ClassName> getComponents(XElement element) { 37 ImmutableSet<ClassName> components; 38 if (element.hasAnnotation(ClassNames.INSTALL_IN) 39 || element.hasAnnotation(ClassNames.TEST_INSTALL_IN)) { 40 components = getHiltInstallInComponents(element); 41 } else { 42 // Check the enclosing element in case it passed in module is a companion object. This helps 43 // in cases where the element was arrived at by checking a binding method and moving outward. 44 XElement enclosing = element.getEnclosingElement(); 45 if (enclosing != null 46 && isTypeElement(enclosing) 47 && isTypeElement(element) 48 && enclosing.hasAnnotation(ClassNames.MODULE) 49 && asTypeElement(element).isCompanionObject()) { 50 return getComponents(enclosing); 51 } 52 if (Processors.hasErrorTypeAnnotation(element)) { 53 throw new BadInputException( 54 String.format( 55 "Error annotation found on element %s. Look above for compilation errors", 56 XElements.toStableString(element)), 57 element); 58 } else { 59 throw new BadInputException( 60 String.format( 61 "An @InstallIn annotation is required for: %s." , 62 XElements.toStableString(element)), 63 element); 64 } 65 } 66 67 return components; 68 } 69 getInstallInAnnotationSpec(ImmutableSet<ClassName> components)70 public static AnnotationSpec getInstallInAnnotationSpec(ImmutableSet<ClassName> components) { 71 Preconditions.checkArgument(!components.isEmpty()); 72 AnnotationSpec.Builder builder = AnnotationSpec.builder(ClassNames.INSTALL_IN); 73 components.forEach(component -> builder.addMember("value", "$T.class", component)); 74 return builder.build(); 75 } 76 getHiltInstallInComponents(XElement element)77 private static ImmutableSet<ClassName> getHiltInstallInComponents(XElement element) { 78 Preconditions.checkArgument( 79 element.hasAnnotation(ClassNames.INSTALL_IN) 80 || element.hasAnnotation(ClassNames.TEST_INSTALL_IN)); 81 82 ImmutableList<XTypeElement> components = 83 element.hasAnnotation(ClassNames.INSTALL_IN) 84 ? Processors.getAnnotationClassValues( 85 element.getAnnotation(ClassNames.INSTALL_IN), "value") 86 : Processors.getAnnotationClassValues( 87 element.getAnnotation(ClassNames.TEST_INSTALL_IN), "components"); 88 89 ImmutableSet<XTypeElement> undefinedComponents = 90 components.stream() 91 .filter(component -> !component.hasAnnotation(ClassNames.DEFINE_COMPONENT)) 92 .collect(toImmutableSet()); 93 94 ProcessorErrors.checkState( 95 undefinedComponents.isEmpty(), 96 element, 97 "@InstallIn, can only be used with @DefineComponent-annotated classes, but found: %s", 98 undefinedComponents.stream().map(XElements::toStableString).collect(toImmutableList())); 99 100 return components.stream().map(XTypeElement::getClassName).collect(toImmutableSet()); 101 } 102 Components()103 private Components() {} 104 } 105