1 /* 2 * Copyright (C) 2015 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.common.base.Joiner; 21 import com.google.common.base.Optional; 22 import com.google.common.collect.FluentIterable; 23 import com.google.common.collect.ImmutableList; 24 import com.google.common.collect.ImmutableMap; 25 import com.google.common.collect.ImmutableSet; 26 import com.google.common.collect.Iterables; 27 import com.google.common.collect.Lists; 28 import com.google.common.collect.Maps; 29 import com.google.common.collect.Sets; 30 import com.google.common.util.concurrent.ListenableFuture; 31 import dagger.MembersInjector; 32 import dagger.internal.DelegateFactory; 33 import dagger.internal.Factory; 34 import dagger.internal.InstanceFactory; 35 import dagger.internal.MapFactory; 36 import dagger.internal.MapProviderFactory; 37 import dagger.internal.MembersInjectors; 38 import dagger.internal.ScopedProvider; 39 import dagger.internal.SetFactory; 40 import dagger.internal.codegen.ComponentDescriptor.BuilderSpec; 41 import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor; 42 import dagger.internal.codegen.ComponentGenerator.MemberSelect; 43 import dagger.internal.codegen.writer.ClassName; 44 import dagger.internal.codegen.writer.ClassWriter; 45 import dagger.internal.codegen.writer.ConstructorWriter; 46 import dagger.internal.codegen.writer.FieldWriter; 47 import dagger.internal.codegen.writer.JavaWriter; 48 import dagger.internal.codegen.writer.MethodWriter; 49 import dagger.internal.codegen.writer.ParameterizedTypeName; 50 import dagger.internal.codegen.writer.Snippet; 51 import dagger.internal.codegen.writer.StringLiteral; 52 import dagger.internal.codegen.writer.TypeName; 53 import dagger.internal.codegen.writer.TypeNames; 54 import dagger.internal.codegen.writer.VoidName; 55 import dagger.producers.Producer; 56 import dagger.producers.internal.Producers; 57 import dagger.producers.internal.SetOfProducedProducer; 58 import dagger.producers.internal.SetProducer; 59 import java.util.Collection; 60 import java.util.HashMap; 61 import java.util.HashSet; 62 import java.util.LinkedHashSet; 63 import java.util.List; 64 import java.util.Map; 65 import java.util.Set; 66 import javax.inject.Provider; 67 import javax.lang.model.element.Element; 68 import javax.lang.model.element.ElementKind; 69 import javax.lang.model.element.ExecutableElement; 70 import javax.lang.model.element.Name; 71 import javax.lang.model.element.TypeElement; 72 import javax.lang.model.element.VariableElement; 73 import javax.lang.model.type.DeclaredType; 74 import javax.lang.model.type.ExecutableType; 75 import javax.lang.model.type.TypeKind; 76 import javax.lang.model.type.TypeMirror; 77 import javax.lang.model.util.Elements; 78 import javax.lang.model.util.Types; 79 import javax.tools.Diagnostic; 80 import javax.tools.Diagnostic.Kind; 81 82 import static com.google.auto.common.MoreTypes.asDeclared; 83 import static com.google.common.base.CaseFormat.LOWER_CAMEL; 84 import static com.google.common.base.CaseFormat.UPPER_CAMEL; 85 import static com.google.common.base.Preconditions.checkState; 86 import static com.google.common.collect.Iterables.any; 87 import static com.google.common.collect.Iterables.getOnlyElement; 88 import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.DELEGATED; 89 import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.INITIALIZED; 90 import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.UNINITIALIZED; 91 import static dagger.internal.codegen.Binding.bindingPackageFor; 92 import static dagger.internal.codegen.ComponentGenerator.MemberSelect.staticMethodInvocationWithCast; 93 import static dagger.internal.codegen.ComponentGenerator.MemberSelect.staticSelect; 94 import static dagger.internal.codegen.ContributionBinding.contributionTypeFor; 95 import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.ENUM_INSTANCE; 96 import static dagger.internal.codegen.ContributionBinding.Kind.PROVISION; 97 import static dagger.internal.codegen.ErrorMessages.CANNOT_RETURN_NULL_FROM_NON_NULLABLE_COMPONENT_METHOD; 98 import static dagger.internal.codegen.MapKeys.getMapKeySnippet; 99 import static dagger.internal.codegen.MembersInjectionBinding.Strategy.NO_OP; 100 import static dagger.internal.codegen.SourceFiles.frameworkTypeUsageStatement; 101 import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding; 102 import static dagger.internal.codegen.SourceFiles.indexDependenciesByUnresolvedKey; 103 import static dagger.internal.codegen.SourceFiles.membersInjectorNameForType; 104 import static dagger.internal.codegen.Util.componentCanMakeNewInstances; 105 import static dagger.internal.codegen.Util.getKeyTypeOfMap; 106 import static dagger.internal.codegen.Util.getProvidedValueTypeOfMap; 107 import static dagger.internal.codegen.Util.isMapWithNonProvidedValues; 108 import static dagger.internal.codegen.writer.Snippet.makeParametersSnippet; 109 import static dagger.internal.codegen.writer.Snippet.memberSelectSnippet; 110 import static dagger.internal.codegen.writer.Snippet.nullCheck; 111 import static javax.lang.model.element.Modifier.ABSTRACT; 112 import static javax.lang.model.element.Modifier.FINAL; 113 import static javax.lang.model.element.Modifier.PRIVATE; 114 import static javax.lang.model.element.Modifier.PUBLIC; 115 import static javax.lang.model.element.Modifier.STATIC; 116 import static javax.lang.model.type.TypeKind.DECLARED; 117 import static javax.lang.model.type.TypeKind.VOID; 118 119 /** 120 * Creates the implementation class for a component or subcomponent. 121 */ 122 abstract class AbstractComponentWriter { 123 // TODO(dpb): Make all these fields private after refactoring is complete. 124 protected final Elements elements; 125 protected final Types types; 126 protected final Key.Factory keyFactory; 127 protected final Kind nullableValidationType; 128 protected final Set<JavaWriter> javaWriters = new LinkedHashSet<>(); 129 protected final ClassName name; 130 protected final BindingGraph graph; 131 private final Map<BindingKey, InitializationState> initializationStates = new HashMap<>(); 132 private final Map<Binding, InitializationState> contributionInitializationStates = 133 new HashMap<>(); 134 protected ClassWriter componentWriter; 135 private final Map<BindingKey, MemberSelect> memberSelectSnippets = new HashMap<>(); 136 private final Map<ContributionBinding, MemberSelect> multibindingContributionSnippets = 137 new HashMap<>(); 138 protected ConstructorWriter constructorWriter; 139 protected Optional<ClassName> builderName = Optional.absent(); 140 141 /** 142 * For each component requirement, the builder field. This map is empty for subcomponents that do 143 * not use a builder. 144 */ 145 private ImmutableMap<TypeElement, FieldWriter> builderFields = ImmutableMap.of(); 146 147 /** 148 * For each component requirement, the snippet for the component field that holds it. 149 * 150 * <p>Fields are written for all requirements for subcomponents that do not use a builder, and for 151 * any requirement that is reused from a subcomponent of this component. 152 */ 153 protected final Map<TypeElement, MemberSelect> componentContributionFields = Maps.newHashMap(); 154 155 AbstractComponentWriter( 156 Types types, 157 Elements elements, 158 Key.Factory keyFactory, 159 Diagnostic.Kind nullableValidationType, 160 ClassName name, 161 BindingGraph graph) { 162 this.types = types; 163 this.elements = elements; 164 this.keyFactory = keyFactory; 165 this.nullableValidationType = nullableValidationType; 166 this.name = name; 167 this.graph = graph; 168 } 169 170 protected final TypeElement componentDefinitionType() { 171 return graph.componentDescriptor().componentDefinitionType(); 172 } 173 174 protected final ClassName componentDefinitionTypeName() { 175 return ClassName.fromTypeElement(componentDefinitionType()); 176 } 177 178 /** 179 * Returns an expression snippet that evaluates to an instance of the contribution, looking for 180 * either a builder field or a component field. 181 */ 182 private Snippet getComponentContributionSnippet(TypeElement contributionType) { 183 if (builderFields.containsKey(contributionType)) { 184 return Snippet.format("builder.%s", builderFields.get(contributionType).name()); 185 } else { 186 Optional<Snippet> snippet = getOrCreateComponentContributionFieldSnippet(contributionType); 187 checkState(snippet.isPresent(), "no builder or component field for %s", contributionType); 188 return snippet.get(); 189 } 190 } 191 192 /** 193 * Returns a snippet for a component contribution field. Adds a field the first time one is 194 * requested for a contribution type if this component's builder has a field for it. 195 */ 196 protected Optional<Snippet> getOrCreateComponentContributionFieldSnippet( 197 TypeElement contributionType) { 198 MemberSelect fieldSelect = componentContributionFields.get(contributionType); 199 if (fieldSelect == null) { 200 if (!builderFields.containsKey(contributionType)) { 201 return Optional.absent(); 202 } 203 FieldWriter componentField = 204 componentWriter.addField(contributionType, simpleVariableName(contributionType)); 205 componentField.addModifiers(PRIVATE, FINAL); 206 constructorWriter 207 .body() 208 .addSnippet( 209 "this.%s = builder.%s;", 210 componentField.name(), 211 builderFields.get(contributionType).name()); 212 fieldSelect = MemberSelect.instanceSelect(name, Snippet.format("%s", componentField.name())); 213 componentContributionFields.put(contributionType, fieldSelect); 214 } 215 return Optional.of(fieldSelect.getSnippetFor(name)); 216 } 217 218 private Snippet getMemberSelectSnippet(BindingKey key) { 219 return getMemberSelect(key).getSnippetFor(name); 220 } 221 222 protected MemberSelect getMemberSelect(BindingKey key) { 223 return memberSelectSnippets.get(key); 224 } 225 226 protected Optional<MemberSelect> getMultibindingContributionSnippet(ContributionBinding binding) { 227 return Optional.fromNullable(multibindingContributionSnippets.get(binding)); 228 } 229 230 /** 231 * Returns the initialization state of the factory field for a binding key in this component. 232 */ 233 protected InitializationState getInitializationState(BindingKey bindingKey) { 234 return initializationStates.containsKey(bindingKey) 235 ? initializationStates.get(bindingKey) 236 : UNINITIALIZED; 237 } 238 239 private void setInitializationState(BindingKey bindingKey, InitializationState state) { 240 initializationStates.put(bindingKey, state); 241 } 242 243 private InitializationState getContributionInitializationState(Binding binding) { 244 return contributionInitializationStates.containsKey(binding) 245 ? contributionInitializationStates.get(binding) 246 : UNINITIALIZED; 247 } 248 249 private void setContributionInitializationState(Binding binding, InitializationState state) { 250 contributionInitializationStates.put(binding, state); 251 } 252 253 ImmutableSet<JavaWriter> write() { 254 if (javaWriters.isEmpty()) { 255 writeComponent(); 256 } 257 return ImmutableSet.copyOf(javaWriters); 258 } 259 260 private void writeComponent() { 261 componentWriter = createComponentClass(); 262 addConstructor(); 263 addBuilder(); 264 addFactoryMethods(); 265 addFields(); 266 initializeFrameworkTypes(); 267 implementInterfaceMethods(); 268 addSubcomponents(); 269 } 270 271 /** 272 * Creates the component implementation class. 273 */ 274 protected abstract ClassWriter createComponentClass(); 275 276 private void addConstructor() { 277 constructorWriter = componentWriter.addConstructor(); 278 constructorWriter.addModifiers(PRIVATE); 279 } 280 281 /** 282 * Adds a builder type. 283 */ 284 protected void addBuilder() { 285 ClassWriter builderWriter = createBuilder(); 286 builderWriter.addModifiers(FINAL); 287 builderWriter.addConstructor().addModifiers(PRIVATE); 288 builderName = Optional.of(builderWriter.name()); 289 290 Optional<BuilderSpec> builderSpec = graph.componentDescriptor().builderSpec(); 291 if (builderSpec.isPresent()) { 292 builderWriter.addModifiers(PRIVATE); 293 builderWriter.setSupertype(builderSpec.get().builderDefinitionType()); 294 } else { 295 builderWriter.addModifiers(PUBLIC); 296 } 297 298 builderFields = addBuilderFields(builderWriter); 299 addBuildMethod(builderWriter, builderSpec); 300 addBuilderMethods(builderWriter, builderSpec); 301 302 constructorWriter.addParameter(builderWriter, "builder"); 303 constructorWriter.body().addSnippet("assert builder != null;"); 304 } 305 306 /** 307 * Adds fields for each of the {@linkplain BindingGraph#componentRequirements component 308 * requirements}. Regardless of builder spec, there is always one field per requirement. 309 */ 310 private ImmutableMap<TypeElement, FieldWriter> addBuilderFields(ClassWriter builderWriter) { 311 ImmutableMap.Builder<TypeElement, FieldWriter> builderFieldsBuilder = ImmutableMap.builder(); 312 for (TypeElement contributionElement : graph.componentRequirements()) { 313 String contributionName = simpleVariableName(contributionElement); 314 FieldWriter builderField = builderWriter.addField(contributionElement, contributionName); 315 builderField.addModifiers(PRIVATE); 316 builderFieldsBuilder.put(contributionElement, builderField); 317 } 318 return builderFieldsBuilder.build(); 319 } 320 321 /** Adds the build method to the builder. */ 322 private void addBuildMethod(ClassWriter builderWriter, Optional<BuilderSpec> builderSpec) { 323 MethodWriter buildMethod; 324 if (builderSpec.isPresent()) { 325 ExecutableElement specBuildMethod = builderSpec.get().buildMethod(); 326 // Note: we don't use the specBuildMethod.getReturnType() as the return type 327 // because it might be a type variable. We make use of covariant returns to allow 328 // us to return the component type, which will always be valid. 329 buildMethod = 330 builderWriter.addMethod( 331 componentDefinitionTypeName(), specBuildMethod.getSimpleName().toString()); 332 buildMethod.annotate(Override.class); 333 } else { 334 buildMethod = builderWriter.addMethod(componentDefinitionTypeName(), "build"); 335 } 336 buildMethod.addModifiers(PUBLIC); 337 338 for (Map.Entry<TypeElement, FieldWriter> builderFieldEntry : builderFields.entrySet()) { 339 FieldWriter builderField = builderFieldEntry.getValue(); 340 if (componentCanMakeNewInstances(builderFieldEntry.getKey())) { 341 buildMethod.body() 342 .addSnippet("if (%1$s == null) { this.%1$s = new %2$s(); }", 343 builderField.name(), 344 builderField.type()); 345 } else { 346 buildMethod.body() 347 .addSnippet( 348 "if (%s == null) { throw new %s(%s.class.getCanonicalName() + \" must be set\"); }", 349 builderField.name(), 350 ClassName.fromClass(IllegalStateException.class), 351 builderField.type()); 352 } 353 } 354 355 buildMethod.body().addSnippet("return new %s(this);", name); 356 } 357 358 /** 359 * Adds the methods that set each of parameters on the builder. If the {@link BuilderSpec} is 360 * present, it will tailor the methods to match the spec. 361 */ 362 private void addBuilderMethods( 363 ClassWriter builderWriter, 364 Optional<BuilderSpec> builderSpec) { 365 if (builderSpec.isPresent()) { 366 for (Map.Entry<TypeElement, ExecutableElement> builderMethodEntry : 367 builderSpec.get().methodMap().entrySet()) { 368 TypeElement builderMethodType = builderMethodEntry.getKey(); 369 ExecutableElement specMethod = builderMethodEntry.getValue(); 370 MethodWriter builderMethod = addBuilderMethodFromSpec(builderWriter, specMethod); 371 String parameterName = 372 Iterables.getOnlyElement(specMethod.getParameters()).getSimpleName().toString(); 373 builderMethod.addParameter(builderMethodType, parameterName); 374 builderMethod.body().addSnippet(nullCheck(parameterName)); 375 if (graph.componentRequirements().contains(builderMethodType)) { 376 // required type 377 builderMethod.body().addSnippet("this.%s = %s;", 378 builderFields.get(builderMethodType).name(), 379 parameterName); 380 addBuilderMethodReturnStatementForSpec(specMethod, builderMethod); 381 } else if (graph.ownedModuleTypes().contains(builderMethodType)) { 382 // owned, but not required 383 builderMethod.body() 384 .addSnippet("// This module is declared, but not used in the component. " 385 + "This method is a no-op"); 386 addBuilderMethodReturnStatementForSpec(specMethod, builderMethod); 387 } else { 388 // neither owned nor required, so it must be an inherited module 389 builderMethod 390 .body() 391 .addSnippet( 392 "throw new %s(%s.format(%s, %s.class.getCanonicalName()));", 393 ClassName.fromClass(UnsupportedOperationException.class), 394 ClassName.fromClass(String.class), 395 StringLiteral.forValue( 396 "%s cannot be set because it is inherited from the enclosing component"), 397 ClassName.fromTypeElement(builderMethodType)); 398 } 399 } 400 } else { 401 for (TypeElement componentRequirement : graph.availableDependencies()) { 402 String componentRequirementName = simpleVariableName(componentRequirement); 403 MethodWriter builderMethod = builderWriter.addMethod( 404 builderWriter.name(), 405 componentRequirementName); 406 builderMethod.addModifiers(PUBLIC); 407 builderMethod.addParameter(componentRequirement, componentRequirementName); 408 builderMethod.body().addSnippet(nullCheck(componentRequirementName)); 409 if (graph.componentRequirements().contains(componentRequirement)) { 410 builderMethod.body() 411 .addSnippet("this.%s = %s;", 412 builderFields.get(componentRequirement).name(), 413 componentRequirementName); 414 } else { 415 builderMethod.annotate(Deprecated.class); 416 } 417 builderMethod.body().addSnippet("return this;"); 418 } 419 } 420 } 421 422 private void addBuilderMethodReturnStatementForSpec( 423 ExecutableElement specMethod, MethodWriter builderMethod) { 424 if (!specMethod.getReturnType().getKind().equals(VOID)) { 425 builderMethod.body().addSnippet("return this;"); 426 } 427 } 428 429 private MethodWriter addBuilderMethodFromSpec( 430 ClassWriter builderWriter, ExecutableElement method) { 431 String methodName = method.getSimpleName().toString(); 432 TypeMirror returnType = method.getReturnType(); 433 // If the return type is void, we add a method with the void return type. 434 // Otherwise we use the builderWriter and take advantage of covariant returns 435 // (so that we don't have to worry about setter methods that return type variables). 436 MethodWriter builderMethod = 437 returnType.getKind().equals(TypeKind.VOID) 438 ? builderWriter.addMethod(returnType, methodName) 439 : builderWriter.addMethod(builderWriter, methodName); 440 builderMethod.annotate(Override.class); 441 builderMethod.addModifiers(Sets.difference(method.getModifiers(), ImmutableSet.of(ABSTRACT))); 442 return builderMethod; 443 } 444 445 /** 446 * Creates the builder class. 447 */ 448 protected abstract ClassWriter createBuilder(); 449 450 /** 451 * Adds component factory methods. 452 */ 453 protected abstract void addFactoryMethods(); 454 455 private void addFields() { 456 for (ResolvedBindings resolvedBindings : graph.resolvedBindings().values()) { 457 addField(resolvedBindings); 458 } 459 } 460 461 private void addField(ResolvedBindings resolvedBindings) { 462 BindingKey bindingKey = resolvedBindings.bindingKey(); 463 464 // No field needed if there are no owned bindings. 465 if (resolvedBindings.ownedBindings().isEmpty()) { 466 return; 467 } 468 469 // No field needed for bindings with no dependencies or state. 470 Optional<MemberSelect> staticMemberSelect = staticMemberSelect(resolvedBindings); 471 if (staticMemberSelect.isPresent()) { 472 memberSelectSnippets.put(bindingKey, staticMemberSelect.get()); 473 return; 474 } 475 476 Optional<String> bindingPackage = bindingPackageFor(resolvedBindings.bindings()); 477 boolean useRawType = bindingPackage.isPresent() 478 && !bindingPackage.get().equals(name.packageName()); 479 if (bindingKey.kind().equals(BindingKey.Kind.CONTRIBUTION)) { 480 ImmutableSet<ContributionBinding> contributionBindings = 481 resolvedBindings.contributionBindings(); 482 if (ContributionBinding.contributionTypeFor(contributionBindings).isMultibinding()) { 483 // note that here we rely on the order of the resolved bindings being from parent to child 484 // otherwise, the numbering wouldn't work 485 int contributionNumber = 0; 486 for (ContributionBinding contributionBinding : contributionBindings) { 487 if (!contributionBinding.isSyntheticBinding()) { 488 contributionNumber++; 489 if (resolvedBindings.ownedContributionBindings().contains(contributionBinding)) { 490 FrameworkField contributionBindingField = 491 FrameworkField.createForSyntheticContributionBinding( 492 contributionNumber, contributionBinding); 493 FieldWriter contributionField = 494 addFrameworkField(useRawType, contributionBindingField); 495 496 ImmutableList<String> contributionSelectTokens = 497 new ImmutableList.Builder<String>() 498 .add(contributionField.name()) 499 .build(); 500 multibindingContributionSnippets.put( 501 contributionBinding, 502 MemberSelect.instanceSelect(name, memberSelectSnippet(contributionSelectTokens))); 503 } 504 } 505 } 506 } 507 } 508 509 FrameworkField bindingField = FrameworkField.createForResolvedBindings(resolvedBindings); 510 FieldWriter frameworkField = addFrameworkField(useRawType, bindingField); 511 512 ImmutableList<String> memberSelectTokens = 513 new ImmutableList.Builder<String>() 514 .add(frameworkField.name()) 515 .build(); 516 memberSelectSnippets.put( 517 bindingKey, 518 MemberSelect.instanceSelect(name, Snippet.memberSelectSnippet(memberSelectTokens))); 519 } 520 521 private FieldWriter addFrameworkField(boolean useRawType, 522 FrameworkField contributionBindingField) { 523 FieldWriter contributionField = 524 componentWriter.addField( 525 useRawType 526 ? contributionBindingField.frameworkType().type() 527 : contributionBindingField.frameworkType(), 528 contributionBindingField.name()); 529 contributionField.addModifiers(PRIVATE); 530 if (useRawType) { 531 contributionField.annotate(SuppressWarnings.class).setValue("rawtypes"); 532 } 533 return contributionField; 534 } 535 536 /** 537 * If {@code resolvedBindings} is an unscoped provision binding with no factory arguments or a 538 * no-op members injection binding, then we don't need a field to hold its factory. In that case, 539 * this method returns the static member select snippet that returns the factory or no-op members 540 * injector. 541 */ 542 private Optional<MemberSelect> staticMemberSelect(ResolvedBindings resolvedBindings) { 543 switch (resolvedBindings.bindingKey().kind()) { 544 case CONTRIBUTION: 545 if (resolvedBindings.contributionBindings().size() != 1) { 546 return Optional.absent(); 547 } 548 ContributionBinding contributionBinding = 549 getOnlyElement(resolvedBindings.contributionBindings()); 550 if (contributionBinding.contributionType().isMultibinding() 551 || !(contributionBinding.bindingType().equals(Binding.Type.PROVISION))) { 552 return Optional.absent(); 553 } 554 if (contributionBinding.factoryCreationStrategy().equals(ENUM_INSTANCE) 555 && !contributionBinding.scope().isPresent()) { 556 return Optional.of( 557 staticSelect( 558 generatedClassNameForBinding(contributionBinding), Snippet.format("create()"))); 559 } 560 break; 561 562 case MEMBERS_INJECTION: 563 Optional<MembersInjectionBinding> membersInjectionBinding = 564 resolvedBindings.membersInjectionBinding(); 565 if (membersInjectionBinding.isPresent() 566 && membersInjectionBinding.get().injectionStrategy().equals(NO_OP)) { 567 return Optional.of( 568 staticMethodInvocationWithCast( 569 ClassName.fromClass(MembersInjectors.class), 570 Snippet.format("noOp()"), 571 ClassName.fromClass(MembersInjector.class))); 572 } 573 break; 574 575 default: 576 throw new AssertionError(); 577 } 578 return Optional.absent(); 579 } 580 581 private void implementInterfaceMethods() { 582 Set<MethodSignature> interfaceMethods = Sets.newHashSet(); 583 for (ComponentMethodDescriptor componentMethod : 584 graph.componentDescriptor().componentMethods()) { 585 if (componentMethod.dependencyRequest().isPresent()) { 586 DependencyRequest interfaceRequest = componentMethod.dependencyRequest().get(); 587 ExecutableElement requestElement = 588 MoreElements.asExecutable(interfaceRequest.requestElement()); 589 ExecutableType requestType = MoreTypes.asExecutable(types.asMemberOf( 590 MoreTypes.asDeclared(componentDefinitionType().asType()), requestElement)); 591 MethodSignature signature = MethodSignature.fromExecutableType( 592 requestElement.getSimpleName().toString(), requestType); 593 if (!interfaceMethods.contains(signature)) { 594 interfaceMethods.add(signature); 595 MethodWriter interfaceMethod = 596 requestType.getReturnType().getKind().equals(VOID) 597 ? componentWriter.addMethod( 598 VoidName.VOID, requestElement.getSimpleName().toString()) 599 : componentWriter.addMethod( 600 requestType.getReturnType(), requestElement.getSimpleName().toString()); 601 interfaceMethod.annotate(Override.class); 602 interfaceMethod.addModifiers(PUBLIC); 603 BindingKey bindingKey = interfaceRequest.bindingKey(); 604 MemberSelect memberSelect = getMemberSelect(bindingKey); 605 Snippet memberSelectSnippet = memberSelect.getSnippetFor(name); 606 switch (interfaceRequest.kind()) { 607 case MEMBERS_INJECTOR: 608 List<? extends VariableElement> parameters = requestElement.getParameters(); 609 if (parameters.isEmpty()) { 610 // we're returning the framework type 611 interfaceMethod.body().addSnippet("return %s;", memberSelectSnippet); 612 } else { 613 VariableElement parameter = Iterables.getOnlyElement(parameters); 614 Name parameterName = parameter.getSimpleName(); 615 interfaceMethod.addParameter( 616 TypeNames.forTypeMirror( 617 Iterables.getOnlyElement(requestType.getParameterTypes())), 618 parameterName.toString()); 619 interfaceMethod 620 .body() 621 .addSnippet( 622 "%s.injectMembers(%s);", 623 memberSelectSnippet, 624 parameterName); 625 if (!requestType.getReturnType().getKind().equals(VOID)) { 626 interfaceMethod.body().addSnippet("return %s;", parameterName); 627 } 628 } 629 break; 630 case INSTANCE: 631 if (memberSelect.staticMember() 632 && bindingKey.key().type().getKind().equals(DECLARED) 633 && !((DeclaredType) bindingKey.key().type()).getTypeArguments().isEmpty()) { 634 // If using a parameterized enum type, then we need to store the factory 635 // in a temporary variable, in order to help javac be able to infer 636 // the generics of the Factory.create methods. 637 TypeName factoryType = 638 ParameterizedTypeName.create( 639 Provider.class, TypeNames.forTypeMirror(requestType.getReturnType())); 640 interfaceMethod 641 .body() 642 .addSnippet( 643 "%s factory = %s;", factoryType, memberSelectSnippet); 644 interfaceMethod.body().addSnippet("return factory.get();"); 645 break; 646 } 647 // fall through in the else case. 648 case LAZY: 649 case PRODUCED: 650 case PRODUCER: 651 case PROVIDER: 652 case FUTURE: 653 interfaceMethod 654 .body() 655 .addSnippet( 656 "return %s;", 657 frameworkTypeUsageStatement( 658 memberSelectSnippet, interfaceRequest.kind())); 659 break; 660 default: 661 throw new AssertionError(); 662 } 663 } 664 } 665 } 666 } 667 668 private void addSubcomponents() { 669 for (Map.Entry<ExecutableElement, BindingGraph> subgraphEntry : graph.subgraphs().entrySet()) { 670 SubcomponentWriter subcomponent = 671 new SubcomponentWriter(this, subgraphEntry.getKey(), subgraphEntry.getValue()); 672 javaWriters.addAll(subcomponent.write()); 673 } 674 } 675 676 private static final int SNIPPETS_PER_INITIALIZATION_METHOD = 100; 677 678 private void initializeFrameworkTypes() { 679 ImmutableList.Builder<Snippet> snippetsBuilder = ImmutableList.builder(); 680 for (BindingKey bindingKey : graph.resolvedBindings().keySet()) { 681 snippetsBuilder.add(initializeFrameworkType(bindingKey)); 682 } 683 ImmutableList<Snippet> snippets = snippetsBuilder.build(); 684 685 List<List<Snippet>> partitions = Lists.partition(snippets, SNIPPETS_PER_INITIALIZATION_METHOD); 686 for (int i = 0; i < partitions.size(); i++) { 687 MethodWriter initializeMethod = 688 componentWriter.addMethod(VoidName.VOID, "initialize" + ((i == 0) ? "" : i)); 689 /* TODO(gak): Strictly speaking, we only need the suppression here if we are also initializing 690 * a raw field in this method, but the structure of this code makes it awkward to pass that 691 * bit through. This will be cleaned up when we no longer separate fields and initilization 692 * as we do now. */ 693 initializeMethod.annotate(SuppressWarnings.class).setValue("unchecked"); 694 for (Snippet snippet : partitions.get(i)) { 695 initializeMethod.body().addSnippet(snippet); 696 } 697 initializeMethod.addModifiers(PRIVATE); 698 if (builderName.isPresent()) { 699 initializeMethod.addParameter(builderName.get(), "builder").addModifiers(FINAL); 700 constructorWriter.body().addSnippet("%s(builder);", initializeMethod.name()); 701 } else { 702 constructorWriter.body().addSnippet("%s();", initializeMethod.name()); 703 } 704 } 705 } 706 707 /** 708 * Returns a single snippet representing the initialization of the framework type. 709 * 710 * <p>Note that this must be a single snippet because initialization snippets can be invoked from 711 * any place in any order. By requiring a single snippet (often of concatenated snippets) we 712 * ensure that things like local variables always behave as expected by the initialization logic. 713 */ 714 private Snippet initializeFrameworkType(BindingKey bindingKey) { 715 ResolvedBindings resolvedBindings = graph.resolvedBindings().get(bindingKey); 716 717 // There's no field for inherited bindings. 718 if (resolvedBindings.ownedBindings().isEmpty()) { 719 return Snippet.format(""); 720 } 721 722 switch (bindingKey.kind()) { 723 case CONTRIBUTION: 724 switch (contributionTypeFor(resolvedBindings.contributionBindings())) { 725 case SET: 726 return initializeSetMultibindings(resolvedBindings); 727 case MAP: 728 return initializeMapMultibindings(resolvedBindings); 729 case UNIQUE: 730 return initializeUniqueContributionBinding(resolvedBindings); 731 default: 732 throw new AssertionError(); 733 } 734 735 case MEMBERS_INJECTION: 736 return initializeMembersInjectionBinding(resolvedBindings); 737 738 default: 739 throw new AssertionError(); 740 } 741 } 742 743 private Snippet initializeSetMultibindings(ResolvedBindings resolvedBindings) { 744 ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder(); 745 746 ImmutableList.Builder<Snippet> parameterSnippets = ImmutableList.builder(); 747 for (ContributionBinding binding : resolvedBindings.contributionBindings()) { 748 Optional<MemberSelect> multibindingContributionSnippet = 749 getMultibindingContributionSnippet(binding); 750 checkState(multibindingContributionSnippet.isPresent(), "%s was not found", binding); 751 Snippet snippet = multibindingContributionSnippet.get().getSnippetFor(name); 752 if (multibindingContributionSnippet.get().owningClass().equals(name) 753 // the binding might already be initialized by a different set binding that shares the 754 // same contributions (e.g., Set<T> and Set<Produced<T>>) 755 && getContributionInitializationState(binding) 756 .equals(InitializationState.UNINITIALIZED)) { 757 Snippet initializeSnippet = initializeFactoryForContributionBinding(binding); 758 initializationSnippets.add(Snippet.format("this.%s = %s;", snippet, initializeSnippet)); 759 setContributionInitializationState(binding, InitializationState.INITIALIZED); 760 } 761 parameterSnippets.add(snippet); 762 } 763 Class<?> factoryClass = 764 Iterables.all(resolvedBindings.contributionBindings(), Binding.Type.PROVISION) 765 ? SetFactory.class 766 : Util.isSetOfProduced(resolvedBindings.bindingKey().key().type()) 767 ? SetOfProducedProducer.class 768 : SetProducer.class; 769 Snippet initializeSetSnippet = 770 Snippet.format( 771 "%s.create(%s)", 772 ClassName.fromClass(factoryClass), 773 makeParametersSnippet(parameterSnippets.build())); 774 initializationSnippets.add( 775 initializeMember(resolvedBindings.bindingKey(), initializeSetSnippet)); 776 777 return Snippet.concat(initializationSnippets.build()); 778 } 779 780 private Snippet initializeMapMultibindings(ResolvedBindings resolvedBindings) { 781 ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder(); 782 783 if (any(resolvedBindings.contributionBindings(), Binding.Type.PRODUCTION)) { 784 // TODO(beder): Implement producer map bindings. 785 throw new IllegalStateException("producer map bindings not implemented yet"); 786 } 787 for (ContributionBinding binding : resolvedBindings.contributionBindings()) { 788 Optional<MemberSelect> multibindingContributionSnippet = 789 getMultibindingContributionSnippet(binding); 790 if (!isMapWithNonProvidedValues(binding.key().type()) 791 && multibindingContributionSnippet.isPresent() 792 && multibindingContributionSnippet.get().owningClass().equals(name)) { 793 initializationSnippets.add( 794 Snippet.format( 795 "this.%s = %s;", 796 multibindingContributionSnippet.get().getSnippetFor(name), 797 initializeFactoryForContributionBinding(binding))); 798 } 799 } 800 initializationSnippets.add( 801 initializeMember( 802 resolvedBindings.bindingKey(), 803 initializeMapBinding(resolvedBindings.contributionBindings()))); 804 805 return Snippet.concat(initializationSnippets.build()); 806 } 807 808 private Snippet initializeUniqueContributionBinding(ResolvedBindings resolvedBindings) { 809 ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder(); 810 811 ContributionBinding binding = getOnlyElement(resolvedBindings.ownedContributionBindings()); 812 if (!binding.factoryCreationStrategy().equals(ENUM_INSTANCE) || binding.scope().isPresent()) { 813 initializationSnippets.add(initializeDelegateFactories(binding)); 814 initializationSnippets.add( 815 initializeMember( 816 resolvedBindings.bindingKey(), initializeFactoryForContributionBinding(binding))); 817 } 818 819 return Snippet.concat(initializationSnippets.build()); 820 } 821 822 private Snippet initializeMembersInjectionBinding(ResolvedBindings resolvedBindings) { 823 ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder(); 824 825 MembersInjectionBinding binding = resolvedBindings.membersInjectionBinding().get(); 826 if (!binding.injectionStrategy().equals(MembersInjectionBinding.Strategy.NO_OP)) { 827 initializationSnippets.add(initializeDelegateFactories(binding)); 828 initializationSnippets.add( 829 initializeMember( 830 resolvedBindings.bindingKey(), initializeMembersInjectorForBinding(binding))); 831 } 832 833 return Snippet.concat(initializationSnippets.build()); 834 } 835 836 private Snippet initializeDelegateFactories(Binding binding) { 837 ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder(); 838 839 for (Collection<DependencyRequest> requestsForKey : 840 indexDependenciesByUnresolvedKey(types, binding.dependencies()).asMap().values()) { 841 BindingKey dependencyKey = 842 Iterables.getOnlyElement( 843 FluentIterable.from(requestsForKey) 844 .transform(DependencyRequest.BINDING_KEY_FUNCTION) 845 .toSet()); 846 if (!getMemberSelect(dependencyKey).staticMember() 847 && getInitializationState(dependencyKey).equals(UNINITIALIZED)) { 848 initializationSnippets.add( 849 Snippet.format( 850 "this.%s = new %s();", 851 getMemberSelectSnippet(dependencyKey), 852 ClassName.fromClass(DelegateFactory.class))); 853 setInitializationState(dependencyKey, DELEGATED); 854 } 855 } 856 857 return Snippet.concat(initializationSnippets.build()); 858 } 859 860 private Snippet initializeMember(BindingKey bindingKey, Snippet initializationSnippet) { 861 ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder(); 862 863 Snippet memberSelect = getMemberSelectSnippet(bindingKey); 864 Snippet delegateFactoryVariable = delegateFactoryVariableSnippet(bindingKey); 865 if (getInitializationState(bindingKey).equals(DELEGATED)) { 866 initializationSnippets.add( 867 Snippet.format( 868 "%1$s %2$s = (%1$s) %3$s;", 869 ClassName.fromClass(DelegateFactory.class), 870 delegateFactoryVariable, 871 memberSelect)); 872 } 873 initializationSnippets.add( 874 Snippet.format("this.%s = %s;", memberSelect, initializationSnippet)); 875 if (getInitializationState(bindingKey).equals(DELEGATED)) { 876 initializationSnippets.add( 877 Snippet.format("%s.setDelegatedProvider(%s);", delegateFactoryVariable, memberSelect)); 878 } 879 setInitializationState(bindingKey, INITIALIZED); 880 881 return Snippet.concat(initializationSnippets.build()); 882 } 883 884 private Snippet delegateFactoryVariableSnippet(BindingKey key) { 885 return Snippet.format("%sDelegate", getMemberSelectSnippet(key).toString().replace('.', '_')); 886 } 887 888 private Snippet initializeFactoryForContributionBinding(ContributionBinding binding) { 889 TypeName bindingKeyTypeName = TypeNames.forTypeMirror(binding.key().type()); 890 switch (binding.bindingKind()) { 891 case COMPONENT: 892 return Snippet.format( 893 "%s.<%s>create(%s)", 894 ClassName.fromClass(InstanceFactory.class), 895 bindingKeyTypeName, 896 bindingKeyTypeName.equals(componentDefinitionTypeName()) 897 ? "this" 898 : getComponentContributionSnippet(MoreTypes.asTypeElement(binding.key().type()))); 899 900 case COMPONENT_PROVISION: 901 { 902 TypeElement bindingTypeElement = 903 graph.componentDescriptor().dependencyMethodIndex().get(binding.bindingElement()); 904 String localFactoryVariable = simpleVariableName(bindingTypeElement); 905 Snippet callFactoryMethodSnippet = 906 Snippet.format( 907 "%s.%s()", 908 localFactoryVariable, 909 binding.bindingElement().getSimpleName().toString()); 910 // TODO(sameb): This throws a very vague NPE right now. The stack trace doesn't 911 // help to figure out what the method or return type is. If we include a string 912 // of the return type or method name in the error message, that can defeat obfuscation. 913 // We can easily include the raw type (no generics) + annotation type (no values), 914 // using .class & String.format -- but that wouldn't be the whole story. 915 // What should we do? 916 StringLiteral failMsg = 917 StringLiteral.forValue(CANNOT_RETURN_NULL_FROM_NON_NULLABLE_COMPONENT_METHOD); 918 Snippet getMethodBody = 919 binding.nullableType().isPresent() 920 || nullableValidationType.equals(Diagnostic.Kind.WARNING) 921 ? Snippet.format("return %s;", callFactoryMethodSnippet) 922 : Snippet.format( 923 Joiner.on('\n') 924 .join( 925 "%s provided = %s;", 926 "if (provided == null) {", 927 " throw new NullPointerException(%s);", 928 "}", 929 "return provided;"), 930 bindingKeyTypeName, 931 callFactoryMethodSnippet, 932 failMsg); 933 return Snippet.format( 934 Joiner.on('\n') 935 .join( 936 "new %1$s<%2$s>() {", 937 " private final %5$s %6$s = %3$s;", 938 " %4$s@Override public %2$s get() {", 939 " %7$s", 940 " }", 941 "}"), 942 /* 1 */ ClassName.fromClass(Factory.class), 943 /* 2 */ bindingKeyTypeName, 944 /* 3 */ getComponentContributionSnippet(bindingTypeElement), 945 /* 4 */ nullableSnippet(binding.nullableType()), 946 /* 5 */ TypeNames.forTypeMirror(bindingTypeElement.asType()), 947 /* 6 */ localFactoryVariable, 948 /* 7 */ getMethodBody); 949 } 950 951 case SUBCOMPONENT_BUILDER: 952 return Snippet.format( 953 Joiner.on('\n') 954 .join( 955 "new %1$s<%2$s>() {", 956 " @Override public %2$s get() {", 957 " return %3$s();", 958 " }", 959 "}"), 960 /* 1 */ ClassName.fromClass(Factory.class), 961 /* 2 */ bindingKeyTypeName, 962 /* 3 */ binding.bindingElement().getSimpleName().toString()); 963 964 case INJECTION: 965 case PROVISION: 966 { 967 List<Snippet> parameters = 968 Lists.newArrayListWithCapacity(binding.dependencies().size() + 1); 969 if (binding.bindingKind().equals(PROVISION) 970 && !binding.bindingElement().getModifiers().contains(STATIC)) { 971 parameters.add(getComponentContributionSnippet(binding.contributedBy().get())); 972 } 973 parameters.addAll(getDependencyParameters(binding)); 974 975 Snippet factorySnippet = 976 Snippet.format( 977 "%s.create(%s)", 978 generatedClassNameForBinding(binding), 979 Snippet.makeParametersSnippet(parameters)); 980 return binding.scope().isPresent() 981 ? Snippet.format( 982 "%s.create(%s)", ClassName.fromClass(ScopedProvider.class), factorySnippet) 983 : factorySnippet; 984 } 985 986 case COMPONENT_PRODUCTION: 987 { 988 TypeElement bindingTypeElement = 989 graph.componentDescriptor().dependencyMethodIndex().get(binding.bindingElement()); 990 return Snippet.format( 991 Joiner.on('\n') 992 .join( 993 "new %1$s<%2$s>() {", 994 " private final %6$s %7$s = %4$s;", 995 " @Override public %3$s<%2$s> get() {", 996 " return %7$s.%5$s();", 997 " }", 998 "}"), 999 /* 1 */ ClassName.fromClass(Producer.class), 1000 /* 2 */ TypeNames.forTypeMirror(binding.key().type()), 1001 /* 3 */ ClassName.fromClass(ListenableFuture.class), 1002 /* 4 */ getComponentContributionSnippet(bindingTypeElement), 1003 /* 5 */ binding.bindingElement().getSimpleName().toString(), 1004 /* 6 */ TypeNames.forTypeMirror(bindingTypeElement.asType()), 1005 /* 7 */ simpleVariableName(bindingTypeElement)); 1006 } 1007 1008 case IMMEDIATE: 1009 case FUTURE_PRODUCTION: 1010 { 1011 List<Snippet> parameters = 1012 Lists.newArrayListWithCapacity(binding.implicitDependencies().size() + 2); 1013 if (!binding.bindingElement().getModifiers().contains(STATIC)) { 1014 parameters.add(getComponentContributionSnippet(binding.bindingTypeElement())); 1015 } 1016 parameters.add( 1017 getComponentContributionSnippet( 1018 graph.componentDescriptor().executorDependency().get())); 1019 parameters.addAll(getProducerDependencyParameters(binding)); 1020 1021 return Snippet.format( 1022 "new %s(%s)", 1023 generatedClassNameForBinding(binding), 1024 Snippet.makeParametersSnippet(parameters)); 1025 } 1026 1027 default: 1028 throw new AssertionError(); 1029 } 1030 } 1031 1032 private Snippet nullableSnippet(Optional<DeclaredType> nullableType) { 1033 return nullableType.isPresent() 1034 ? Snippet.format("@%s ", TypeNames.forTypeMirror(nullableType.get())) 1035 : Snippet.format(""); 1036 } 1037 1038 private Snippet initializeMembersInjectorForBinding(MembersInjectionBinding binding) { 1039 switch (binding.injectionStrategy()) { 1040 case NO_OP: 1041 return Snippet.format("%s.noOp()", ClassName.fromClass(MembersInjectors.class)); 1042 case INJECT_MEMBERS: 1043 List<Snippet> parameters = getDependencyParameters(binding); 1044 return Snippet.format( 1045 "%s.create(%s)", 1046 membersInjectorNameForType(binding.bindingElement()), 1047 Snippet.makeParametersSnippet(parameters)); 1048 default: 1049 throw new AssertionError(); 1050 } 1051 } 1052 1053 private List<Snippet> getDependencyParameters(Binding binding) { 1054 ImmutableList.Builder<Snippet> parameters = ImmutableList.builder(); 1055 Set<Key> keysSeen = new HashSet<>(); 1056 for (Collection<DependencyRequest> requestsForKey : 1057 indexDependenciesByUnresolvedKey(types, binding.implicitDependencies()).asMap().values()) { 1058 Set<BindingKey> requestedBindingKeys = new HashSet<>(); 1059 for (DependencyRequest dependencyRequest : requestsForKey) { 1060 Element requestElement = dependencyRequest.requestElement(); 1061 TypeMirror typeMirror = typeMirrorAsMemberOf(binding.bindingTypeElement(), requestElement); 1062 Key key = keyFactory.forQualifiedType(dependencyRequest.key().qualifier(), typeMirror); 1063 if (keysSeen.add(key)) { 1064 requestedBindingKeys.add(dependencyRequest.bindingKey()); 1065 } 1066 } 1067 if (!requestedBindingKeys.isEmpty()) { 1068 BindingKey key = Iterables.getOnlyElement(requestedBindingKeys); 1069 parameters.add(getMemberSelect(key).getSnippetWithRawTypeCastFor(name)); 1070 } 1071 } 1072 return parameters.build(); 1073 } 1074 1075 // TODO(dpb): Investigate use of asMemberOf here. Why aren't the dependency requests already 1076 // resolved? 1077 private TypeMirror typeMirrorAsMemberOf(TypeElement bindingTypeElement, Element requestElement) { 1078 TypeMirror requestType = requestElement.asType(); 1079 if (requestType.getKind() == TypeKind.TYPEVAR) { 1080 return types.asMemberOf( 1081 MoreTypes.asDeclared(bindingTypeElement.asType()), 1082 (requestElement.getKind() == ElementKind.PARAMETER) 1083 ? MoreTypes.asElement(requestType) 1084 : requestElement); 1085 } else { 1086 return requestType; 1087 } 1088 } 1089 1090 private List<Snippet> getProducerDependencyParameters(Binding binding) { 1091 ImmutableList.Builder<Snippet> parameters = ImmutableList.builder(); 1092 for (Collection<DependencyRequest> requestsForKey : 1093 SourceFiles.indexDependenciesByUnresolvedKey(types, binding.implicitDependencies()) 1094 .asMap() 1095 .values()) { 1096 BindingKey key = Iterables.getOnlyElement(FluentIterable.from(requestsForKey) 1097 .transform(DependencyRequest.BINDING_KEY_FUNCTION)); 1098 ResolvedBindings resolvedBindings = graph.resolvedBindings().get(key); 1099 Class<?> frameworkClass = 1100 DependencyRequestMapper.FOR_PRODUCER.getFrameworkClass(requestsForKey); 1101 if (FrameworkField.frameworkClassForResolvedBindings(resolvedBindings).equals(Provider.class) 1102 && frameworkClass.equals(Producer.class)) { 1103 parameters.add( 1104 Snippet.format( 1105 "%s.producerFromProvider(%s)", 1106 ClassName.fromClass(Producers.class), 1107 getMemberSelectSnippet(key))); 1108 } else { 1109 parameters.add(getMemberSelectSnippet(key)); 1110 } 1111 } 1112 return parameters.build(); 1113 } 1114 1115 private Snippet initializeMapBinding(Set<ContributionBinding> bindings) { 1116 // Get type information from the first binding. 1117 ContributionBinding firstBinding = bindings.iterator().next(); 1118 DeclaredType mapType = asDeclared(firstBinding.key().type()); 1119 1120 if (isMapWithNonProvidedValues(mapType)) { 1121 return Snippet.format( 1122 "%s.create(%s)", 1123 ClassName.fromClass(MapFactory.class), 1124 getMemberSelectSnippet(getOnlyElement(firstBinding.dependencies()).bindingKey())); 1125 } 1126 1127 ImmutableList.Builder<dagger.internal.codegen.writer.Snippet> snippets = 1128 ImmutableList.builder(); 1129 snippets.add(Snippet.format("%s.<%s, %s>builder(%d)", 1130 ClassName.fromClass(MapProviderFactory.class), 1131 TypeNames.forTypeMirror(getKeyTypeOfMap(mapType)), 1132 TypeNames.forTypeMirror(getProvidedValueTypeOfMap(mapType)), // V of Map<K, Provider<V>> 1133 bindings.size())); 1134 1135 for (ContributionBinding binding : bindings) { 1136 snippets.add( 1137 Snippet.format( 1138 " .put(%s, %s)", 1139 getMapKeySnippet(binding.bindingElement()), 1140 getMultibindingContributionSnippet(binding).get().getSnippetFor(name))); 1141 } 1142 1143 snippets.add(Snippet.format(" .build()")); 1144 1145 return Snippet.concat(snippets.build()); 1146 } 1147 1148 private static String simpleVariableName(TypeElement typeElement) { 1149 return UPPER_CAMEL.to(LOWER_CAMEL, typeElement.getSimpleName().toString()); 1150 } 1151 1152 /** 1153 * Initialization state for a factory field. 1154 */ 1155 enum InitializationState { 1156 /** The field is {@code null}. */ 1157 UNINITIALIZED, 1158 1159 /** The field is set to a {@link DelegateFactory}. */ 1160 DELEGATED, 1161 1162 /** The field is set to an undelegated factory. */ 1163 INITIALIZED; 1164 } 1165 } 1166