1 /* 2 * Copyright (C) 2015 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.internal.codegen.componentgenerator; 18 19 import static com.google.auto.common.MoreElements.getLocalAndInheritedMethods; 20 import static com.google.auto.common.MoreTypes.asDeclared; 21 import static com.google.common.base.Preconditions.checkState; 22 import static com.squareup.javapoet.MethodSpec.constructorBuilder; 23 import static com.squareup.javapoet.MethodSpec.methodBuilder; 24 import static dagger.internal.codegen.binding.BindingRequest.bindingRequest; 25 import static dagger.internal.codegen.binding.ComponentCreatorKind.BUILDER; 26 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; 27 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED; 28 import static dagger.internal.codegen.javapoet.CodeBlocks.parameterNames; 29 import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.BUILDER_METHOD; 30 import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.CANCELLATION_LISTENER_METHOD; 31 import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.COMPONENT_METHOD; 32 import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.CONSTRUCTOR; 33 import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.INITIALIZE_METHOD; 34 import static dagger.internal.codegen.writing.ComponentImplementation.TypeSpecKind.COMPONENT_CREATOR; 35 import static dagger.internal.codegen.writing.ComponentImplementation.TypeSpecKind.SUBCOMPONENT; 36 import static dagger.producers.CancellationPolicy.Propagation.PROPAGATE; 37 import static javax.lang.model.element.Modifier.FINAL; 38 import static javax.lang.model.element.Modifier.PRIVATE; 39 import static javax.lang.model.element.Modifier.PUBLIC; 40 import static javax.lang.model.element.Modifier.STATIC; 41 42 import com.google.auto.common.MoreTypes; 43 import com.google.common.collect.ImmutableList; 44 import com.google.common.collect.ImmutableListMultimap; 45 import com.google.common.collect.ImmutableMap; 46 import com.google.common.collect.Iterables; 47 import com.google.common.collect.Lists; 48 import com.google.common.collect.Maps; 49 import com.google.common.collect.Multimaps; 50 import com.squareup.javapoet.ClassName; 51 import com.squareup.javapoet.CodeBlock; 52 import com.squareup.javapoet.MethodSpec; 53 import com.squareup.javapoet.ParameterSpec; 54 import com.squareup.javapoet.TypeSpec; 55 import dagger.internal.Preconditions; 56 import dagger.internal.codegen.binding.BindingGraph; 57 import dagger.internal.codegen.binding.ComponentCreatorDescriptor; 58 import dagger.internal.codegen.binding.ComponentCreatorKind; 59 import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor; 60 import dagger.internal.codegen.binding.ComponentRequirement; 61 import dagger.internal.codegen.binding.FrameworkType; 62 import dagger.internal.codegen.javapoet.AnnotationSpecs; 63 import dagger.internal.codegen.javapoet.CodeBlocks; 64 import dagger.internal.codegen.kotlin.KotlinMetadataUtil; 65 import dagger.internal.codegen.langmodel.DaggerElements; 66 import dagger.internal.codegen.langmodel.DaggerTypes; 67 import dagger.internal.codegen.writing.ComponentBindingExpressions; 68 import dagger.internal.codegen.writing.ComponentCreatorImplementation; 69 import dagger.internal.codegen.writing.ComponentImplementation; 70 import dagger.internal.codegen.writing.ComponentRequirementExpressions; 71 import dagger.internal.codegen.writing.ParentComponent; 72 import dagger.model.Key; 73 import dagger.producers.internal.CancellationListener; 74 import dagger.producers.internal.Producers; 75 import java.util.Collection; 76 import java.util.List; 77 import java.util.Map; 78 import java.util.Optional; 79 import java.util.function.Function; 80 import javax.inject.Inject; 81 import javax.lang.model.element.ExecutableElement; 82 import javax.lang.model.type.DeclaredType; 83 84 /** A builder of {@link ComponentImplementation}s. */ 85 // This only needs to be public because it's referenced in an entry point. 86 public final class ComponentImplementationBuilder { 87 private static final String MAY_INTERRUPT_IF_RUNNING = "mayInterruptIfRunning"; 88 89 /** 90 * How many statements per {@code initialize()} or {@code onProducerFutureCancelled()} method 91 * before they get partitioned. 92 */ 93 private static final int STATEMENTS_PER_METHOD = 100; 94 95 private static final String CANCELLATION_LISTENER_METHOD_NAME = "onProducerFutureCancelled"; 96 97 private final Optional<ComponentImplementationBuilder> parent; 98 private final BindingGraph graph; 99 private final ComponentBindingExpressions bindingExpressions; 100 private final ComponentRequirementExpressions componentRequirementExpressions; 101 private final ComponentImplementation componentImplementation; 102 private final ComponentCreatorImplementationFactory componentCreatorImplementationFactory; 103 private final TopLevelImplementationComponent topLevelImplementationComponent; 104 private final DaggerTypes types; 105 private final DaggerElements elements; 106 private final KotlinMetadataUtil metadataUtil; 107 private boolean done; 108 109 @Inject ComponentImplementationBuilder( @arentComponent Optional<ComponentImplementationBuilder> parent, BindingGraph graph, ComponentBindingExpressions bindingExpressions, ComponentRequirementExpressions componentRequirementExpressions, ComponentImplementation componentImplementation, ComponentCreatorImplementationFactory componentCreatorImplementationFactory, TopLevelImplementationComponent topLevelImplementationComponent, DaggerTypes types, DaggerElements elements, KotlinMetadataUtil metadataUtil)110 ComponentImplementationBuilder( 111 @ParentComponent Optional<ComponentImplementationBuilder> parent, 112 BindingGraph graph, 113 ComponentBindingExpressions bindingExpressions, 114 ComponentRequirementExpressions componentRequirementExpressions, 115 ComponentImplementation componentImplementation, 116 ComponentCreatorImplementationFactory componentCreatorImplementationFactory, 117 TopLevelImplementationComponent topLevelImplementationComponent, 118 DaggerTypes types, 119 DaggerElements elements, 120 KotlinMetadataUtil metadataUtil) { 121 this.parent = parent; 122 this.graph = graph; 123 this.bindingExpressions = bindingExpressions; 124 this.componentRequirementExpressions = componentRequirementExpressions; 125 this.componentImplementation = componentImplementation; 126 this.componentCreatorImplementationFactory = componentCreatorImplementationFactory; 127 this.types = types; 128 this.elements = elements; 129 this.topLevelImplementationComponent = topLevelImplementationComponent; 130 this.metadataUtil = metadataUtil; 131 } 132 133 /** 134 * Returns a {@link ComponentImplementation} for this component. This is only intended to be 135 * called once (and will throw on successive invocations). If the component must be regenerated, 136 * use a new instance. 137 */ build()138 ComponentImplementation build() { 139 checkState( 140 !done, 141 "ComponentImplementationBuilder has already built the ComponentImplementation for [%s].", 142 componentImplementation.name()); 143 setSupertype(); 144 145 componentCreatorImplementationFactory.create() 146 .map(ComponentCreatorImplementation::spec) 147 .ifPresent(this::addCreatorClass); 148 149 getLocalAndInheritedMethods(graph.componentTypeElement(), types, elements) 150 .forEach(method -> componentImplementation.claimMethodName(method.getSimpleName())); 151 152 addFactoryMethods(); 153 addInterfaceMethods(); 154 addChildComponents(); 155 156 addConstructorAndInitializationMethods(); 157 158 if (graph.componentDescriptor().isProduction()) { 159 addCancellationListenerImplementation(); 160 } 161 162 done = true; 163 return componentImplementation; 164 } 165 166 /** Set the supertype for this generated class. */ setSupertype()167 private void setSupertype() { 168 componentImplementation.addSupertype(graph.componentTypeElement()); 169 } 170 addCreatorClass(TypeSpec creator)171 private void addCreatorClass(TypeSpec creator) { 172 if (parent.isPresent()) { 173 // In an inner implementation of a subcomponent the creator is a peer class. 174 parent.get().componentImplementation.addType(SUBCOMPONENT, creator); 175 } else { 176 componentImplementation.addType(COMPONENT_CREATOR, creator); 177 } 178 } 179 addFactoryMethods()180 private void addFactoryMethods() { 181 if (parent.isPresent()) { 182 graph.factoryMethod().ifPresent(this::createSubcomponentFactoryMethod); 183 } else { 184 createRootComponentFactoryMethod(); 185 } 186 } 187 addInterfaceMethods()188 private void addInterfaceMethods() { 189 // Each component method may have been declared by several supertypes. We want to implement 190 // only one method for each distinct signature. 191 ImmutableListMultimap<MethodSignature, ComponentMethodDescriptor> componentMethodsBySignature = 192 Multimaps.index(graph.componentDescriptor().entryPointMethods(), this::getMethodSignature); 193 for (List<ComponentMethodDescriptor> methodsWithSameSignature : 194 Multimaps.asMap(componentMethodsBySignature).values()) { 195 ComponentMethodDescriptor anyOneMethod = methodsWithSameSignature.stream().findAny().get(); 196 MethodSpec methodSpec = bindingExpressions.getComponentMethod(anyOneMethod); 197 198 componentImplementation.addMethod(COMPONENT_METHOD, methodSpec); 199 } 200 } 201 addCancellationListenerImplementation()202 private void addCancellationListenerImplementation() { 203 componentImplementation.addSupertype(elements.getTypeElement(CancellationListener.class)); 204 componentImplementation.claimMethodName(CANCELLATION_LISTENER_METHOD_NAME); 205 206 ImmutableList<ParameterSpec> parameters = 207 ImmutableList.of(ParameterSpec.builder(boolean.class, MAY_INTERRUPT_IF_RUNNING).build()); 208 209 MethodSpec.Builder methodBuilder = 210 methodBuilder(CANCELLATION_LISTENER_METHOD_NAME) 211 .addModifiers(PUBLIC) 212 .addAnnotation(Override.class) 213 .addParameters(parameters); 214 215 ImmutableList<CodeBlock> cancellationStatements = cancellationStatements(); 216 217 if (cancellationStatements.size() < STATEMENTS_PER_METHOD) { 218 methodBuilder.addCode(CodeBlocks.concat(cancellationStatements)).build(); 219 } else { 220 ImmutableList<MethodSpec> cancelProducersMethods = 221 createPartitionedMethods( 222 "cancelProducers", 223 parameters, 224 cancellationStatements, 225 methodName -> methodBuilder(methodName).addModifiers(PRIVATE)); 226 for (MethodSpec cancelProducersMethod : cancelProducersMethods) { 227 methodBuilder.addStatement("$N($L)", cancelProducersMethod, MAY_INTERRUPT_IF_RUNNING); 228 componentImplementation.addMethod(CANCELLATION_LISTENER_METHOD, cancelProducersMethod); 229 } 230 } 231 232 cancelParentStatement().ifPresent(methodBuilder::addCode); 233 234 componentImplementation.addMethod(CANCELLATION_LISTENER_METHOD, methodBuilder.build()); 235 } 236 cancellationStatements()237 private ImmutableList<CodeBlock> cancellationStatements() { 238 // Reversing should order cancellations starting from entry points and going down to leaves 239 // rather than the other way around. This shouldn't really matter but seems *slightly* 240 // preferable because: 241 // When a future that another future depends on is cancelled, that cancellation will propagate 242 // up the future graph toward the entry point. Cancelling in reverse order should ensure that 243 // everything that depends on a particular node has already been cancelled when that node is 244 // cancelled, so there's no need to propagate. Otherwise, when we cancel a leaf node, it might 245 // propagate through most of the graph, making most of the cancel calls that follow in the 246 // onProducerFutureCancelled method do nothing. 247 ImmutableList<Key> cancellationKeys = 248 componentImplementation.getCancellableProducerKeys().reverse(); 249 250 ImmutableList.Builder<CodeBlock> cancellationStatements = ImmutableList.builder(); 251 for (Key cancellationKey : cancellationKeys) { 252 cancellationStatements.add( 253 CodeBlock.of( 254 "$T.cancel($L, $N);", 255 Producers.class, 256 bindingExpressions 257 .getDependencyExpression( 258 bindingRequest(cancellationKey, FrameworkType.PRODUCER_NODE), 259 componentImplementation.name()) 260 .codeBlock(), 261 MAY_INTERRUPT_IF_RUNNING)); 262 } 263 return cancellationStatements.build(); 264 } 265 cancelParentStatement()266 private Optional<CodeBlock> cancelParentStatement() { 267 if (!shouldPropagateCancellationToParent()) { 268 return Optional.empty(); 269 } 270 return Optional.of( 271 CodeBlock.builder() 272 .addStatement( 273 "$T.this.$N($N)", 274 parent.get().componentImplementation.name(), 275 CANCELLATION_LISTENER_METHOD_NAME, 276 MAY_INTERRUPT_IF_RUNNING) 277 .build()); 278 } 279 shouldPropagateCancellationToParent()280 private boolean shouldPropagateCancellationToParent() { 281 return parent.isPresent() 282 && parent 283 .get() 284 .componentImplementation 285 .componentDescriptor() 286 .cancellationPolicy() 287 .map(policy -> policy.fromSubcomponents().equals(PROPAGATE)) 288 .orElse(false); 289 } 290 getMethodSignature(ComponentMethodDescriptor method)291 private MethodSignature getMethodSignature(ComponentMethodDescriptor method) { 292 return MethodSignature.forComponentMethod( 293 method, MoreTypes.asDeclared(graph.componentTypeElement().asType()), types); 294 } 295 addChildComponents()296 private void addChildComponents() { 297 for (BindingGraph subgraph : graph.subgraphs()) { 298 componentImplementation.addType(SUBCOMPONENT, childComponent(subgraph)); 299 } 300 } 301 childComponent(BindingGraph childGraph)302 private TypeSpec childComponent(BindingGraph childGraph) { 303 return topLevelImplementationComponent 304 .currentImplementationSubcomponentBuilder() 305 .componentImplementation(subcomponent(childGraph)) 306 .bindingGraph(childGraph) 307 .parentBuilder(Optional.of(this)) 308 .parentBindingExpressions(Optional.of(bindingExpressions)) 309 .parentRequirementExpressions(Optional.of(componentRequirementExpressions)) 310 .build() 311 .componentImplementationBuilder() 312 .build() 313 .generate() 314 .build(); 315 } 316 317 /** Creates an inner subcomponent implementation. */ subcomponent(BindingGraph childGraph)318 private ComponentImplementation subcomponent(BindingGraph childGraph) { 319 return componentImplementation.childComponentImplementation(childGraph); 320 } 321 322 /** Creates and adds the constructor and methods needed for initializing the component. */ addConstructorAndInitializationMethods()323 private void addConstructorAndInitializationMethods() { 324 MethodSpec.Builder constructor = constructorBuilder().addModifiers(PRIVATE); 325 implementInitializationMethod(constructor, initializationParameters()); 326 componentImplementation.addMethod(CONSTRUCTOR, constructor.build()); 327 } 328 329 /** Adds parameters and code to the given {@code initializationMethod}. */ implementInitializationMethod( MethodSpec.Builder initializationMethod, ImmutableMap<ComponentRequirement, ParameterSpec> initializationParameters)330 private void implementInitializationMethod( 331 MethodSpec.Builder initializationMethod, 332 ImmutableMap<ComponentRequirement, ParameterSpec> initializationParameters) { 333 initializationMethod.addParameters(initializationParameters.values()); 334 initializationMethod.addCode( 335 CodeBlocks.concat(componentImplementation.getComponentRequirementInitializations())); 336 addInitializeMethods(initializationMethod, initializationParameters.values().asList()); 337 } 338 339 /** 340 * Adds any necessary {@code initialize} methods to the component and adds calls to them to the 341 * given {@code callingMethod}. 342 */ addInitializeMethods( MethodSpec.Builder callingMethod, ImmutableList<ParameterSpec> parameters)343 private void addInitializeMethods( 344 MethodSpec.Builder callingMethod, ImmutableList<ParameterSpec> parameters) { 345 // TODO(cgdecker): It's not the case that each initialize() method has need for all of the 346 // given parameters. In some cases, those parameters may have already been assigned to fields 347 // which could be referenced instead. In other cases, an initialize method may just not need 348 // some of the parameters because the set of initializations in that partition does not 349 // include any reference to them. Right now, the Dagger code has no way of getting that 350 // information because, among other things, componentImplementation.getImplementations() just 351 // returns a bunch of CodeBlocks with no semantic information. Additionally, we may not know 352 // yet whether a field will end up needing to be created for a specific requirement, and we 353 // don't want to create a field that ends up only being used during initialization. 354 CodeBlock args = parameterNames(parameters); 355 ImmutableList<MethodSpec> methods = 356 createPartitionedMethods( 357 "initialize", 358 makeFinal(parameters), 359 componentImplementation.getInitializations(), 360 methodName -> 361 methodBuilder(methodName) 362 .addModifiers(PRIVATE) 363 /* TODO(gak): Strictly speaking, we only need the suppression here if we are 364 * also initializing a raw field in this method, but the structure of this 365 * code makes it awkward to pass that bit through. This will be cleaned up 366 * when we no longer separate fields and initialization as we do now. */ 367 .addAnnotation(AnnotationSpecs.suppressWarnings(UNCHECKED))); 368 for (MethodSpec method : methods) { 369 callingMethod.addStatement("$N($L)", method, args); 370 componentImplementation.addMethod(INITIALIZE_METHOD, method); 371 } 372 } 373 374 /** 375 * Creates one or more methods, all taking the given {@code parameters}, which partition the given 376 * list of {@code statements} among themselves such that no method has more than {@code 377 * STATEMENTS_PER_METHOD} statements in it and such that the returned methods, if called in order, 378 * will execute the {@code statements} in the given order. 379 */ createPartitionedMethods( String methodName, Iterable<ParameterSpec> parameters, List<CodeBlock> statements, Function<String, MethodSpec.Builder> methodBuilderCreator)380 private ImmutableList<MethodSpec> createPartitionedMethods( 381 String methodName, 382 Iterable<ParameterSpec> parameters, 383 List<CodeBlock> statements, 384 Function<String, MethodSpec.Builder> methodBuilderCreator) { 385 return Lists.partition(statements, STATEMENTS_PER_METHOD).stream() 386 .map( 387 partition -> 388 methodBuilderCreator 389 .apply(componentImplementation.getUniqueMethodName(methodName)) 390 .addParameters(parameters) 391 .addCode(CodeBlocks.concat(partition)) 392 .build()) 393 .collect(toImmutableList()); 394 } 395 396 /** Returns the given parameters with a final modifier added. */ makeFinal(Collection<ParameterSpec> parameters)397 private final ImmutableList<ParameterSpec> makeFinal(Collection<ParameterSpec> parameters) { 398 return parameters.stream() 399 .map(param -> param.toBuilder().addModifiers(FINAL).build()) 400 .collect(toImmutableList()); 401 } 402 403 /** 404 * Returns the parameters for the constructor as a map from the requirement the parameter fulfills 405 * to the spec for the parameter. 406 */ initializationParameters()407 private final ImmutableMap<ComponentRequirement, ParameterSpec> initializationParameters() { 408 Map<ComponentRequirement, ParameterSpec> parameters; 409 if (componentImplementation.componentDescriptor().hasCreator()) { 410 parameters = Maps.toMap(graph.componentRequirements(), ComponentRequirement::toParameterSpec); 411 } else if (graph.factoryMethod().isPresent()) { 412 parameters = getFactoryMethodParameters(graph); 413 } else { 414 throw new AssertionError( 415 "Expected either a component creator or factory method but found neither."); 416 } 417 418 return renameParameters(parameters); 419 } 420 421 /** 422 * Renames the given parameters to guarantee their names do not conflict with fields in the 423 * component to ensure that a parameter is never referenced where a reference to a field was 424 * intended. 425 */ 426 // TODO(cgdecker): This is a bit kludgy; it would be preferable to either qualify the field 427 // references with "this." or "super." when needed to disambiguate between field and parameter, 428 // but that would require more context than is currently available when the code referencing a 429 // field is generated. renameParameters( Map<ComponentRequirement, ParameterSpec> parameters)430 private ImmutableMap<ComponentRequirement, ParameterSpec> renameParameters( 431 Map<ComponentRequirement, ParameterSpec> parameters) { 432 return ImmutableMap.copyOf( 433 Maps.transformEntries( 434 parameters, 435 (requirement, parameter) -> 436 renameParameter( 437 parameter, 438 componentImplementation.getParameterName(requirement, parameter.name)))); 439 } 440 renameParameter(ParameterSpec parameter, String newName)441 private ParameterSpec renameParameter(ParameterSpec parameter, String newName) { 442 return ParameterSpec.builder(parameter.type, newName) 443 .addAnnotations(parameter.annotations) 444 .addModifiers(parameter.modifiers) 445 .build(); 446 } 447 createRootComponentFactoryMethod()448 private void createRootComponentFactoryMethod() { 449 checkState(!parent.isPresent()); 450 // Top-level components have a static method that returns a builder or factory for the 451 // component. If the user defined a @Component.Builder or @Component.Factory, an 452 // implementation of their type is returned. Otherwise, an autogenerated Builder type is 453 // returned. 454 // TODO(cgdecker): Replace this abomination with a small class? 455 // Better yet, change things so that an autogenerated builder type has a descriptor of sorts 456 // just like a user-defined creator type. 457 ComponentCreatorKind creatorKind; 458 ClassName creatorType; 459 String factoryMethodName; 460 boolean noArgFactoryMethod; 461 Optional<ComponentCreatorDescriptor> creatorDescriptor = 462 graph.componentDescriptor().creatorDescriptor(); 463 if (creatorDescriptor.isPresent()) { 464 ComponentCreatorDescriptor descriptor = creatorDescriptor.get(); 465 creatorKind = descriptor.kind(); 466 creatorType = ClassName.get(descriptor.typeElement()); 467 factoryMethodName = descriptor.factoryMethod().getSimpleName().toString(); 468 noArgFactoryMethod = descriptor.factoryParameters().isEmpty(); 469 } else { 470 creatorKind = BUILDER; 471 creatorType = componentImplementation.getCreatorName(); 472 factoryMethodName = "build"; 473 noArgFactoryMethod = true; 474 } 475 476 MethodSpec creatorFactoryMethod = 477 methodBuilder(creatorKind.methodName()) 478 .addModifiers(PUBLIC, STATIC) 479 .returns(creatorType) 480 .addStatement("return new $T()", componentImplementation.getCreatorName()) 481 .build(); 482 componentImplementation.addMethod(BUILDER_METHOD, creatorFactoryMethod); 483 if (noArgFactoryMethod && canInstantiateAllRequirements()) { 484 componentImplementation.addMethod( 485 BUILDER_METHOD, 486 methodBuilder("create") 487 .returns(ClassName.get(graph.componentTypeElement())) 488 .addModifiers(PUBLIC, STATIC) 489 .addStatement("return new $L().$L()", creatorKind.typeName(), factoryMethodName) 490 .build()); 491 } 492 } 493 494 /** {@code true} if all of the graph's required dependencies can be automatically constructed */ canInstantiateAllRequirements()495 private boolean canInstantiateAllRequirements() { 496 return !Iterables.any( 497 graph.componentRequirements(), 498 dependency -> dependency.requiresAPassedInstance(elements, types, metadataUtil)); 499 } 500 createSubcomponentFactoryMethod(ExecutableElement factoryMethod)501 private void createSubcomponentFactoryMethod(ExecutableElement factoryMethod) { 502 checkState(parent.isPresent()); 503 Collection<ParameterSpec> params = getFactoryMethodParameters(graph).values(); 504 MethodSpec.Builder method = MethodSpec.overriding(factoryMethod, parentType(), types); 505 params.forEach( 506 param -> method.addStatement("$T.checkNotNull($N)", Preconditions.class, param)); 507 method.addStatement( 508 "return new $T($L)", componentImplementation.name(), parameterNames(params)); 509 510 parent.get().componentImplementation.addMethod(COMPONENT_METHOD, method.build()); 511 } 512 parentType()513 private DeclaredType parentType() { 514 return asDeclared(parent.get().graph.componentTypeElement().asType()); 515 } 516 /** 517 * Returns the map of {@link ComponentRequirement}s to {@link ParameterSpec}s for the given 518 * graph's factory method. 519 */ getFactoryMethodParameters( BindingGraph graph)520 private static Map<ComponentRequirement, ParameterSpec> getFactoryMethodParameters( 521 BindingGraph graph) { 522 return Maps.transformValues(graph.factoryMethodParameters(), ParameterSpec::get); 523 } 524 } 525