blob: 36108cfa208bb92604adf4fda7903629d88365e3 [file] [log] [blame]
bcorsoc5dac092017-11-29 09:23:02 -08001/*
2 * Copyright (C) 2017 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
17package dagger.internal.codegen;
18
bcorsoc5dac092017-11-29 09:23:02 -080019import static com.google.common.base.Preconditions.checkNotNull;
20import static com.squareup.javapoet.MethodSpec.methodBuilder;
21import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom;
bcorso2b8e1682017-12-05 13:59:00 -080022import static dagger.internal.codegen.GeneratedComponentModel.MethodSpecKind.MEMBERS_INJECTION_METHOD;
bcorsoc5dac092017-11-29 09:23:02 -080023import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
24import static javax.lang.model.element.Modifier.PRIVATE;
25
bcorsoc5dac092017-11-29 09:23:02 -080026import com.google.common.collect.ImmutableSet;
27import com.squareup.javapoet.ClassName;
28import com.squareup.javapoet.CodeBlock;
29import com.squareup.javapoet.MethodSpec;
30import com.squareup.javapoet.ParameterSpec;
31import com.squareup.javapoet.TypeName;
32import dagger.internal.codegen.InjectionMethods.InjectionSiteMethod;
33import dagger.internal.codegen.MembersInjectionBinding.InjectionSite;
ronshapiroa6f99ed2017-12-12 09:26:26 -080034import dagger.model.Key;
bcorsoc5dac092017-11-29 09:23:02 -080035import java.util.LinkedHashMap;
36import java.util.Map;
37import javax.lang.model.element.Name;
38import javax.lang.model.element.TypeElement;
39import javax.lang.model.type.TypeMirror;
bcorsoc5dac092017-11-29 09:23:02 -080040
41/** Manages the member injection methods for a component. */
42final class MembersInjectionMethods {
43 private final Map<Key, MethodSpec> membersInjectionMethods = new LinkedHashMap<>();
44 private final GeneratedComponentModel generatedComponentModel;
45 private final ComponentBindingExpressions bindingExpressions;
46 private final BindingGraph graph;
dpbe7b89582018-02-19 08:42:19 -080047 private final DaggerElements elements;
bcorsoc5dac092017-11-29 09:23:02 -080048 private final DaggerTypes types;
49
50 MembersInjectionMethods(
51 GeneratedComponentModel generatedComponentModel,
52 ComponentBindingExpressions bindingExpressions,
53 BindingGraph graph,
dpbe7b89582018-02-19 08:42:19 -080054 DaggerElements elements,
bcorsoc5dac092017-11-29 09:23:02 -080055 DaggerTypes types) {
56 this.generatedComponentModel = checkNotNull(generatedComponentModel);
57 this.bindingExpressions = checkNotNull(bindingExpressions);
58 this.graph = checkNotNull(graph);
59 this.elements = checkNotNull(elements);
60 this.types = checkNotNull(types);
61 }
62
63 /**
64 * Returns the members injection {@link MethodSpec} for the given {@link Key}, creating it if
65 * necessary.
bcorsoc5dac092017-11-29 09:23:02 -080066 */
67 MethodSpec getOrCreate(Key key) {
68 return reentrantComputeIfAbsent(membersInjectionMethods, key, this::membersInjectionMethod);
69 }
70
bcorsoc5dac092017-11-29 09:23:02 -080071 private MethodSpec membersInjectionMethod(Key key) {
ronshapiro0a277fd2017-12-22 08:30:49 -080072 ResolvedBindings resolvedBindings =
73 graph.membersInjectionBindings().getOrDefault(key, graph.contributionBindings().get(key));
74 Binding binding = resolvedBindings.binding();
bcorsoc5dac092017-11-29 09:23:02 -080075 TypeMirror keyType = binding.key().type();
76 TypeMirror membersInjectedType =
77 isTypeAccessibleFrom(keyType, generatedComponentModel.name().packageName())
78 ? keyType
dpbe7b89582018-02-19 08:42:19 -080079 : elements.getTypeElement(Object.class).asType();
bcorsoc5dac092017-11-29 09:23:02 -080080 TypeName membersInjectedTypeName = TypeName.get(membersInjectedType);
81 Name bindingTypeName = binding.bindingTypeElement().get().getSimpleName();
82 // TODO(ronshapiro): include type parameters in this name e.g. injectFooOfT, and outer class
83 // simple names Foo.Builder -> injectFooBuilder
84 String methodName = generatedComponentModel.getUniqueMethodName("inject" + bindingTypeName);
85 ParameterSpec parameter = ParameterSpec.builder(membersInjectedTypeName, "instance").build();
bcorso2b8e1682017-12-05 13:59:00 -080086 MethodSpec.Builder methodBuilder =
bcorsoc5dac092017-11-29 09:23:02 -080087 methodBuilder(methodName)
88 .addModifiers(PRIVATE)
89 .returns(membersInjectedTypeName)
90 .addParameter(parameter);
91 TypeElement canIgnoreReturnValue =
92 elements.getTypeElement("com.google.errorprone.annotations.CanIgnoreReturnValue");
93 if (canIgnoreReturnValue != null) {
bcorso2b8e1682017-12-05 13:59:00 -080094 methodBuilder.addAnnotation(ClassName.get(canIgnoreReturnValue));
bcorsoc5dac092017-11-29 09:23:02 -080095 }
96 CodeBlock instance = CodeBlock.of("$N", parameter);
bcorso2b8e1682017-12-05 13:59:00 -080097 methodBuilder.addCode(
bcorsoc5dac092017-11-29 09:23:02 -080098 InjectionSiteMethod.invokeAll(
99 injectionSites(binding),
100 generatedComponentModel.name(),
101 instance,
102 membersInjectedType,
103 types,
104 request ->
105 bindingExpressions
106 .getDependencyArgumentExpression(request, generatedComponentModel.name())
107 .codeBlock()));
bcorso2b8e1682017-12-05 13:59:00 -0800108 methodBuilder.addStatement("return $L", instance);
bcorsoc5dac092017-11-29 09:23:02 -0800109
bcorso2b8e1682017-12-05 13:59:00 -0800110 MethodSpec method = methodBuilder.build();
111 generatedComponentModel.addMethod(MEMBERS_INJECTION_METHOD, method);
112 return method;
bcorsoc5dac092017-11-29 09:23:02 -0800113 }
114
115 private static ImmutableSet<InjectionSite> injectionSites(Binding binding) {
116 if (binding instanceof ProvisionBinding) {
117 return ((ProvisionBinding) binding).injectionSites();
118 } else if (binding instanceof MembersInjectionBinding) {
119 return ((MembersInjectionBinding) binding).injectionSites();
120 }
121 throw new IllegalArgumentException(binding.key().toString());
122 }
123}