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.binding; 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.base.ModuleAnnotation.moduleAnnotation; 24 import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.getCreatorAnnotations; 25 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 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 public abstract class ComponentCreatorDescriptor { 54 55 /** Returns the annotation marking this creator. */ annotation()56 public abstract ComponentCreatorAnnotation annotation(); 57 58 /** The kind of this creator. */ kind()59 public final ComponentCreatorKind kind() { 60 return annotation().creatorKind(); 61 } 62 63 /** The annotated creator type. */ typeElement()64 public abstract TypeElement typeElement(); 65 66 /** The method that creates and returns a component instance. */ factoryMethod()67 public 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 */ 93 public final ImmutableSetMultimap<ComponentRequirement, Element> unvalidatedRequirementElements()94 unvalidatedRequirementElements() { 95 // ComponentCreatorValidator ensures that there are either setter methods or factory method 96 // parameters, but not both, so we can cheat a little here since we know that only one of 97 // the two multimaps will be non-empty. 98 return ImmutableSetMultimap.copyOf( // no actual copy 99 unvalidatedSetterMethods().isEmpty() 100 ? unvalidatedFactoryParameters() 101 : unvalidatedSetterMethods()); 102 } 103 104 /** 105 * Map of component requirements to elements (setter methods or factory method parameters) that 106 * set them. 107 */ 108 @Memoized requirementElements()109 ImmutableMap<ComponentRequirement, Element> requirementElements() { 110 return flatten(unvalidatedRequirementElements()); 111 } 112 113 /** Map of component requirements to setter methods for those requirements. */ 114 @Memoized setterMethods()115 public ImmutableMap<ComponentRequirement, ExecutableElement> setterMethods() { 116 return flatten(unvalidatedSetterMethods()); 117 } 118 119 /** Map of component requirements to factory method parameters for those requirements. */ 120 @Memoized factoryParameters()121 public ImmutableMap<ComponentRequirement, VariableElement> factoryParameters() { 122 return flatten(unvalidatedFactoryParameters()); 123 } 124 flatten(Multimap<K, V> multimap)125 private static <K, V> ImmutableMap<K, V> flatten(Multimap<K, V> multimap) { 126 return ImmutableMap.copyOf( 127 Maps.transformValues(multimap.asMap(), values -> getOnlyElement(values))); 128 } 129 130 /** Returns the set of component requirements this creator allows the user to set. */ userSettableRequirements()131 public final ImmutableSet<ComponentRequirement> userSettableRequirements() { 132 // Note: they should have been validated at the point this is used, so this set is valid. 133 return unvalidatedRequirementElements().keySet(); 134 } 135 136 /** Returns the set of requirements for modules and component dependencies for this creator. */ moduleAndDependencyRequirements()137 public final ImmutableSet<ComponentRequirement> moduleAndDependencyRequirements() { 138 return userSettableRequirements().stream() 139 .filter(requirement -> !requirement.isBoundInstance()) 140 .collect(toImmutableSet()); 141 } 142 143 /** Returns the set of bound instance requirements for this creator. */ boundInstanceRequirements()144 final ImmutableSet<ComponentRequirement> boundInstanceRequirements() { 145 return userSettableRequirements().stream() 146 .filter(ComponentRequirement::isBoundInstance) 147 .collect(toImmutableSet()); 148 } 149 150 /** Returns the element in this creator that sets the given {@code requirement}. */ elementForRequirement(ComponentRequirement requirement)151 final Element elementForRequirement(ComponentRequirement requirement) { 152 return requirementElements().get(requirement); 153 } 154 155 /** Creates a new {@link ComponentCreatorDescriptor} for the given creator {@code type}. */ create( DeclaredType type, DaggerElements elements, DaggerTypes types, DependencyRequestFactory dependencyRequestFactory)156 public static ComponentCreatorDescriptor create( 157 DeclaredType type, 158 DaggerElements elements, 159 DaggerTypes types, 160 DependencyRequestFactory dependencyRequestFactory) { 161 TypeElement typeElement = asTypeElement(type); 162 TypeMirror componentType = typeElement.getEnclosingElement().asType(); 163 164 ImmutableSetMultimap.Builder<ComponentRequirement, ExecutableElement> setterMethods = 165 ImmutableSetMultimap.builder(); 166 167 ExecutableElement factoryMethod = null; 168 for (ExecutableElement method : elements.getUnimplementedMethods(typeElement)) { 169 ExecutableType resolvedMethodType = MoreTypes.asExecutable(types.asMemberOf(type, method)); 170 171 if (types.isSubtype(componentType, resolvedMethodType.getReturnType())) { 172 factoryMethod = method; 173 } else { 174 VariableElement parameter = getOnlyElement(method.getParameters()); 175 TypeMirror parameterType = getOnlyElement(resolvedMethodType.getParameterTypes()); 176 setterMethods.put( 177 requirement(method, parameter, parameterType, dependencyRequestFactory, method), 178 method); 179 } 180 } 181 verify(factoryMethod != null); // validation should have ensured this. 182 183 ImmutableSetMultimap.Builder<ComponentRequirement, VariableElement> factoryParameters = 184 ImmutableSetMultimap.builder(); 185 186 ExecutableType resolvedFactoryMethodType = 187 MoreTypes.asExecutable(types.asMemberOf(type, factoryMethod)); 188 List<? extends VariableElement> parameters = factoryMethod.getParameters(); 189 List<? extends TypeMirror> parameterTypes = resolvedFactoryMethodType.getParameterTypes(); 190 for (int i = 0; i < parameters.size(); i++) { 191 VariableElement parameter = parameters.get(i); 192 TypeMirror parameterType = parameterTypes.get(i); 193 factoryParameters.put( 194 requirement(factoryMethod, parameter, parameterType, dependencyRequestFactory, parameter), 195 parameter); 196 } 197 198 // Validation should have ensured exactly one creator annotation is present on the type. 199 ComponentCreatorAnnotation annotation = getOnlyElement(getCreatorAnnotations(typeElement)); 200 return new AutoValue_ComponentCreatorDescriptor( 201 annotation, typeElement, factoryMethod, setterMethods.build(), factoryParameters.build()); 202 } 203 requirement( ExecutableElement method, VariableElement parameter, TypeMirror type, DependencyRequestFactory dependencyRequestFactory, Element elementForVariableName)204 private static ComponentRequirement requirement( 205 ExecutableElement method, 206 VariableElement parameter, 207 TypeMirror type, 208 DependencyRequestFactory dependencyRequestFactory, 209 Element elementForVariableName) { 210 if (isAnnotationPresent(method, BindsInstance.class) 211 || isAnnotationPresent(parameter, BindsInstance.class)) { 212 DependencyRequest request = 213 dependencyRequestFactory.forRequiredResolvedVariable(parameter, type); 214 String variableName = elementForVariableName.getSimpleName().toString(); 215 return ComponentRequirement.forBoundInstance( 216 request.key(), request.isNullable(), variableName); 217 } 218 219 return moduleAnnotation(asTypeElement(type)).isPresent() 220 ? ComponentRequirement.forModule(type) 221 : ComponentRequirement.forDependency(type); 222 } 223 } 224