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