1 /* 2 * Copyright (C) 2014 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.MoreElements.isAnnotationPresent; 20 import static com.google.auto.common.MoreTypes.asTypeElement; 21 import static com.google.common.base.Verify.verify; 22 import static com.google.common.collect.Iterables.getOnlyElement; 23 import static dagger.internal.codegen.ComponentCreatorAnnotation.getCreatorAnnotations; 24 import static dagger.internal.codegen.DaggerStreams.toImmutableSet; 25 import static dagger.internal.codegen.ModuleAnnotation.moduleAnnotation; 26 27 import com.google.auto.common.MoreTypes; 28 import com.google.auto.value.AutoValue; 29 import com.google.auto.value.extension.memoized.Memoized; 30 import com.google.common.collect.ImmutableMap; 31 import com.google.common.collect.ImmutableSet; 32 import com.google.common.collect.ImmutableSetMultimap; 33 import com.google.common.collect.Maps; 34 import com.google.common.collect.Multimap; 35 import dagger.BindsInstance; 36 import dagger.internal.codegen.langmodel.DaggerElements; 37 import dagger.internal.codegen.langmodel.DaggerTypes; 38 import dagger.model.DependencyRequest; 39 import java.util.List; 40 import javax.lang.model.element.Element; 41 import javax.lang.model.element.ExecutableElement; 42 import javax.lang.model.element.TypeElement; 43 import javax.lang.model.element.VariableElement; 44 import javax.lang.model.type.DeclaredType; 45 import javax.lang.model.type.ExecutableType; 46 import javax.lang.model.type.TypeMirror; 47 48 /** 49 * A descriptor for a component <i>creator</i> type: that is, a type annotated with 50 * {@code @Component.Builder} (or one of the corresponding production or subcomponent versions). 51 */ 52 @AutoValue 53 abstract class ComponentCreatorDescriptor { 54 55 /** Returns the annotation marking this creator. */ annotation()56 abstract ComponentCreatorAnnotation annotation(); 57 58 /** The kind of this creator. */ kind()59 final ComponentCreatorKind kind() { 60 return annotation().creatorKind(); 61 } 62 63 /** The annotated creator type. */ typeElement()64 abstract TypeElement typeElement(); 65 66 /** The method that creates and returns a component instance. */ factoryMethod()67 abstract ExecutableElement factoryMethod(); 68 69 /** 70 * Multimap of component requirements to setter methods that set that requirement. 71 * 72 * <p>In a valid creator, there will be exactly one element per component requirement, so this 73 * method should only be called when validating the descriptor. 74 */ unvalidatedSetterMethods()75 abstract ImmutableSetMultimap<ComponentRequirement, ExecutableElement> unvalidatedSetterMethods(); 76 77 /** 78 * Multimap of component requirements to factory method parameters that set that requirement. 79 * 80 * <p>In a valid creator, there will be exactly one element per component requirement, so this 81 * method should only be called when validating the descriptor. 82 */ 83 abstract ImmutableSetMultimap<ComponentRequirement, VariableElement> unvalidatedFactoryParameters()84 unvalidatedFactoryParameters(); 85 86 /** 87 * Multimap of component requirements to elements (methods or parameters) that set that 88 * requirement. 89 * 90 * <p>In a valid creator, there will be exactly one element per component requirement, so this 91 * method should only be called when validating the descriptor. 92 */ unvalidatedRequirementElements()93 final ImmutableSetMultimap<ComponentRequirement, Element> unvalidatedRequirementElements() { 94 // ComponentCreatorValidator ensures that there are either setter methods or factory method 95 // parameters, but not both, so we can cheat a little here since we know that only one of 96 // the two multimaps will be non-empty. 97 return ImmutableSetMultimap.copyOf( // no actual copy 98 unvalidatedSetterMethods().isEmpty() 99 ? unvalidatedFactoryParameters() 100 : unvalidatedSetterMethods()); 101 } 102 103 /** 104 * Map of component requirements to elements (setter methods or factory method parameters) that 105 * set them. 106 */ 107 @Memoized requirementElements()108 ImmutableMap<ComponentRequirement, Element> requirementElements() { 109 return flatten(unvalidatedRequirementElements()); 110 } 111 112 /** Map of component requirements to setter methods for those requirements. */ 113 @Memoized setterMethods()114 ImmutableMap<ComponentRequirement, ExecutableElement> setterMethods() { 115 return flatten(unvalidatedSetterMethods()); 116 } 117 118 /** Map of component requirements to factory method parameters for those requirements. */ 119 @Memoized factoryParameters()120 ImmutableMap<ComponentRequirement, VariableElement> factoryParameters() { 121 return flatten(unvalidatedFactoryParameters()); 122 } 123 flatten(Multimap<K, V> multimap)124 private static <K, V> ImmutableMap<K, V> flatten(Multimap<K, V> multimap) { 125 return ImmutableMap.copyOf( 126 Maps.transformValues(multimap.asMap(), values -> getOnlyElement(values))); 127 } 128 129 /** Returns the set of component requirements this creator allows the user to set. */ userSettableRequirements()130 final ImmutableSet<ComponentRequirement> userSettableRequirements() { 131 // Note: they should have been validated at the point this is used, so this set is valid. 132 return unvalidatedRequirementElements().keySet(); 133 } 134 135 /** Returns the set of requirements for modules and component dependencies for this creator. */ moduleAndDependencyRequirements()136 final ImmutableSet<ComponentRequirement> moduleAndDependencyRequirements() { 137 return userSettableRequirements().stream() 138 .filter(requirement -> !requirement.isBoundInstance()) 139 .collect(toImmutableSet()); 140 } 141 142 /** Returns the set of bound instance requirements for this creator. */ boundInstanceRequirements()143 final ImmutableSet<ComponentRequirement> boundInstanceRequirements() { 144 return userSettableRequirements().stream() 145 .filter(ComponentRequirement::isBoundInstance) 146 .collect(toImmutableSet()); 147 } 148 149 /** Returns the element in this creator that sets the given {@code requirement}. */ elementForRequirement(ComponentRequirement requirement)150 final Element elementForRequirement(ComponentRequirement requirement) { 151 return requirementElements().get(requirement); 152 } 153 154 /** Creates a new {@link ComponentCreatorDescriptor} for the given creator {@code type}. */ create( DeclaredType type, DaggerElements elements, DaggerTypes types, DependencyRequestFactory dependencyRequestFactory)155 static ComponentCreatorDescriptor create( 156 DeclaredType type, 157 DaggerElements elements, 158 DaggerTypes types, 159 DependencyRequestFactory dependencyRequestFactory) { 160 TypeElement typeElement = asTypeElement(type); 161 TypeMirror componentType = typeElement.getEnclosingElement().asType(); 162 163 ImmutableSetMultimap.Builder<ComponentRequirement, ExecutableElement> setterMethods = 164 ImmutableSetMultimap.builder(); 165 166 ExecutableElement factoryMethod = null; 167 for (ExecutableElement method : elements.getUnimplementedMethods(typeElement)) { 168 ExecutableType resolvedMethodType = MoreTypes.asExecutable(types.asMemberOf(type, method)); 169 170 if (types.isSubtype(componentType, resolvedMethodType.getReturnType())) { 171 factoryMethod = method; 172 } else { 173 VariableElement parameter = getOnlyElement(method.getParameters()); 174 TypeMirror parameterType = getOnlyElement(resolvedMethodType.getParameterTypes()); 175 setterMethods.put( 176 requirement(method, parameter, parameterType, dependencyRequestFactory, method), 177 method); 178 } 179 } 180 verify(factoryMethod != null); // validation should have ensured this. 181 182 ImmutableSetMultimap.Builder<ComponentRequirement, VariableElement> factoryParameters = 183 ImmutableSetMultimap.builder(); 184 185 ExecutableType resolvedFactoryMethodType = 186 MoreTypes.asExecutable(types.asMemberOf(type, factoryMethod)); 187 List<? extends VariableElement> parameters = factoryMethod.getParameters(); 188 List<? extends TypeMirror> parameterTypes = resolvedFactoryMethodType.getParameterTypes(); 189 for (int i = 0; i < parameters.size(); i++) { 190 VariableElement parameter = parameters.get(i); 191 TypeMirror parameterType = parameterTypes.get(i); 192 factoryParameters.put( 193 requirement(factoryMethod, parameter, parameterType, dependencyRequestFactory, parameter), 194 parameter); 195 } 196 197 // Validation should have ensured exactly one creator annotation is present on the type. 198 ComponentCreatorAnnotation annotation = getOnlyElement(getCreatorAnnotations(typeElement)); 199 return new AutoValue_ComponentCreatorDescriptor( 200 annotation, typeElement, factoryMethod, setterMethods.build(), factoryParameters.build()); 201 } 202 requirement( ExecutableElement method, VariableElement parameter, TypeMirror type, DependencyRequestFactory dependencyRequestFactory, Element elementForVariableName)203 private static ComponentRequirement requirement( 204 ExecutableElement method, 205 VariableElement parameter, 206 TypeMirror type, 207 DependencyRequestFactory dependencyRequestFactory, 208 Element elementForVariableName) { 209 if (isAnnotationPresent(method, BindsInstance.class) 210 || isAnnotationPresent(parameter, BindsInstance.class)) { 211 DependencyRequest request = 212 dependencyRequestFactory.forRequiredResolvedVariable(parameter, type); 213 String variableName = elementForVariableName.getSimpleName().toString(); 214 return ComponentRequirement.forBoundInstance( 215 request.key(), request.isNullable(), variableName); 216 } 217 218 return moduleAnnotation(asTypeElement(type)).isPresent() 219 ? ComponentRequirement.forModule(type) 220 : ComponentRequirement.forDependency(type); 221 } 222 } 223