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.common.base.Verify.verify; 20 import static com.google.common.collect.Iterables.getOnlyElement; 21 import static dagger.internal.codegen.base.ComponentCreatorAnnotation.getCreatorAnnotations; 22 import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotations; 23 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 24 import static dagger.internal.codegen.xprocessing.XTypeElements.getAllUnimplementedMethods; 25 import static dagger.internal.codegen.xprocessing.XTypes.isSubtype; 26 27 import androidx.room.compiler.processing.XElement; 28 import androidx.room.compiler.processing.XExecutableParameterElement; 29 import androidx.room.compiler.processing.XMethodElement; 30 import androidx.room.compiler.processing.XMethodType; 31 import androidx.room.compiler.processing.XType; 32 import androidx.room.compiler.processing.XTypeElement; 33 import com.google.auto.value.AutoValue; 34 import com.google.auto.value.extension.memoized.Memoized; 35 import com.google.common.collect.ImmutableMap; 36 import com.google.common.collect.ImmutableSet; 37 import com.google.common.collect.ImmutableSetMultimap; 38 import com.google.common.collect.Maps; 39 import com.google.common.collect.Multimap; 40 import dagger.internal.codegen.base.ComponentCreatorAnnotation; 41 import dagger.internal.codegen.base.ComponentCreatorKind; 42 import dagger.internal.codegen.javapoet.TypeNames; 43 import dagger.internal.codegen.model.DependencyRequest; 44 import dagger.internal.codegen.xprocessing.XElements; 45 import java.util.List; 46 47 /** 48 * A descriptor for a component <i>creator</i> type: that is, a type annotated with 49 * {@code @Component.Builder} (or one of the corresponding production or subcomponent versions). 50 */ 51 @AutoValue 52 public abstract class ComponentCreatorDescriptor { 53 54 /** Returns the annotation marking this creator. */ annotation()55 public abstract ComponentCreatorAnnotation annotation(); 56 57 /** The kind of this creator. */ kind()58 public final ComponentCreatorKind kind() { 59 return annotation().creatorKind(); 60 } 61 62 /** The annotated creator type. */ typeElement()63 public abstract XTypeElement typeElement(); 64 65 /** The method that creates and returns a component instance. */ factoryMethod()66 public abstract XMethodElement factoryMethod(); 67 68 /** 69 * Multimap of component requirements to setter methods that set that requirement. 70 * 71 * <p>In a valid creator, there will be exactly one element per component requirement, so this 72 * method should only be called when validating the descriptor. 73 */ unvalidatedSetterMethods()74 abstract ImmutableSetMultimap<ComponentRequirement, XMethodElement> unvalidatedSetterMethods(); 75 76 /** 77 * Multimap of component requirements to factory method parameters that set that requirement. 78 * 79 * <p>In a valid creator, there will be exactly one element per component requirement, so this 80 * method should only be called when validating the descriptor. 81 */ 82 abstract ImmutableSetMultimap<ComponentRequirement, XExecutableParameterElement> unvalidatedFactoryParameters()83 unvalidatedFactoryParameters(); 84 85 /** 86 * Multimap of component requirements to elements (methods or parameters) that set that 87 * requirement. 88 * 89 * <p>In a valid creator, there will be exactly one element per component requirement, so this 90 * method should only be called when validating the descriptor. 91 */ 92 public final ImmutableSetMultimap<ComponentRequirement, XElement> unvalidatedRequirementElements()93 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, XElement> requirementElements() { 109 return flatten(unvalidatedRequirementElements()); 110 } 111 112 /** Map of component requirements to setter methods for those requirements. */ 113 @Memoized setterMethods()114 public ImmutableMap<ComponentRequirement, XMethodElement> setterMethods() { 115 return flatten(unvalidatedSetterMethods()); 116 } 117 118 /** Map of component requirements to factory method parameters for those requirements. */ 119 @Memoized factoryParameters()120 public ImmutableMap<ComponentRequirement, XExecutableParameterElement> 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 public 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 public 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 XElement elementForRequirement(ComponentRequirement requirement) { 151 return requirementElements().get(requirement); 152 } 153 154 /** Creates a new {@link ComponentCreatorDescriptor} for the given creator {@code type}. */ create( XTypeElement creator, DependencyRequestFactory dependencyRequestFactory)155 public static ComponentCreatorDescriptor create( 156 XTypeElement creator, DependencyRequestFactory dependencyRequestFactory) { 157 XType componentType = creator.getEnclosingTypeElement().getType(); 158 159 ImmutableSetMultimap.Builder<ComponentRequirement, XMethodElement> setterMethods = 160 ImmutableSetMultimap.builder(); 161 XMethodElement factoryMethod = null; 162 for (XMethodElement method : getAllUnimplementedMethods(creator)) { 163 XMethodType resolvedMethodType = method.asMemberOf(creator.getType()); 164 if (isSubtype(componentType, resolvedMethodType.getReturnType())) { 165 verify( 166 factoryMethod == null, 167 "Expected a single factory method for %s but found multiple: [%s, %s]", 168 XElements.toStableString(creator), 169 XElements.toStableString(factoryMethod), 170 XElements.toStableString(method)); 171 factoryMethod = method; 172 } else { 173 XExecutableParameterElement parameter = getOnlyElement(method.getParameters()); 174 XType parameterType = getOnlyElement(resolvedMethodType.getParameterTypes()); 175 setterMethods.put( 176 requirement(method, parameter, parameterType, dependencyRequestFactory, method), 177 method); 178 } 179 } 180 verify( 181 factoryMethod != null, 182 "Expected a single factory method for %s but found none.", 183 XElements.toStableString(creator)); 184 185 ImmutableSetMultimap.Builder<ComponentRequirement, XExecutableParameterElement> 186 factoryParameters = ImmutableSetMultimap.builder(); 187 188 XMethodType resolvedFactoryMethodType = factoryMethod.asMemberOf(creator.getType()); 189 List<XExecutableParameterElement> parameters = factoryMethod.getParameters(); 190 List<XType> parameterTypes = resolvedFactoryMethodType.getParameterTypes(); 191 for (int i = 0; i < parameters.size(); i++) { 192 XExecutableParameterElement parameter = parameters.get(i); 193 XType parameterType = parameterTypes.get(i); 194 factoryParameters.put( 195 requirement( 196 factoryMethod, 197 parameter, 198 parameterType, 199 dependencyRequestFactory, 200 parameter), 201 parameter); 202 } 203 // Validation should have ensured exactly one creator annotation is present on the type. 204 ComponentCreatorAnnotation annotation = getOnlyElement(getCreatorAnnotations(creator)); 205 return new AutoValue_ComponentCreatorDescriptor( 206 annotation, creator, factoryMethod, setterMethods.build(), factoryParameters.build()); 207 } 208 requirement( XMethodElement method, XExecutableParameterElement parameter, XType parameterType, DependencyRequestFactory dependencyRequestFactory, XElement elementForVariableName)209 private static ComponentRequirement requirement( 210 XMethodElement method, 211 XExecutableParameterElement parameter, 212 XType parameterType, 213 DependencyRequestFactory dependencyRequestFactory, 214 XElement elementForVariableName) { 215 if (method.hasAnnotation(TypeNames.BINDS_INSTANCE) 216 || parameter.hasAnnotation(TypeNames.BINDS_INSTANCE)) { 217 DependencyRequest request = 218 dependencyRequestFactory.forRequiredResolvedVariable(parameter, parameterType); 219 return ComponentRequirement.forBoundInstance( 220 request.key(), request.isNullable(), elementForVariableName); 221 } 222 223 return parameterType.getTypeElement().hasAnyAnnotation(moduleAnnotations()) 224 ? ComponentRequirement.forModule(parameterType) 225 : ComponentRequirement.forDependency(parameterType); 226 } 227 } 228