blob: 4d06d38ca140682acaf296d178c57a16d8e05020 [file] [log] [blame]
erichang9dd6aed2017-06-15 15:54:00 -07001/*
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
erichang9dd6aed2017-06-15 15:54:00 -070019import static com.google.common.base.Preconditions.checkNotNull;
erichang43774172017-08-04 10:42:07 -070020import static dagger.internal.codegen.AnnotationSpecs.Suppression.RAWTYPES;
dpbb5ae2492017-08-18 14:58:23 -070021import static dagger.internal.codegen.FrameworkInstanceBindingExpression.producerFromProviderBindingExpression;
erichang9dd6aed2017-06-15 15:54:00 -070022import static dagger.internal.codegen.MemberSelect.staticMemberSelect;
erichang43774172017-08-04 10:42:07 -070023import static dagger.internal.codegen.TypeNames.PRODUCER;
24import static javax.lang.model.element.Modifier.PRIVATE;
erichang9dd6aed2017-06-15 15:54:00 -070025
erichang9dd6aed2017-06-15 15:54:00 -070026import com.google.common.collect.ImmutableMap;
27import com.squareup.javapoet.ClassName;
28import com.squareup.javapoet.CodeBlock;
29import com.squareup.javapoet.FieldSpec;
erichang9dd6aed2017-06-15 15:54:00 -070030import java.util.Optional;
ronshapirocb725da2017-07-04 15:14:48 -070031import javax.lang.model.util.Elements;
erichang9dd6aed2017-06-15 15:54:00 -070032
dpb68c77d82017-08-15 15:23:35 -070033/** A factory of code expressions used to access a single binding in a component. */
ronshapiro186d17a2017-08-11 08:18:07 -070034abstract class BindingExpression {
dpbb5ae2492017-08-18 14:58:23 -070035 // TODO(dpb): Put the Binding or ResolvedBindings itself here.
ronshapiro186d17a2017-08-11 08:18:07 -070036 private final BindingKey bindingKey;
erichang9dd6aed2017-06-15 15:54:00 -070037
ronshapiro186d17a2017-08-11 08:18:07 -070038 BindingExpression(BindingKey bindingKey) {
39 this.bindingKey = checkNotNull(bindingKey);
dpb02dd23f2017-07-27 11:13:11 -070040 }
41
ronshapiro186d17a2017-08-11 08:18:07 -070042 /** The key for which this instance can fulfill requests. */
43 final BindingKey bindingKey() {
44 return bindingKey;
dpb02dd23f2017-07-27 11:13:11 -070045 }
46
47 /**
dpb68c77d82017-08-15 15:23:35 -070048 * Returns an expression that evaluates to the value of a request for a given kind of dependency
49 * on this binding.
dpba6ff6c12017-08-14 08:47:36 -070050 *
51 * @param requestingClass the class that will contain the expression
dpb02dd23f2017-07-27 11:13:11 -070052 */
dpba6ff6c12017-08-14 08:47:36 -070053 abstract CodeBlock getDependencyExpression(
dpb68c77d82017-08-15 15:23:35 -070054 DependencyRequest.Kind requestKind, ClassName requestingClass);
dpba6ff6c12017-08-14 08:47:36 -070055
erichang9dd6aed2017-06-15 15:54:00 -070056 /** Factory for building a {@link BindingExpression}. */
57 static final class Factory {
dpbc8c6c052017-07-28 10:48:06 -070058 private final CompilerOptions compilerOptions;
erichang9dd6aed2017-06-15 15:54:00 -070059 private final ClassName componentName;
erichang43774172017-08-04 10:42:07 -070060 private final UniqueNameSet componentFieldNames;
dpb68c77d82017-08-15 15:23:35 -070061 private final ComponentBindingExpressions componentBindingExpressions;
62 private final GeneratedComponentModel generatedComponentModel;
erichang9dd6aed2017-06-15 15:54:00 -070063 private final ImmutableMap<BindingKey, String> subcomponentNames;
64 private final BindingGraph graph;
ronshapirocb725da2017-07-04 15:14:48 -070065 private final Elements elements;
erichang9dd6aed2017-06-15 15:54:00 -070066
67 Factory(
dpbc8c6c052017-07-28 10:48:06 -070068 CompilerOptions compilerOptions,
erichang9dd6aed2017-06-15 15:54:00 -070069 ClassName componentName,
erichang43774172017-08-04 10:42:07 -070070 UniqueNameSet componentFieldNames,
dpb68c77d82017-08-15 15:23:35 -070071 ComponentBindingExpressions componentBindingExpressions,
72 GeneratedComponentModel generatedComponentModel,
erichang9dd6aed2017-06-15 15:54:00 -070073 ImmutableMap<BindingKey, String> subcomponentNames,
ronshapirocb725da2017-07-04 15:14:48 -070074 BindingGraph graph,
75 Elements elements) {
dpbc8c6c052017-07-28 10:48:06 -070076 this.compilerOptions = checkNotNull(compilerOptions);
erichang9dd6aed2017-06-15 15:54:00 -070077 this.componentName = checkNotNull(componentName);
erichang43774172017-08-04 10:42:07 -070078 this.componentFieldNames = checkNotNull(componentFieldNames);
dpb68c77d82017-08-15 15:23:35 -070079 this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
80 this.generatedComponentModel = checkNotNull(generatedComponentModel);
erichang9dd6aed2017-06-15 15:54:00 -070081 this.subcomponentNames = checkNotNull(subcomponentNames);
82 this.graph = checkNotNull(graph);
ronshapiroe05f9212017-08-08 11:22:11 -070083 this.elements = checkNotNull(elements);
erichang9dd6aed2017-06-15 15:54:00 -070084 }
85
86 /** Creates a binding expression for a field. */
erichang43774172017-08-04 10:42:07 -070087 BindingExpression forField(ResolvedBindings resolvedBindings) {
88 FieldSpec fieldSpec = generateFrameworkField(resolvedBindings, Optional.empty());
erichang9dd6aed2017-06-15 15:54:00 -070089 MemberSelect memberSelect = MemberSelect.localField(componentName, fieldSpec.name);
ronshapiro186d17a2017-08-11 08:18:07 -070090 return create(resolvedBindings, Optional.of(fieldSpec), memberSelect);
erichang43774172017-08-04 10:42:07 -070091 }
92
dpbb5ae2492017-08-18 14:58:23 -070093 FrameworkInstanceBindingExpression forProducerFromProviderField(
94 ResolvedBindings resolvedBindings) {
erichang43774172017-08-04 10:42:07 -070095 FieldSpec fieldSpec = generateFrameworkField(resolvedBindings, Optional.of(PRODUCER));
96 MemberSelect memberSelect = MemberSelect.localField(componentName, fieldSpec.name);
dpbb5ae2492017-08-18 14:58:23 -070097 return producerFromProviderBindingExpression(
ronshapiro186d17a2017-08-11 08:18:07 -070098 resolvedBindings.bindingKey(),
erichang43774172017-08-04 10:42:07 -070099 Optional.of(fieldSpec),
dpb68c77d82017-08-15 15:23:35 -0700100 generatedComponentModel,
dpbb5ae2492017-08-18 14:58:23 -0700101 memberSelect);
erichang9dd6aed2017-06-15 15:54:00 -0700102 }
103
dpb68c77d82017-08-15 15:23:35 -0700104 /** Creates a binding expression for a static method call. */
erichang9dd6aed2017-06-15 15:54:00 -0700105 Optional<BindingExpression> forStaticMethod(ResolvedBindings resolvedBindings) {
ronshapiro186d17a2017-08-11 08:18:07 -0700106 return staticMemberSelect(resolvedBindings)
107 .map(memberSelect -> create(resolvedBindings, Optional.empty(), memberSelect));
erichang43774172017-08-04 10:42:07 -0700108 }
109
110 /**
111 * Adds a field representing the resolved bindings, optionally forcing it to use a particular
112 * binding type (instead of the type the resolved bindings would typically use).
113 */
114 private FieldSpec generateFrameworkField(
115 ResolvedBindings resolvedBindings, Optional<ClassName> frameworkClass) {
116 boolean useRawType = useRawType(resolvedBindings);
117
118 FrameworkField contributionBindingField =
119 FrameworkField.forResolvedBindings(resolvedBindings, frameworkClass);
120 FieldSpec.Builder contributionField =
121 FieldSpec.builder(
122 useRawType
123 ? contributionBindingField.type().rawType
124 : contributionBindingField.type(),
125 componentFieldNames.getUniqueName(contributionBindingField.name()));
126 contributionField.addModifiers(PRIVATE);
127 if (useRawType) {
128 contributionField.addAnnotation(AnnotationSpecs.suppressWarnings(RAWTYPES));
129 }
130
131 return contributionField.build();
132 }
133
134 private boolean useRawType(ResolvedBindings resolvedBindings) {
135 Optional<String> bindingPackage = resolvedBindings.bindingPackage();
136 return bindingPackage.isPresent()
137 && !bindingPackage.get().equals(componentName.packageName());
erichang9dd6aed2017-06-15 15:54:00 -0700138 }
139
ronshapiro186d17a2017-08-11 08:18:07 -0700140 private BindingExpression create(
141 ResolvedBindings resolvedBindings,
142 Optional<FieldSpec> fieldSpec,
143 MemberSelect memberSelect) {
dpbb5ae2492017-08-18 14:58:23 -0700144 FrameworkInstanceBindingExpression bindingExpression =
145 FrameworkInstanceBindingExpression.create(
146 resolvedBindings, fieldSpec, generatedComponentModel, memberSelect);
erichang9dd6aed2017-06-15 15:54:00 -0700147
dpbb5ae2492017-08-18 14:58:23 -0700148 if (!resolvedBindings.bindingType().equals(BindingType.PROVISION)) {
149 return bindingExpression;
150 }
erichang9dd6aed2017-06-15 15:54:00 -0700151
dpbb5ae2492017-08-18 14:58:23 -0700152 ProvisionBinding provisionBinding = (ProvisionBinding) resolvedBindings.contributionBinding();
153 switch (provisionBinding.bindingKind()) {
154 case SUBCOMPONENT_BUILDER:
155 return new SubcomponentBuilderBindingExpression(
156 bindingExpression, subcomponentNames.get(resolvedBindings.bindingKey()));
157 case SYNTHETIC_MULTIBOUND_SET:
158 return new SetBindingExpression(
159 provisionBinding, graph, componentBindingExpressions, bindingExpression, elements);
160 case SYNTHETIC_OPTIONAL_BINDING:
161 return new OptionalBindingExpression(
162 provisionBinding, bindingExpression, componentBindingExpressions);
erichang9dd6aed2017-06-15 15:54:00 -0700163 case INJECTION:
dpbb5ae2492017-08-18 14:58:23 -0700164 case PROVISION:
165 if (!provisionBinding.scope().isPresent()
166 && !provisionBinding.requiresModuleInstance()
167 && provisionBinding.bindingElement().isPresent()) {
168 return new SimpleMethodBindingExpression(
169 compilerOptions,
170 provisionBinding,
171 bindingExpression,
172 componentBindingExpressions,
173 generatedComponentModel);
erichang9dd6aed2017-06-15 15:54:00 -0700174 }
dpbb5ae2492017-08-18 14:58:23 -0700175 // fall through
erichang9dd6aed2017-06-15 15:54:00 -0700176 default:
dpbb5ae2492017-08-18 14:58:23 -0700177 return bindingExpression;
erichang9dd6aed2017-06-15 15:54:00 -0700178 }
179 }
180 }
erichang9dd6aed2017-06-15 15:54:00 -0700181}