1 /* 2 * Copyright (C) 2014 Google, Inc. 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 package dagger.internal.codegen; 17 18 import com.google.auto.common.MoreElements; 19 import com.google.auto.common.MoreTypes; 20 import com.google.auto.value.AutoValue; 21 import com.google.common.base.Optional; 22 import com.google.common.base.Predicate; 23 import com.google.common.collect.FluentIterable; 24 import com.google.common.collect.ImmutableList; 25 import com.google.common.collect.ImmutableMap; 26 import com.google.common.collect.ImmutableSet; 27 import com.google.common.util.concurrent.ListenableFuture; 28 import dagger.Component; 29 import dagger.Lazy; 30 import dagger.MembersInjector; 31 import dagger.Module; 32 import dagger.Subcomponent; 33 import dagger.producers.ProductionComponent; 34 import java.lang.annotation.Annotation; 35 import java.util.EnumSet; 36 import java.util.LinkedHashSet; 37 import java.util.List; 38 import java.util.Map; 39 import java.util.Set; 40 import java.util.concurrent.Executor; 41 import javax.inject.Provider; 42 import javax.lang.model.element.AnnotationMirror; 43 import javax.lang.model.element.ExecutableElement; 44 import javax.lang.model.element.TypeElement; 45 import javax.lang.model.type.DeclaredType; 46 import javax.lang.model.type.ExecutableType; 47 import javax.lang.model.type.TypeMirror; 48 import javax.lang.model.util.ElementFilter; 49 import javax.lang.model.util.Elements; 50 import javax.lang.model.util.Types; 51 52 import static com.google.auto.common.MoreElements.getAnnotationMirror; 53 import static com.google.auto.common.MoreElements.isAnnotationPresent; 54 import static com.google.common.base.Preconditions.checkArgument; 55 import static com.google.common.base.Verify.verify; 56 import static com.google.common.collect.Iterables.getOnlyElement; 57 import static dagger.internal.codegen.ConfigurationAnnotations.enclosedBuilders; 58 import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies; 59 import static dagger.internal.codegen.ConfigurationAnnotations.getComponentModules; 60 import static dagger.internal.codegen.ConfigurationAnnotations.isComponent; 61 import static javax.lang.model.type.TypeKind.DECLARED; 62 import static javax.lang.model.type.TypeKind.VOID; 63 64 /** 65 * The logical representation of a {@link Component} or {@link ProductionComponent} definition. 66 * 67 * @author Gregory Kick 68 * @since 2.0 69 */ 70 @AutoValue 71 abstract class ComponentDescriptor { 72 ComponentDescriptor() {} 73 74 enum Kind { 75 COMPONENT(Component.class, Component.Builder.class, true), 76 SUBCOMPONENT(Subcomponent.class, Subcomponent.Builder.class, false), 77 PRODUCTION_COMPONENT(ProductionComponent.class, ProductionComponent.Builder.class, true); 78 79 private final Class<? extends Annotation> annotationType; 80 private final Class<? extends Annotation> builderType; 81 private final boolean isTopLevel; 82 83 /** 84 * Returns the kind of an annotated element if it is annotated with one of the 85 * {@linkplain #annotationType() annotation types}. 86 * 87 * @throws IllegalArgumentException if the element is annotated with more than one of the 88 * annotation types 89 */ 90 static Optional<Kind> forAnnotatedElement(TypeElement element) { 91 Set<Kind> kinds = EnumSet.noneOf(Kind.class); 92 for (Kind kind : values()) { 93 if (MoreElements.isAnnotationPresent(element, kind.annotationType())) { 94 kinds.add(kind); 95 } 96 } 97 checkArgument( 98 kinds.size() <= 1, "%s cannot be annotated with more than one of %s", element, kinds); 99 return Optional.fromNullable(getOnlyElement(kinds, null)); 100 } 101 102 Kind( 103 Class<? extends Annotation> annotationType, 104 Class<? extends Annotation> builderType, 105 boolean isTopLevel) { 106 this.annotationType = annotationType; 107 this.builderType = builderType; 108 this.isTopLevel = isTopLevel; 109 } 110 111 Class<? extends Annotation> annotationType() { 112 return annotationType; 113 } 114 115 Class<? extends Annotation> builderAnnotationType() { 116 return builderType; 117 } 118 119 boolean isTopLevel() { 120 return isTopLevel; 121 } 122 } 123 124 abstract Kind kind(); 125 126 abstract AnnotationMirror componentAnnotation(); 127 128 /** 129 * The type (interface or abstract class) that defines the component. This is the element to which 130 * the {@link Component} annotation was applied. 131 */ 132 abstract TypeElement componentDefinitionType(); 133 134 /** 135 * The set of component dependencies listed in {@link Component#dependencies}. 136 */ 137 abstract ImmutableSet<TypeElement> dependencies(); 138 139 /** 140 * The set of {@link ModuleDescriptor modules} declared directly in {@link Component#modules}. 141 * Use {@link #transitiveModules} to get the full set of modules available upon traversing 142 * {@link Module#includes}. 143 */ 144 abstract ImmutableSet<ModuleDescriptor> modules(); 145 146 /** 147 * Returns the set of {@link ModuleDescriptor modules} declared in {@link Component#modules} and 148 * those reachable by traversing {@link Module#includes}. 149 * 150 * <p>Note that for subcomponents this <em>will not</em> include descriptors for any modules that 151 * are declared in parent components. 152 */ 153 ImmutableSet<ModuleDescriptor> transitiveModules() { 154 Set<ModuleDescriptor> transitiveModules = new LinkedHashSet<>(); 155 for (ModuleDescriptor module : modules()) { 156 addTransitiveModules(transitiveModules, module); 157 } 158 return ImmutableSet.copyOf(transitiveModules); 159 } 160 161 ImmutableSet<TypeElement> transitiveModuleTypes() { 162 return FluentIterable.from(transitiveModules()) 163 .transform(ModuleDescriptor.getModuleElement()) 164 .toSet(); 165 } 166 167 private static Set<ModuleDescriptor> addTransitiveModules( 168 Set<ModuleDescriptor> transitiveModules, ModuleDescriptor module) { 169 if (transitiveModules.add(module)) { 170 for (ModuleDescriptor includedModule : module.includedModules()) { 171 addTransitiveModules(transitiveModules, includedModule); 172 } 173 } 174 return transitiveModules; 175 } 176 177 /** 178 * An index of the type to which this component holds a reference (the type listed in 179 * {@link Component#dependencies} or {@link ProductionComponent#dependencies} as opposed to the 180 * enclosing type) for each method from a component dependency that can be used for binding. 181 */ 182 abstract ImmutableMap<ExecutableElement, TypeElement> dependencyMethodIndex(); 183 184 /** 185 * The element representing {@link Executor}, if it should be a dependency of this component. 186 */ 187 abstract Optional<TypeElement> executorDependency(); 188 189 /** 190 * The scope of the component. 191 */ 192 abstract Scope scope(); 193 194 abstract ImmutableMap<ComponentMethodDescriptor, ComponentDescriptor> subcomponents(); 195 196 abstract ImmutableSet<ComponentMethodDescriptor> componentMethods(); 197 198 // TODO(gak): Consider making this non-optional and revising the 199 // interaction between the spec & generation 200 abstract Optional<BuilderSpec> builderSpec(); 201 202 @AutoValue 203 static abstract class ComponentMethodDescriptor { 204 abstract ComponentMethodKind kind(); 205 abstract Optional<DependencyRequest> dependencyRequest(); 206 abstract ExecutableElement methodElement(); 207 208 /** 209 * A predicate that passes for {@link ComponentMethodDescriptor}s of a given kind. 210 */ 211 static Predicate<ComponentMethodDescriptor> isOfKind(final ComponentMethodKind kind) { 212 return new Predicate<ComponentMethodDescriptor>() { 213 @Override 214 public boolean apply(ComponentMethodDescriptor descriptor) { 215 return kind.equals(descriptor.kind()); 216 } 217 }; 218 } 219 } 220 221 enum ComponentMethodKind { 222 PROVISON, 223 PRODUCTION, 224 MEMBERS_INJECTION, 225 SUBCOMPONENT, 226 SUBCOMPONENT_BUILDER, 227 } 228 229 @AutoValue 230 static abstract class BuilderSpec { 231 abstract TypeElement builderDefinitionType(); 232 abstract Map<TypeElement, ExecutableElement> methodMap(); 233 abstract ExecutableElement buildMethod(); 234 abstract TypeMirror componentType(); 235 } 236 237 static final class Factory { 238 private final Elements elements; 239 private final Types types; 240 private final DependencyRequest.Factory dependencyRequestFactory; 241 private final ModuleDescriptor.Factory moduleDescriptorFactory; 242 243 Factory( 244 Elements elements, 245 Types types, 246 DependencyRequest.Factory dependencyRequestFactory, 247 ModuleDescriptor.Factory moduleDescriptorFactory) { 248 this.elements = elements; 249 this.types = types; 250 this.dependencyRequestFactory = dependencyRequestFactory; 251 this.moduleDescriptorFactory = moduleDescriptorFactory; 252 } 253 254 /** 255 * Returns a component descriptor for a type annotated with either {@link Component @Component} 256 * or {@link ProductionComponent @ProductionComponent}. 257 */ 258 ComponentDescriptor forComponent(TypeElement componentDefinitionType) { 259 Optional<Kind> kind = Kind.forAnnotatedElement(componentDefinitionType); 260 checkArgument( 261 kind.isPresent() && kind.get().isTopLevel(), 262 "%s must be annotated with @Component or @ProductionComponent", 263 componentDefinitionType); 264 return create(componentDefinitionType, kind.get()); 265 } 266 267 private ComponentDescriptor create(TypeElement componentDefinitionType, Kind kind) { 268 DeclaredType declaredComponentType = MoreTypes.asDeclared(componentDefinitionType.asType()); 269 AnnotationMirror componentMirror = 270 getAnnotationMirror(componentDefinitionType, kind.annotationType()) 271 .or(getAnnotationMirror(componentDefinitionType, Subcomponent.class)) 272 .get(); 273 ImmutableSet<TypeElement> componentDependencyTypes = 274 isComponent(componentDefinitionType) 275 ? MoreTypes.asTypeElements(getComponentDependencies(componentMirror)) 276 : ImmutableSet.<TypeElement>of(); 277 278 ImmutableMap.Builder<ExecutableElement, TypeElement> dependencyMethodIndex = 279 ImmutableMap.builder(); 280 281 for (TypeElement componentDependency : componentDependencyTypes) { 282 List<ExecutableElement> dependencyMethods = 283 ElementFilter.methodsIn(elements.getAllMembers(componentDependency)); 284 for (ExecutableElement dependencyMethod : dependencyMethods) { 285 if (isComponentContributionMethod(elements, dependencyMethod)) { 286 dependencyMethodIndex.put(dependencyMethod, componentDependency); 287 } 288 } 289 } 290 291 Optional<TypeElement> executorDependency = 292 kind.equals(Kind.PRODUCTION_COMPONENT) 293 ? Optional.of(elements.getTypeElement(Executor.class.getCanonicalName())) 294 : Optional.<TypeElement>absent(); 295 296 ImmutableSet.Builder<ModuleDescriptor> modules = ImmutableSet.builder(); 297 for (TypeMirror moduleIncludesType : getComponentModules(componentMirror)) { 298 modules.add(moduleDescriptorFactory.create(MoreTypes.asTypeElement(moduleIncludesType))); 299 } 300 if (kind.equals(Kind.PRODUCTION_COMPONENT)) { 301 modules.add(descriptorForMonitoringModule(componentDefinitionType)); 302 } 303 304 ImmutableSet<ExecutableElement> unimplementedMethods = 305 Util.getUnimplementedMethods(elements, componentDefinitionType); 306 307 ImmutableSet.Builder<ComponentMethodDescriptor> componentMethodsBuilder = 308 ImmutableSet.builder(); 309 310 ImmutableMap.Builder<ComponentMethodDescriptor, ComponentDescriptor> subcomponentDescriptors = 311 ImmutableMap.builder(); 312 for (ExecutableElement componentMethod : unimplementedMethods) { 313 ExecutableType resolvedMethod = 314 MoreTypes.asExecutable(types.asMemberOf(declaredComponentType, componentMethod)); 315 ComponentMethodDescriptor componentMethodDescriptor = 316 getDescriptorForComponentMethod(componentDefinitionType, kind, componentMethod); 317 componentMethodsBuilder.add(componentMethodDescriptor); 318 switch (componentMethodDescriptor.kind()) { 319 case SUBCOMPONENT: 320 subcomponentDescriptors.put( 321 componentMethodDescriptor, 322 create( 323 MoreElements.asType(MoreTypes.asElement(resolvedMethod.getReturnType())), 324 Kind.SUBCOMPONENT)); 325 break; 326 case SUBCOMPONENT_BUILDER: 327 subcomponentDescriptors.put( 328 componentMethodDescriptor, 329 create( 330 MoreElements.asType( 331 MoreTypes.asElement(resolvedMethod.getReturnType()).getEnclosingElement()), 332 Kind.SUBCOMPONENT)); 333 break; 334 default: // nothing special to do for other methods. 335 } 336 337 } 338 339 ImmutableList<DeclaredType> enclosedBuilders = kind.builderAnnotationType() == null 340 ? ImmutableList.<DeclaredType>of() 341 : enclosedBuilders(componentDefinitionType, kind.builderAnnotationType()); 342 Optional<DeclaredType> builderType = 343 Optional.fromNullable(getOnlyElement(enclosedBuilders, null)); 344 345 Scope scope = Scope.scopeOf(componentDefinitionType); 346 return new AutoValue_ComponentDescriptor( 347 kind, 348 componentMirror, 349 componentDefinitionType, 350 componentDependencyTypes, 351 modules.build(), 352 dependencyMethodIndex.build(), 353 executorDependency, 354 scope, 355 subcomponentDescriptors.build(), 356 componentMethodsBuilder.build(), 357 createBuilderSpec(builderType)); 358 } 359 360 private ComponentMethodDescriptor getDescriptorForComponentMethod(TypeElement componentElement, 361 Kind componentKind, 362 ExecutableElement componentMethod) { 363 ExecutableType resolvedComponentMethod = MoreTypes.asExecutable(types.asMemberOf( 364 MoreTypes.asDeclared(componentElement.asType()), componentMethod)); 365 TypeMirror returnType = resolvedComponentMethod.getReturnType(); 366 if (returnType.getKind().equals(DECLARED)) { 367 if (MoreTypes.isTypeOf(Provider.class, returnType) 368 || MoreTypes.isTypeOf(Lazy.class, returnType)) { 369 return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor( 370 ComponentMethodKind.PROVISON, 371 Optional.of(dependencyRequestFactory.forComponentProvisionMethod(componentMethod, 372 resolvedComponentMethod)), 373 componentMethod); 374 } else if (MoreTypes.isTypeOf(MembersInjector.class, returnType)) { 375 return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor( 376 ComponentMethodKind.MEMBERS_INJECTION, 377 Optional.of(dependencyRequestFactory.forComponentMembersInjectionMethod( 378 componentMethod, 379 resolvedComponentMethod)), 380 componentMethod); 381 } else if (isAnnotationPresent(MoreTypes.asElement(returnType), Subcomponent.class)) { 382 return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor( 383 ComponentMethodKind.SUBCOMPONENT, 384 Optional.<DependencyRequest>absent(), 385 componentMethod); 386 } else if (isAnnotationPresent(MoreTypes.asElement(returnType), 387 Subcomponent.Builder.class)) { 388 return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor( 389 ComponentMethodKind.SUBCOMPONENT_BUILDER, 390 Optional.<DependencyRequest>absent(), 391 componentMethod); 392 } 393 } 394 395 // a typical provision method 396 if (componentMethod.getParameters().isEmpty() 397 && !componentMethod.getReturnType().getKind().equals(VOID)) { 398 switch (componentKind) { 399 case COMPONENT: 400 case SUBCOMPONENT: 401 return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor( 402 ComponentMethodKind.PROVISON, 403 Optional.of(dependencyRequestFactory.forComponentProvisionMethod(componentMethod, 404 resolvedComponentMethod)), 405 componentMethod); 406 case PRODUCTION_COMPONENT: 407 return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor( 408 ComponentMethodKind.PRODUCTION, 409 Optional.of(dependencyRequestFactory.forComponentProductionMethod(componentMethod, 410 resolvedComponentMethod)), 411 componentMethod); 412 default: 413 throw new AssertionError(); 414 } 415 } 416 417 List<? extends TypeMirror> parameterTypes = resolvedComponentMethod.getParameterTypes(); 418 if (parameterTypes.size() == 1 419 && (returnType.getKind().equals(VOID) 420 || MoreTypes.equivalence().equivalent(returnType, parameterTypes.get(0)))) { 421 return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor( 422 ComponentMethodKind.MEMBERS_INJECTION, 423 Optional.of(dependencyRequestFactory.forComponentMembersInjectionMethod( 424 componentMethod, 425 resolvedComponentMethod)), 426 componentMethod); 427 } 428 429 throw new IllegalArgumentException("not a valid component method: " + componentMethod); 430 } 431 432 private Optional<BuilderSpec> createBuilderSpec(Optional<DeclaredType> builderType) { 433 if (!builderType.isPresent()) { 434 return Optional.absent(); 435 } 436 TypeElement element = MoreTypes.asTypeElement(builderType.get()); 437 ImmutableSet<ExecutableElement> methods = Util.getUnimplementedMethods(elements, element); 438 ImmutableMap.Builder<TypeElement, ExecutableElement> map = ImmutableMap.builder(); 439 ExecutableElement buildMethod = null; 440 for (ExecutableElement method : methods) { 441 if (method.getParameters().isEmpty()) { 442 buildMethod = method; 443 } else { 444 ExecutableType resolved = 445 MoreTypes.asExecutable(types.asMemberOf(builderType.get(), method)); 446 map.put(MoreTypes.asTypeElement(getOnlyElement(resolved.getParameterTypes())), method); 447 } 448 } 449 verify(buildMethod != null); // validation should have ensured this. 450 return Optional.<BuilderSpec>of(new AutoValue_ComponentDescriptor_BuilderSpec(element, 451 map.build(), buildMethod, element.getEnclosingElement().asType())); 452 } 453 454 /** 455 * Returns a descriptor for a generated module that handles monitoring for production 456 * components. This module is generated in the {@link MonitoringModuleProcessingStep}. 457 * 458 * @throws TypeNotPresentException if the module has not been generated yet. This will cause the 459 * processor to retry in a later processing round. 460 */ 461 private ModuleDescriptor descriptorForMonitoringModule(TypeElement componentDefinitionType) { 462 String generatedMonitorModuleName = 463 SourceFiles.generatedMonitoringModuleName(componentDefinitionType).canonicalName(); 464 TypeElement monitoringModule = elements.getTypeElement(generatedMonitorModuleName); 465 if (monitoringModule == null) { 466 throw new TypeNotPresentException(generatedMonitorModuleName, null); 467 } 468 return moduleDescriptorFactory.create(monitoringModule); 469 } 470 } 471 472 static boolean isComponentContributionMethod(Elements elements, ExecutableElement method) { 473 return method.getParameters().isEmpty() 474 && !method.getReturnType().getKind().equals(VOID) 475 && !elements.getTypeElement(Object.class.getCanonicalName()) 476 .equals(method.getEnclosingElement()); 477 } 478 479 static boolean isComponentProductionMethod(Elements elements, ExecutableElement method) { 480 return isComponentContributionMethod(elements, method) 481 && MoreTypes.isTypeOf(ListenableFuture.class, method.getReturnType()); 482 } 483 } 484