1 /* 2 * Copyright (C) 2016 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.common.base.CaseFormat.LOWER_CAMEL; 20 import static com.google.common.base.CaseFormat.UPPER_CAMEL; 21 import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE; 22 import static com.google.common.base.Preconditions.checkArgument; 23 import static com.google.common.base.Preconditions.checkNotNull; 24 import static com.google.common.base.Preconditions.checkState; 25 import static com.squareup.javapoet.TypeSpec.classBuilder; 26 import static dagger.internal.codegen.ComponentCreatorKind.BUILDER; 27 import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom; 28 import static dagger.internal.codegen.serialization.ProtoSerialization.toAnnotationValue; 29 import static java.util.stream.Collectors.toList; 30 import static javax.lang.model.element.Modifier.ABSTRACT; 31 import static javax.lang.model.element.Modifier.FINAL; 32 import static javax.lang.model.element.Modifier.PUBLIC; 33 34 import com.google.auto.value.AutoValue; 35 import com.google.common.base.Supplier; 36 import com.google.common.collect.ImmutableList; 37 import com.google.common.collect.ImmutableMap; 38 import com.google.common.collect.ImmutableSet; 39 import com.google.common.collect.LinkedHashMultimap; 40 import com.google.common.collect.ListMultimap; 41 import com.google.common.collect.Maps; 42 import com.google.common.collect.MultimapBuilder; 43 import com.google.common.collect.SetMultimap; 44 import com.google.common.collect.Sets; 45 import com.squareup.javapoet.AnnotationSpec; 46 import com.squareup.javapoet.ClassName; 47 import com.squareup.javapoet.CodeBlock; 48 import com.squareup.javapoet.FieldSpec; 49 import com.squareup.javapoet.MethodSpec; 50 import com.squareup.javapoet.TypeSpec; 51 import dagger.internal.ConfigureInitializationParameters; 52 import dagger.internal.ModifiableBinding; 53 import dagger.internal.ModifiableModule; 54 import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod; 55 import dagger.internal.codegen.javapoet.TypeSpecs; 56 import dagger.model.DependencyRequest; 57 import dagger.model.Key; 58 import dagger.model.RequestKind; 59 import java.util.ArrayList; 60 import java.util.HashMap; 61 import java.util.HashSet; 62 import java.util.LinkedHashMap; 63 import java.util.LinkedHashSet; 64 import java.util.List; 65 import java.util.Map; 66 import java.util.Optional; 67 import java.util.Set; 68 import javax.lang.model.element.Modifier; 69 import javax.lang.model.element.NestingKind; 70 import javax.lang.model.element.TypeElement; 71 import javax.lang.model.type.TypeMirror; 72 73 /** The implementation of a component type. */ 74 final class ComponentImplementation { 75 /** A type of field that this component can contain. */ 76 enum FieldSpecKind { 77 78 /** A field required by the component, e.g. module instances. */ 79 COMPONENT_REQUIREMENT_FIELD, 80 81 /** 82 * A field for the lock and cached value for {@linkplain PrivateMethodBindingExpression 83 * private-method scoped bindings}. 84 */ 85 PRIVATE_METHOD_SCOPED_FIELD, 86 87 /** A framework field for type T, e.g. {@code Provider<T>}. */ 88 FRAMEWORK_FIELD, 89 90 /** A static field that always returns an absent {@code Optional} value for the binding. */ 91 ABSENT_OPTIONAL_FIELD 92 } 93 94 /** A type of method that this component can contain. */ 95 // TODO(user, dpb): Change the oder to constructor, initialize, component, then private 96 // (including MIM and AOM—why treat those separately?). 97 enum MethodSpecKind { 98 /** The component constructor. */ 99 CONSTRUCTOR, 100 101 /** 102 * In ahead-of-time subcomponents, this method coordinates the invocation of {@link 103 * #INITIALIZE_METHOD initialization methods} instead of constructors. 104 */ 105 // TODO(b/117833324): try to merge this with other initialize() methods so it looks more natural 106 CONFIGURE_INITIALIZATION_METHOD, 107 108 /** A builder method for the component. (Only used by the root component.) */ 109 BUILDER_METHOD, 110 111 /** A private method that wraps dependency expressions. */ 112 PRIVATE_METHOD, 113 114 /** An initialization method that initializes component requirements and framework types. */ 115 INITIALIZE_METHOD, 116 117 /** An implementation of a component interface method. */ 118 COMPONENT_METHOD, 119 120 /** A private method that encapsulates members injection logic for a binding. */ 121 MEMBERS_INJECTION_METHOD, 122 123 /** A static method that always returns an absent {@code Optional} value for the binding. */ 124 ABSENT_OPTIONAL_METHOD, 125 126 /** 127 * A method that encapsulates a modifiable binding. A binding is modifiable if it can change 128 * across implementations of a subcomponent. This is only relevant for ahead-of-time 129 * subcomponents. 130 */ 131 MODIFIABLE_BINDING_METHOD, 132 133 /** 134 * The {@link dagger.producers.internal.CancellationListener#onProducerFutureCancelled(boolean)} 135 * method for a production component. 136 */ 137 CANCELLATION_LISTENER_METHOD, 138 ; 139 } 140 141 /** A type of nested class that this component can contain. */ 142 enum TypeSpecKind { 143 /** A factory class for a present optional binding. */ 144 PRESENT_FACTORY, 145 146 /** A class for the component creator (only used by the root component.) */ 147 COMPONENT_CREATOR, 148 149 /** A provider class for a component provision. */ 150 COMPONENT_PROVISION_FACTORY, 151 152 /** A class for the subcomponent or subcomponent builder. */ 153 SUBCOMPONENT 154 } 155 156 /** 157 * The method spec for a {@code configureInitialization} method plus details on the component 158 * requirements that its parameters are associated with. 159 */ 160 @AutoValue 161 abstract static class ConfigureInitializationMethod { 162 /** Creates a new {@link ConfigureInitializationMethod}. */ create( MethodSpec spec, ImmutableSet<ComponentRequirement> parameters)163 static ConfigureInitializationMethod create( 164 MethodSpec spec, ImmutableSet<ComponentRequirement> parameters) { 165 return new AutoValue_ComponentImplementation_ConfigureInitializationMethod(spec, parameters); 166 } 167 168 /** The spec for the method. */ spec()169 abstract MethodSpec spec(); 170 171 /** 172 * The component requirements associated with the method's parameters, in the same order as the 173 * parameters. 174 */ parameters()175 abstract ImmutableSet<ComponentRequirement> parameters(); 176 } 177 178 private final CompilerOptions compilerOptions; 179 private final ComponentDescriptor componentDescriptor; 180 private final Optional<BindingGraph> graph; 181 private final ClassName name; 182 private final NestingKind nestingKind; 183 private final boolean isAbstract; 184 private final Optional<ComponentImplementation> superclassImplementation; 185 private Optional<ComponentCreatorImplementation> creatorImplementation; 186 private final Map<TypeElement, ComponentImplementation> childImplementations = new HashMap<>(); 187 private final TypeSpec.Builder component; 188 private final Optional<SubcomponentNames> subcomponentNames; 189 private final UniqueNameSet componentFieldNames = new UniqueNameSet(); 190 private final UniqueNameSet componentMethodNames = new UniqueNameSet(); 191 private final List<CodeBlock> initializations = new ArrayList<>(); 192 private final Set<ComponentRequirement> componentRequirementParameters = new HashSet<>(); 193 private final List<CodeBlock> componentRequirementInitializations = new ArrayList<>(); 194 private final Map<ComponentRequirement, String> componentRequirementParameterNames = 195 new HashMap<>(); 196 private final Set<Key> cancellableProducerKeys = new LinkedHashSet<>(); 197 private final ListMultimap<FieldSpecKind, FieldSpec> fieldSpecsMap = 198 MultimapBuilder.enumKeys(FieldSpecKind.class).arrayListValues().build(); 199 private final ListMultimap<MethodSpecKind, MethodSpec> methodSpecsMap = 200 MultimapBuilder.enumKeys(MethodSpecKind.class).arrayListValues().build(); 201 private final ListMultimap<TypeSpecKind, TypeSpec> typeSpecsMap = 202 MultimapBuilder.enumKeys(TypeSpecKind.class).arrayListValues().build(); 203 private final List<Supplier<TypeSpec>> switchingProviderSupplier = new ArrayList<>(); 204 private final ModifiableBindingMethods modifiableBindingMethods = new ModifiableBindingMethods(); 205 private final SetMultimap<BindingRequest, Key> multibindingContributionsMade = 206 LinkedHashMultimap.create(); 207 private Optional<ConfigureInitializationMethod> configureInitializationMethod = Optional.empty(); 208 private final Map<ComponentRequirement, String> modifiableModuleMethods = new LinkedHashMap<>(); 209 ComponentImplementation( ComponentDescriptor componentDescriptor, Optional<BindingGraph> graph, ClassName name, NestingKind nestingKind, Optional<ComponentImplementation> superclassImplementation, Optional<SubcomponentNames> subcomponentNames, CompilerOptions compilerOptions, ImmutableSet<Modifier> modifiers)210 private ComponentImplementation( 211 ComponentDescriptor componentDescriptor, 212 Optional<BindingGraph> graph, 213 ClassName name, 214 NestingKind nestingKind, 215 Optional<ComponentImplementation> superclassImplementation, 216 Optional<SubcomponentNames> subcomponentNames, 217 CompilerOptions compilerOptions, 218 ImmutableSet<Modifier> modifiers) { 219 checkName(name, nestingKind); 220 this.compilerOptions = compilerOptions; 221 this.componentDescriptor = componentDescriptor; 222 this.graph = graph; 223 this.name = name; 224 this.nestingKind = nestingKind; 225 this.isAbstract = modifiers.contains(ABSTRACT); 226 this.superclassImplementation = superclassImplementation; 227 this.component = classBuilder(name); 228 modifiers.forEach(component::addModifiers); 229 this.subcomponentNames = subcomponentNames; 230 } 231 232 /** Returns a component implementation for a top-level component. */ topLevelComponentImplementation( BindingGraph graph, ClassName name, SubcomponentNames subcomponentNames, CompilerOptions compilerOptions)233 static ComponentImplementation topLevelComponentImplementation( 234 BindingGraph graph, 235 ClassName name, 236 SubcomponentNames subcomponentNames, 237 CompilerOptions compilerOptions) { 238 return new ComponentImplementation( 239 graph.componentDescriptor(), 240 Optional.of(graph), 241 name, 242 NestingKind.TOP_LEVEL, 243 Optional.empty(), // superclass implementation 244 Optional.of(subcomponentNames), 245 compilerOptions, 246 topLevelComponentImplementationModifiers(graph)); 247 } 248 topLevelComponentImplementationModifiers( BindingGraph graph)249 private static ImmutableSet<Modifier> topLevelComponentImplementationModifiers( 250 BindingGraph graph) { 251 ImmutableSet.Builder<Modifier> modifiers = ImmutableSet.builder(); 252 if (graph.componentTypeElement().getModifiers().contains(PUBLIC) 253 || graph.componentDescriptor().isSubcomponent()) { 254 // TODO(ronshapiro): perhaps all generated components should be non-public? 255 modifiers.add(PUBLIC); 256 } 257 return modifiers.add(graph.componentDescriptor().isSubcomponent() ? ABSTRACT : FINAL).build(); 258 } 259 260 /** Returns a component implementation that is a child of the current implementation. */ childComponentImplementation( BindingGraph graph, Optional<ComponentImplementation> superclassImplementation, Modifier... modifiers)261 ComponentImplementation childComponentImplementation( 262 BindingGraph graph, 263 Optional<ComponentImplementation> superclassImplementation, 264 Modifier... modifiers) { 265 return new ComponentImplementation( 266 graph.componentDescriptor(), 267 Optional.of(graph), 268 getSubcomponentName(graph.componentDescriptor()), 269 NestingKind.MEMBER, 270 superclassImplementation, 271 subcomponentNames, 272 compilerOptions, 273 ImmutableSet.copyOf(modifiers)); 274 } 275 276 /** 277 * Returns a component implementation that models a previously compiled class. This {@link 278 * ComponentImplementation} is not used for code generation itself; it is used to determine what 279 * methods need to be implemented in a subclass implementation. 280 */ forDeserializedComponent( ComponentDescriptor componentDescriptor, ClassName name, NestingKind nestingKind, Optional<ComponentImplementation> superclassImplementation, CompilerOptions compilerOptions)281 static ComponentImplementation forDeserializedComponent( 282 ComponentDescriptor componentDescriptor, 283 ClassName name, 284 NestingKind nestingKind, 285 Optional<ComponentImplementation> superclassImplementation, 286 CompilerOptions compilerOptions) { 287 return new ComponentImplementation( 288 componentDescriptor, 289 Optional.empty(), 290 name, 291 nestingKind, 292 superclassImplementation, 293 Optional.empty(), 294 compilerOptions, 295 ImmutableSet.of(PUBLIC, ABSTRACT)); 296 } 297 298 // TODO(dpb): Just determine the nesting kind from the name. checkName(ClassName name, NestingKind nestingKind)299 private static void checkName(ClassName name, NestingKind nestingKind) { 300 switch (nestingKind) { 301 case TOP_LEVEL: 302 checkArgument( 303 name.enclosingClassName() == null, "must be a top-level class name: %s", name); 304 break; 305 306 case MEMBER: 307 checkNotNull(name.enclosingClassName(), "must not be a top-level class name: %s", name); 308 break; 309 310 default: 311 throw new IllegalArgumentException( 312 "nestingKind must be TOP_LEVEL or MEMBER: " + nestingKind); 313 } 314 } 315 316 /** 317 * Returns {@code true} if this component implementation represents a component that has already 318 * been compiled. If this returns true, the implementation will have no {@link #graph 319 * BindingGraph}. 320 */ isDeserializedImplementation()321 boolean isDeserializedImplementation() { 322 return !graph.isPresent(); 323 } 324 325 // TODO(ronshapiro): see if we can remove this method and instead inject it in the objects that 326 // need it. 327 /** Returns the binding graph for the component being generated. */ graph()328 BindingGraph graph() { 329 checkState(!isDeserializedImplementation(), 330 "A BindingGraph is not available for deserialized component implementations."); 331 return graph.get(); 332 } 333 334 /** Returns the descriptor for the component being generated. */ componentDescriptor()335 ComponentDescriptor componentDescriptor() { 336 return componentDescriptor; 337 } 338 339 /** Returns the name of the component. */ name()340 ClassName name() { 341 return name; 342 } 343 344 /** Returns whether or not the implementation is nested within another class. */ isNested()345 boolean isNested() { 346 return nestingKind.isNested(); 347 } 348 349 /** Returns whether or not the implementation is abstract. */ isAbstract()350 boolean isAbstract() { 351 return isAbstract; 352 } 353 354 /** Returns the superclass implementation. */ superclassImplementation()355 Optional<ComponentImplementation> superclassImplementation() { 356 return superclassImplementation; 357 } 358 359 /** 360 * Returns the base implementation of this component in ahead-of-time subcomponents mode. If this 361 * is the base implementation, this returns {@link Optional#empty()}. 362 */ baseImplementation()363 Optional<ComponentImplementation> baseImplementation() { 364 return superclassImplementation.isPresent() 365 ? Optional.of(Optionals.rootmostValue(this, c -> c.superclassImplementation)) 366 : Optional.empty(); 367 } 368 369 /** 370 * Returns the {@link #configureInitializationMethod()} of the nearest supertype that defines one, 371 * if any. 372 * 373 * <p>Only returns a present value in {@link CompilerOptions#aheadOfTimeSubcomponents()}. 374 */ superConfigureInitializationMethod()375 Optional<ConfigureInitializationMethod> superConfigureInitializationMethod() { 376 for (Optional<ComponentImplementation> currentSuper = superclassImplementation; 377 currentSuper.isPresent(); 378 currentSuper = currentSuper.get().superclassImplementation) { 379 if (currentSuper.get().configureInitializationMethod.isPresent()) { 380 return currentSuper.get().configureInitializationMethod; 381 } 382 } 383 return Optional.empty(); 384 } 385 386 /** 387 * The requirements for creating an instance of this component implementation type. 388 * 389 * <p>If this component implementation is concrete, these requirements will be in the order that 390 * the implementation's constructor takes them as parameters. 391 */ requirements()392 ImmutableSet<ComponentRequirement> requirements() { 393 // If the base implementation's creator is being generated in ahead-of-time-subcomponents 394 // mode, this uses the ComponentDescriptor's requirements() since Dagger doesn't know what 395 // modules may end being unused or owned by an ancestor component. Otherwise, we use the 396 // necessary component requirements. 397 // TODO(ronshapiro): can we remove the second condition here? Or, is it never going to be 398 // called, so we should enforce that invariant? 399 return isAbstract() && !superclassImplementation().isPresent() 400 ? componentDescriptor().requirements() 401 : graph().componentRequirements(); 402 } 403 404 /** 405 * Returns the {@link MethodSpecKind#CONFIGURE_INITIALIZATION_METHOD} of this implementation if 406 * there is one. 407 * 408 * <p>Only returns a present value in {@link CompilerOptions#aheadOfTimeSubcomponents()}. 409 */ configureInitializationMethod()410 Optional<ConfigureInitializationMethod> configureInitializationMethod() { 411 return configureInitializationMethod; 412 } 413 414 /** 415 * Set's this component implementation's {@code configureInitialization()} method and {@linkplain 416 * #addMethod(MethodSpecKind, MethodSpec) adds the method}. 417 */ setConfigureInitializationMethod(ConfigureInitializationMethod method)418 void setConfigureInitializationMethod(ConfigureInitializationMethod method) { 419 configureInitializationMethod = Optional.of(method); 420 addMethod( 421 MethodSpecKind.CONFIGURE_INITIALIZATION_METHOD, 422 addConfigureInitializationMetadata(method)); 423 } 424 addConfigureInitializationMetadata(ConfigureInitializationMethod method)425 private MethodSpec addConfigureInitializationMetadata(ConfigureInitializationMethod method) { 426 if (!shouldEmitModifiableMetadataAnnotations()) { 427 return method.spec(); 428 } 429 AnnotationSpec.Builder annotation = 430 AnnotationSpec.builder(ConfigureInitializationParameters.class); 431 for (ComponentRequirement parameter : method.parameters()) { 432 annotation.addMember("value", toAnnotationValue(parameter.toProto())); 433 } 434 435 return method.spec().toBuilder().addAnnotation(annotation.build()).build(); 436 } 437 setCreatorImplementation(Optional<ComponentCreatorImplementation> creatorImplementation)438 void setCreatorImplementation(Optional<ComponentCreatorImplementation> creatorImplementation) { 439 checkState( 440 this.creatorImplementation == null, "setCreatorImplementation has already been called"); 441 this.creatorImplementation = creatorImplementation; 442 } 443 creatorImplementation()444 Optional<ComponentCreatorImplementation> creatorImplementation() { 445 checkState(creatorImplementation != null, "setCreatorImplementation has not been called yet"); 446 return creatorImplementation; 447 } 448 449 /** 450 * Returns the {@link ComponentCreatorImplementation} defined in the base implementation for this 451 * component, if one exists. 452 */ baseCreatorImplementation()453 Optional<ComponentCreatorImplementation> baseCreatorImplementation() { 454 return baseImplementation().flatMap(baseImpl -> baseImpl.creatorImplementation()); 455 } 456 457 /** 458 * Returns the kind of this component's creator. 459 * 460 * @throws IllegalStateException if the component has no creator 461 */ creatorKind()462 private ComponentCreatorKind creatorKind() { 463 checkState(componentDescriptor().hasCreator()); 464 return componentDescriptor() 465 .creatorDescriptor() 466 .map(ComponentCreatorDescriptor::kind) 467 .orElse(BUILDER); 468 } 469 470 /** 471 * Returns the name of the creator class for this component. It will be a sibling of this 472 * generated class unless this is a top-level component, in which case it will be nested. 473 */ getCreatorName()474 ClassName getCreatorName() { 475 return isNested() 476 ? name.peerClass(subcomponentNames().getCreatorName(componentDescriptor())) 477 : name.nestedClass(creatorKind().typeName()); 478 } 479 480 /** Returns the name of the nested implementation class for a child component. */ getSubcomponentName(ComponentDescriptor childDescriptor)481 ClassName getSubcomponentName(ComponentDescriptor childDescriptor) { 482 checkArgument( 483 componentDescriptor().childComponents().contains(childDescriptor), 484 "%s is not a child component of %s", 485 childDescriptor.typeElement(), 486 componentDescriptor().typeElement()); 487 return name.nestedClass(subcomponentNames().get(childDescriptor) + "Impl"); 488 } 489 490 /** 491 * Returns the simple name of the creator implementation class for the given subcomponent creator 492 * {@link Key}. 493 */ getSubcomponentCreatorSimpleName(Key key)494 String getSubcomponentCreatorSimpleName(Key key) { 495 return subcomponentNames().getCreatorName(key); 496 } 497 subcomponentNames()498 private SubcomponentNames subcomponentNames() { 499 checkState( 500 subcomponentNames.isPresent(), 501 "SubcomponentNames is not available for deserialized component implementations."); 502 return subcomponentNames.get(); 503 } 504 505 /** Returns the child implementation. */ childImplementation(ComponentDescriptor child)506 Optional<ComponentImplementation> childImplementation(ComponentDescriptor child) { 507 return Optional.ofNullable(childImplementations.get(child.typeElement())); 508 } 509 510 /** Returns {@code true} if {@code type} is accessible from the generated component. */ isTypeAccessible(TypeMirror type)511 boolean isTypeAccessible(TypeMirror type) { 512 return isTypeAccessibleFrom(type, name.packageName()); 513 } 514 515 /** Adds the given super type to the component. */ addSupertype(TypeElement supertype)516 void addSupertype(TypeElement supertype) { 517 TypeSpecs.addSupertype(component, supertype); 518 } 519 520 /** Adds the given super class to the subcomponent. */ addSuperclass(ClassName className)521 void addSuperclass(ClassName className) { 522 checkState( 523 superclassImplementation.isPresent(), 524 "Setting the superclass for component [%s] when there is no superclass implementation.", 525 name); 526 component.superclass(className); 527 } 528 529 // TODO(dpb): Consider taking FieldSpec, and returning identical FieldSpec with unique name? 530 /** Adds the given field to the component. */ addField(FieldSpecKind fieldKind, FieldSpec fieldSpec)531 void addField(FieldSpecKind fieldKind, FieldSpec fieldSpec) { 532 fieldSpecsMap.put(fieldKind, fieldSpec); 533 } 534 535 /** Adds the given fields to the component. */ addFields(FieldSpecKind fieldKind, Iterable<FieldSpec> fieldSpecs)536 void addFields(FieldSpecKind fieldKind, Iterable<FieldSpec> fieldSpecs) { 537 fieldSpecsMap.putAll(fieldKind, fieldSpecs); 538 } 539 540 // TODO(dpb): Consider taking MethodSpec, and returning identical MethodSpec with unique name? 541 /** Adds the given method to the component. */ addMethod(MethodSpecKind methodKind, MethodSpec methodSpec)542 void addMethod(MethodSpecKind methodKind, MethodSpec methodSpec) { 543 methodSpecsMap.put(methodKind, methodSpec); 544 } 545 546 /** Adds the given annotation to the component. */ addAnnotation(AnnotationSpec annotation)547 void addAnnotation(AnnotationSpec annotation) { 548 component.addAnnotation(annotation); 549 } 550 551 /** 552 * Adds the given method to the component. In this case, the method represents an encapsulation of 553 * a modifiable binding between implementations of a subcomponent. This is only relevant for 554 * ahead-of-time subcomponents. 555 */ addModifiableBindingMethod( ModifiableBindingType type, BindingRequest request, TypeMirror returnType, MethodSpec methodSpec, boolean finalized)556 void addModifiableBindingMethod( 557 ModifiableBindingType type, 558 BindingRequest request, 559 TypeMirror returnType, 560 MethodSpec methodSpec, 561 boolean finalized) { 562 addModifiableMethod( 563 MethodSpecKind.MODIFIABLE_BINDING_METHOD, type, request, returnType, methodSpec, finalized); 564 } 565 566 /** 567 * Adds a component method that is modifiable to the component. In this case, the method 568 * represents an encapsulation of a modifiable binding between implementations of a subcomponent. 569 * This is only relevant for ahead-of-time subcomponents. 570 */ addModifiableComponentMethod( ModifiableBindingType type, BindingRequest request, TypeMirror returnType, MethodSpec methodSpec, boolean finalized)571 void addModifiableComponentMethod( 572 ModifiableBindingType type, 573 BindingRequest request, 574 TypeMirror returnType, 575 MethodSpec methodSpec, 576 boolean finalized) { 577 addModifiableMethod( 578 MethodSpecKind.COMPONENT_METHOD, type, request, returnType, methodSpec, finalized); 579 } 580 addModifiableMethod( MethodSpecKind methodKind, ModifiableBindingType type, BindingRequest request, TypeMirror returnType, MethodSpec methodSpec, boolean finalized)581 private void addModifiableMethod( 582 MethodSpecKind methodKind, 583 ModifiableBindingType type, 584 BindingRequest request, 585 TypeMirror returnType, 586 MethodSpec methodSpec, 587 boolean finalized) { 588 modifiableBindingMethods.addModifiableMethod( 589 type, request, returnType, methodSpec, finalized); 590 methodSpecsMap.put(methodKind, withModifiableBindingMetadata(methodSpec, type, request)); 591 } 592 593 /** Adds the implementation for the given {@link ModifiableBindingMethod} to the component. */ addImplementedModifiableBindingMethod(ModifiableBindingMethod method)594 void addImplementedModifiableBindingMethod(ModifiableBindingMethod method) { 595 modifiableBindingMethods.addReimplementedMethod(method); 596 methodSpecsMap.put( 597 MethodSpecKind.MODIFIABLE_BINDING_METHOD, 598 withModifiableBindingMetadata(method.methodSpec(), method.type(), method.request())); 599 } 600 withModifiableBindingMetadata( MethodSpec method, ModifiableBindingType type, BindingRequest request)601 private MethodSpec withModifiableBindingMetadata( 602 MethodSpec method, ModifiableBindingType type, BindingRequest request) { 603 if (!shouldEmitModifiableMetadataAnnotations()) { 604 return method; 605 } 606 AnnotationSpec.Builder metadata = 607 AnnotationSpec.builder(ModifiableBinding.class) 608 .addMember("modifiableBindingType", "$S", type.name()) 609 .addMember("bindingRequest", toAnnotationValue(request.toProto())); 610 for (Key multibindingContribution : multibindingContributionsMade.get(request)) { 611 metadata.addMember( 612 "multibindingContributions", 613 toAnnotationValue(KeyFactory.toProto(multibindingContribution))); 614 } 615 return method.toBuilder().addAnnotation(metadata.build()).build(); 616 } 617 618 /** Add's a modifiable module method to this implementation. */ addModifiableModuleMethod(ComponentRequirement module, MethodSpec method)619 void addModifiableModuleMethod(ComponentRequirement module, MethodSpec method) { 620 registerModifiableModuleMethod(module, method.name); 621 methodSpecsMap.put( 622 MethodSpecKind.MODIFIABLE_BINDING_METHOD, withModifiableModuleMetadata(module, method)); 623 } 624 625 /** Registers a modifiable module method with {@code name} for {@code module}. */ registerModifiableModuleMethod(ComponentRequirement module, String name)626 void registerModifiableModuleMethod(ComponentRequirement module, String name) { 627 checkArgument(module.kind().isModule()); 628 checkState(modifiableModuleMethods.put(module, name) == null); 629 } 630 withModifiableModuleMetadata(ComponentRequirement module, MethodSpec method)631 private MethodSpec withModifiableModuleMetadata(ComponentRequirement module, MethodSpec method) { 632 if (!shouldEmitModifiableMetadataAnnotations()) { 633 return method; 634 } 635 return method 636 .toBuilder() 637 .addAnnotation( 638 AnnotationSpec.builder(ModifiableModule.class) 639 .addMember("value", toAnnotationValue(module.toProto())) 640 .build()) 641 .build(); 642 } 643 644 /** 645 * Returns {@code true} if the generated component should include metadata annotations with 646 * information to deserialize this {@link ComponentImplementation} in future compilations. 647 */ shouldEmitModifiableMetadataAnnotations()648 boolean shouldEmitModifiableMetadataAnnotations() { 649 return isAbstract && compilerOptions.emitModifiableMetadataAnnotations(); 650 } 651 652 /** Adds the given type to the component. */ addType(TypeSpecKind typeKind, TypeSpec typeSpec)653 void addType(TypeSpecKind typeKind, TypeSpec typeSpec) { 654 typeSpecsMap.put(typeKind, typeSpec); 655 } 656 657 /** Adds the type generated from the given child implementation. */ addChild(ComponentDescriptor child, ComponentImplementation childImplementation)658 void addChild(ComponentDescriptor child, ComponentImplementation childImplementation) { 659 childImplementations.put(child.typeElement(), childImplementation); 660 addType(TypeSpecKind.SUBCOMPONENT, childImplementation.generate().build()); 661 } 662 663 /** Adds a {@link Supplier} for the SwitchingProvider for the component. */ addSwitchingProvider(Supplier<TypeSpec> typeSpecSupplier)664 void addSwitchingProvider(Supplier<TypeSpec> typeSpecSupplier) { 665 switchingProviderSupplier.add(typeSpecSupplier); 666 } 667 668 /** Adds the given code block to the initialize methods of the component. */ addInitialization(CodeBlock codeBlock)669 void addInitialization(CodeBlock codeBlock) { 670 initializations.add(codeBlock); 671 } 672 673 /** 674 * Adds the given component requirement as one that should have a parameter in the component's 675 * initialization methods. 676 */ addComponentRequirementParameter(ComponentRequirement requirement)677 void addComponentRequirementParameter(ComponentRequirement requirement) { 678 componentRequirementParameters.add(requirement); 679 } 680 681 /** 682 * The set of component requirements that have parameters in the component's initialization 683 * methods. 684 */ getComponentRequirementParameters()685 ImmutableSet<ComponentRequirement> getComponentRequirementParameters() { 686 return ImmutableSet.copyOf(componentRequirementParameters); 687 } 688 689 /** Adds the given code block that initializes a {@link ComponentRequirement}. */ addComponentRequirementInitialization(CodeBlock codeBlock)690 void addComponentRequirementInitialization(CodeBlock codeBlock) { 691 componentRequirementInitializations.add(codeBlock); 692 } 693 694 /** 695 * Marks the given key of a producer as one that should have a cancellation statement in the 696 * cancellation listener method of the component. 697 */ addCancellableProducerKey(Key key)698 void addCancellableProducerKey(Key key) { 699 cancellableProducerKeys.add(key); 700 } 701 702 /** Returns a new, unique field name for the component based on the given name. */ getUniqueFieldName(String name)703 String getUniqueFieldName(String name) { 704 return componentFieldNames.getUniqueName(name); 705 } 706 707 /** Returns a new, unique method name for the component based on the given name. */ getUniqueMethodName(String name)708 String getUniqueMethodName(String name) { 709 return componentMethodNames.getUniqueName(name); 710 } 711 712 /** Returns a new, unique method name for a getter method for the given request. */ getUniqueMethodName(BindingRequest request)713 String getUniqueMethodName(BindingRequest request) { 714 return uniqueMethodName(request, KeyVariableNamer.name(request.key())); 715 } 716 uniqueMethodName(BindingRequest request, String bindingName)717 private String uniqueMethodName(BindingRequest request, String bindingName) { 718 String baseMethodName = 719 "get" 720 + LOWER_CAMEL.to(UPPER_CAMEL, bindingName) 721 + (request.isRequestKind(RequestKind.INSTANCE) 722 ? "" 723 : UPPER_UNDERSCORE.to(UPPER_CAMEL, request.kindName())); 724 return getUniqueMethodName(baseMethodName); 725 } 726 727 /** Gets the parameter name to use for the given requirement for this component. */ getParameterName(ComponentRequirement requirement)728 String getParameterName(ComponentRequirement requirement) { 729 return getParameterName(requirement, requirement.variableName()); 730 } 731 732 /** 733 * Gets the parameter name to use for the given requirement for this component, starting with the 734 * given base name if no parameter name has already been selected for the requirement. 735 */ getParameterName(ComponentRequirement requirement, String baseName)736 String getParameterName(ComponentRequirement requirement, String baseName) { 737 return componentRequirementParameterNames.computeIfAbsent( 738 requirement, r -> getUniqueFieldName(baseName)); 739 } 740 741 /** Claims a new method name for the component. Does nothing if method name already exists. */ claimMethodName(CharSequence name)742 void claimMethodName(CharSequence name) { 743 componentMethodNames.claim(name); 744 } 745 746 /** Returns the list of {@link CodeBlock}s that need to go in the initialize method. */ getInitializations()747 ImmutableList<CodeBlock> getInitializations() { 748 return ImmutableList.copyOf(initializations); 749 } 750 751 /** 752 * Returns a list of {@link CodeBlock}s for initializing {@link ComponentRequirement}s. 753 * 754 * <p>These initializations are kept separate from {@link #getInitializations()} because they must 755 * be executed before the initializations of any framework instance initializations in a 756 * superclass implementation that may depend on the instances. We cannot use the same strategy 757 * that we use for framework instances (i.e. wrap in a {@link dagger.internal.DelegateFactory} or 758 * {@link dagger.producers.internal.DelegateProducer} since the types of these initialized fields 759 * have no interface type that we can write a proxy for. 760 */ getComponentRequirementInitializations()761 ImmutableList<CodeBlock> getComponentRequirementInitializations() { 762 return ImmutableList.copyOf(componentRequirementInitializations); 763 } 764 765 /** 766 * Returns whether or not this component has any {@linkplain #getInitializations() initilizations} 767 * or {@linkplain #getComponentRequirementInitializations() component requirement 768 * initializations}. 769 */ hasInitializations()770 boolean hasInitializations() { 771 return !initializations.isEmpty() || !componentRequirementInitializations.isEmpty(); 772 } 773 774 /** 775 * Returns the list of producer {@link Key}s that need cancellation statements in the cancellation 776 * listener method. 777 */ getCancellableProducerKeys()778 ImmutableList<Key> getCancellableProducerKeys() { 779 Optional<ComponentImplementation> currentSuperImplementation = superclassImplementation; 780 Set<Key> cancelledKeysFromSuperclass = new HashSet<>(); 781 while (currentSuperImplementation.isPresent()) { 782 cancelledKeysFromSuperclass.addAll(currentSuperImplementation.get().cancellableProducerKeys); 783 currentSuperImplementation = currentSuperImplementation.get().superclassImplementation; 784 } 785 return Sets.difference(cancellableProducerKeys, cancelledKeysFromSuperclass) 786 .immutableCopy() 787 .asList(); 788 } 789 790 /** 791 * Returns the {@link ModifiableBindingMethod}s for this subcomponent implementation and its 792 * superclasses. 793 */ getModifiableBindingMethods()794 ImmutableMap<BindingRequest, ModifiableBindingMethod> getModifiableBindingMethods() { 795 Map<BindingRequest, ModifiableBindingMethod> modifiableBindingMethodsBuilder = 796 new LinkedHashMap<>(); 797 if (superclassImplementation.isPresent()) { 798 modifiableBindingMethodsBuilder.putAll( 799 Maps.filterValues( 800 superclassImplementation.get().getModifiableBindingMethods(), 801 // filters the modifiable methods of a superclass that are finalized in this component 802 method -> !modifiableBindingMethods.finalized(method))); 803 } 804 // replace superclass modifiable binding methods with any that are defined in this component 805 // implementation 806 modifiableBindingMethodsBuilder.putAll(modifiableBindingMethods.getNonFinalizedMethods()); 807 return ImmutableMap.copyOf(modifiableBindingMethodsBuilder); 808 } 809 810 /** 811 * Returns the names of every modifiable method of this implementation and any superclass 812 * implementations. 813 */ getAllModifiableMethodNames()814 ImmutableSet<String> getAllModifiableMethodNames() { 815 ImmutableSet.Builder<String> names = ImmutableSet.builder(); 816 modifiableBindingMethods.allMethods().forEach(method -> names.add(method.methodSpec().name)); 817 names.addAll(modifiableModuleMethods.values()); 818 superclassImplementation.ifPresent( 819 superclass -> names.addAll(superclass.getAllModifiableMethodNames())); 820 return names.build(); 821 } 822 823 /** 824 * Returns the {@link ModifiableBindingMethod} for this subcomponent for the given binding, if it 825 * exists. 826 */ getModifiableBindingMethod(BindingRequest request)827 Optional<ModifiableBindingMethod> getModifiableBindingMethod(BindingRequest request) { 828 Optional<ModifiableBindingMethod> method = modifiableBindingMethods.getMethod(request); 829 if (!method.isPresent() && superclassImplementation.isPresent()) { 830 return superclassImplementation.get().getModifiableBindingMethod(request); 831 } 832 return method; 833 } 834 835 /** 836 * Returns the {@link ModifiableBindingMethod} of a supertype for this method's {@code request}, 837 * if one exists. 838 */ supertypeModifiableBindingMethod(BindingRequest request)839 Optional<ModifiableBindingMethod> supertypeModifiableBindingMethod(BindingRequest request) { 840 return superclassImplementation() 841 .flatMap(superImplementation -> superImplementation.getModifiableBindingMethod(request)); 842 } 843 844 /** 845 * Returns the names of modifiable module methods for this implementation and all inherited 846 * implementations, keyed by the corresponding module's {@link ComponentRequirement}. 847 */ getAllModifiableModuleMethods()848 ImmutableMap<ComponentRequirement, String> getAllModifiableModuleMethods() { 849 ImmutableMap.Builder<ComponentRequirement, String> methods = ImmutableMap.builder(); 850 methods.putAll(modifiableModuleMethods); 851 superclassImplementation.ifPresent( 852 superclass -> methods.putAll(superclass.getAllModifiableModuleMethods())); 853 return methods.build(); 854 } 855 856 /** 857 * Returns the name of the modifiable module method for {@code module} that is inherited in this 858 * implementation, or empty if none has been defined. 859 */ supertypeModifiableModuleMethodName(ComponentRequirement module)860 Optional<String> supertypeModifiableModuleMethodName(ComponentRequirement module) { 861 checkArgument(module.kind().isModule()); 862 if (!superclassImplementation.isPresent()) { 863 return Optional.empty(); 864 } 865 String methodName = superclassImplementation.get().modifiableModuleMethods.get(module); 866 if (methodName == null) { 867 return superclassImplementation.get().supertypeModifiableModuleMethodName(module); 868 } 869 return Optional.of(methodName); 870 } 871 872 /** Generates the component and returns the resulting {@link TypeSpec.Builder}. */ generate()873 TypeSpec.Builder generate() { 874 fieldSpecsMap.asMap().values().forEach(component::addFields); 875 methodSpecsMap.asMap().values().forEach(component::addMethods); 876 typeSpecsMap.asMap().values().forEach(component::addTypes); 877 switchingProviderSupplier.stream().map(Supplier::get).forEach(component::addType); 878 return component; 879 } 880 881 /** 882 * Registers a {@ProvisionBinding} representing a multibinding as having been implemented in this 883 * component. Multibindings are modifiable across subcomponent implementations and this allows us 884 * to know whether a contribution has been made by a superclass implementation. This is only 885 * relevant for ahead-of-time subcomponents. 886 */ registerImplementedMultibinding( ContributionBinding multibinding, BindingRequest bindingRequest)887 void registerImplementedMultibinding( 888 ContributionBinding multibinding, BindingRequest bindingRequest) { 889 checkArgument(multibinding.isSyntheticMultibinding()); 890 // We register a multibinding as implemented each time we request the multibinding expression, 891 // so only modify the set of contributions once. 892 if (!multibindingContributionsMade.containsKey(bindingRequest)) { 893 registerImplementedMultibindingKeys( 894 bindingRequest, 895 multibinding.dependencies().stream().map(DependencyRequest::key).collect(toList())); 896 } 897 } 898 899 /** 900 * Registers the multibinding contributions represented by {@code keys} as having been implemented 901 * in this component. Multibindings are modifiable across subcomponent implementations and this 902 * allows us to know whether a contribution has been made by a superclass implementation. This is 903 * only relevant for ahead-of-time subcomponents. 904 */ registerImplementedMultibindingKeys(BindingRequest bindingRequest, Iterable<Key> keys)905 void registerImplementedMultibindingKeys(BindingRequest bindingRequest, Iterable<Key> keys) { 906 multibindingContributionsMade.putAll(bindingRequest, keys); 907 } 908 909 /** 910 * Returns the set of multibinding contributions associated with all superclass implementations of 911 * a multibinding. 912 */ superclassContributionsMade(BindingRequest bindingRequest)913 ImmutableSet<Key> superclassContributionsMade(BindingRequest bindingRequest) { 914 return superclassImplementation 915 .map(s -> s.getAllMultibindingContributions(bindingRequest)) 916 .orElse(ImmutableSet.of()); 917 } 918 919 /** 920 * Returns the set of multibinding contributions associated with all implementations of a 921 * multibinding. 922 */ getAllMultibindingContributions(BindingRequest bindingRequest)923 private ImmutableSet<Key> getAllMultibindingContributions(BindingRequest bindingRequest) { 924 return ImmutableSet.copyOf( 925 Sets.union( 926 multibindingContributionsMade.get(bindingRequest), 927 superclassContributionsMade(bindingRequest))); 928 } 929 } 930