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 AbstractComponentWriter( Types types, Elements elements, Key.Factory keyFactory, Diagnostic.Kind nullableValidationType, ClassName name, BindingGraph graph)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 componentDefinitionType()170 protected final TypeElement componentDefinitionType() { 171 return graph.componentDescriptor().componentDefinitionType(); 172 } 173 componentDefinitionTypeName()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 */ getComponentContributionSnippet(TypeElement contributionType)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 */ getOrCreateComponentContributionFieldSnippet( TypeElement contributionType)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 getMemberSelectSnippet(BindingKey key)218 private Snippet getMemberSelectSnippet(BindingKey key) { 219 return getMemberSelect(key).getSnippetFor(name); 220 } 221 getMemberSelect(BindingKey key)222 protected MemberSelect getMemberSelect(BindingKey key) { 223 return memberSelectSnippets.get(key); 224 } 225 getMultibindingContributionSnippet(ContributionBinding binding)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 */ getInitializationState(BindingKey bindingKey)233 protected InitializationState getInitializationState(BindingKey bindingKey) { 234 return initializationStates.containsKey(bindingKey) 235 ? initializationStates.get(bindingKey) 236 : UNINITIALIZED; 237 } 238 setInitializationState(BindingKey bindingKey, InitializationState state)239 private void setInitializationState(BindingKey bindingKey, InitializationState state) { 240 initializationStates.put(bindingKey, state); 241 } 242 getContributionInitializationState(Binding binding)243 private InitializationState getContributionInitializationState(Binding binding) { 244 return contributionInitializationStates.containsKey(binding) 245 ? contributionInitializationStates.get(binding) 246 : UNINITIALIZED; 247 } 248 setContributionInitializationState(Binding binding, InitializationState state)249 private void setContributionInitializationState(Binding binding, InitializationState state) { 250 contributionInitializationStates.put(binding, state); 251 } 252 write()253 ImmutableSet<JavaWriter> write() { 254 if (javaWriters.isEmpty()) { 255 writeComponent(); 256 } 257 return ImmutableSet.copyOf(javaWriters); 258 } 259 writeComponent()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 */ createComponentClass()274 protected abstract ClassWriter createComponentClass(); 275 addConstructor()276 private void addConstructor() { 277 constructorWriter = componentWriter.addConstructor(); 278 constructorWriter.addModifiers(PRIVATE); 279 } 280 281 /** 282 * Adds a builder type. 283 */ addBuilder()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 */ addBuilderFields(ClassWriter builderWriter)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. */ addBuildMethod(ClassWriter builderWriter, Optional<BuilderSpec> builderSpec)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 */ addBuilderMethods( ClassWriter builderWriter, Optional<BuilderSpec> builderSpec)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 addBuilderMethodReturnStatementForSpec( ExecutableElement specMethod, MethodWriter builderMethod)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 addBuilderMethodFromSpec( ClassWriter builderWriter, ExecutableElement method)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 */ createBuilder()448 protected abstract ClassWriter createBuilder(); 449 450 /** 451 * Adds component factory methods. 452 */ addFactoryMethods()453 protected abstract void addFactoryMethods(); 454 addFields()455 private void addFields() { 456 for (ResolvedBindings resolvedBindings : graph.resolvedBindings().values()) { 457 addField(resolvedBindings); 458 } 459 } 460 addField(ResolvedBindings resolvedBindings)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 addFrameworkField(boolean useRawType, FrameworkField contributionBindingField)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 */ staticMemberSelect(ResolvedBindings resolvedBindings)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 implementInterfaceMethods()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 addSubcomponents()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 initializeFrameworkTypes()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 */ initializeFrameworkType(BindingKey bindingKey)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 initializeSetMultibindings(ResolvedBindings resolvedBindings)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 initializeMapMultibindings(ResolvedBindings resolvedBindings)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 initializeUniqueContributionBinding(ResolvedBindings resolvedBindings)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 initializeMembersInjectionBinding(ResolvedBindings resolvedBindings)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 initializeDelegateFactories(Binding binding)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 initializeMember(BindingKey bindingKey, Snippet initializationSnippet)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 delegateFactoryVariableSnippet(BindingKey key)884 private Snippet delegateFactoryVariableSnippet(BindingKey key) { 885 return Snippet.format("%sDelegate", getMemberSelectSnippet(key).toString().replace('.', '_')); 886 } 887 initializeFactoryForContributionBinding(ContributionBinding binding)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 nullableSnippet(Optional<DeclaredType> nullableType)1032 private Snippet nullableSnippet(Optional<DeclaredType> nullableType) { 1033 return nullableType.isPresent() 1034 ? Snippet.format("@%s ", TypeNames.forTypeMirror(nullableType.get())) 1035 : Snippet.format(""); 1036 } 1037 initializeMembersInjectorForBinding(MembersInjectionBinding binding)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 getDependencyParameters(Binding binding)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? typeMirrorAsMemberOf(TypeElement bindingTypeElement, Element requestElement)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 getProducerDependencyParameters(Binding binding)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 initializeMapBinding(Set<ContributionBinding> bindings)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 simpleVariableName(TypeElement typeElement)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