| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 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; |
| 18 | |
| dpb | 6486184 | 2017-12-12 08:17:18 -0800 | [diff] [blame] | 19 | import static com.google.common.base.Preconditions.checkArgument; |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 20 | import static com.google.common.base.Preconditions.checkNotNull; |
| cgdecker | ea48dfd | 2018-10-02 10:37:46 -0700 | [diff] [blame] | 21 | import static com.google.common.base.Verify.verify; |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 22 | import static dagger.internal.codegen.Accessibility.isRawTypeAccessible; |
| 23 | import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom; |
| dpb | 3379b95 | 2018-09-24 13:39:04 -0700 | [diff] [blame] | 24 | import static dagger.internal.codegen.BindingRequest.bindingRequest; |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 25 | import static dagger.internal.codegen.BindingType.MEMBERS_INJECTION; |
| 26 | import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock; |
| dpb | 09fb2cb | 2018-01-29 08:39:33 -0800 | [diff] [blame] | 27 | import static dagger.internal.codegen.DelegateBindingExpression.isBindsScopeStrongerThanDependencyScope; |
| dpb | 356a684 | 2018-02-07 07:45:50 -0800 | [diff] [blame] | 28 | import static dagger.internal.codegen.MemberSelect.staticFactoryCreation; |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 29 | import static dagger.internal.codegen.TypeNames.DOUBLE_CHECK; |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 30 | import static dagger.internal.codegen.TypeNames.SINGLE_CHECK; |
| dpb | 09fb2cb | 2018-01-29 08:39:33 -0800 | [diff] [blame] | 31 | import static dagger.model.BindingKind.DELEGATE; |
| bcorso | af9e004 | 2018-04-16 14:12:23 -0700 | [diff] [blame] | 32 | import static dagger.model.BindingKind.MULTIBOUND_MAP; |
| 33 | import static dagger.model.BindingKind.MULTIBOUND_SET; |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 34 | |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 35 | import com.google.auto.common.MoreTypes; |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 36 | import com.google.common.collect.ImmutableList; |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 37 | import com.squareup.javapoet.ClassName; |
| bcorso | e643cc6 | 2017-10-24 08:57:09 -0700 | [diff] [blame] | 38 | import com.squareup.javapoet.CodeBlock; |
| dpb | 02db213 | 2018-01-08 07:20:23 -0800 | [diff] [blame] | 39 | import com.squareup.javapoet.MethodSpec; |
| bcorso | 2c27966 | 2017-12-01 09:51:18 -0800 | [diff] [blame] | 40 | import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor; |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 41 | import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression; |
| dstrasburg | 9203183 | 2018-10-17 08:48:40 -0700 | [diff] [blame] | 42 | import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod; |
| ronshapiro | a5023ca | 2018-01-02 12:55:01 -0800 | [diff] [blame] | 43 | import dagger.model.DependencyRequest; |
| ronshapiro | 120abc6 | 2017-12-15 09:57:09 -0800 | [diff] [blame] | 44 | import dagger.model.RequestKind; |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 45 | import java.util.HashMap; |
| 46 | import java.util.Map; |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 47 | import java.util.Optional; |
| dpb | 356a684 | 2018-02-07 07:45:50 -0800 | [diff] [blame] | 48 | import javax.inject.Provider; |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 49 | import javax.lang.model.type.TypeMirror; |
| 50 | |
| ronshapiro | dc07ed5 | 2017-08-23 08:52:10 -0700 | [diff] [blame] | 51 | /** A central repository of code expressions used to access any binding available to a component. */ |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 52 | final class ComponentBindingExpressions { |
| 53 | |
| ronshapiro | dc07ed5 | 2017-08-23 08:52:10 -0700 | [diff] [blame] | 54 | // TODO(dpb,ronshapiro): refactor this and ComponentRequirementFields into a |
| 55 | // HierarchicalComponentMap<K, V>, or perhaps this use a flattened ImmutableMap, built from its |
| 56 | // parents? If so, maybe make BindingExpression.Factory create it. |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 57 | |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 58 | private final Optional<ComponentBindingExpressions> parent; |
| 59 | private final BindingGraph graph; |
| dpb | 02db213 | 2018-01-08 07:20:23 -0800 | [diff] [blame] | 60 | private final GeneratedComponentModel generatedComponentModel; |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 61 | private final ComponentRequirementFields componentRequirementFields; |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 62 | private final OptionalFactories optionalFactories; |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 63 | private final DaggerTypes types; |
| dpb | e7b8958 | 2018-02-19 08:42:19 -0800 | [diff] [blame] | 64 | private final DaggerElements elements; |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 65 | private final CompilerOptions compilerOptions; |
| 66 | private final MembersInjectionMethods membersInjectionMethods; |
| bcorso | cc739fe | 2018-04-23 09:16:12 -0700 | [diff] [blame] | 67 | private final InnerSwitchingProviders innerSwitchingProviders; |
| 68 | private final StaticSwitchingProviders staticSwitchingProviders; |
| dstrasburg | f0f6dfb | 2018-09-27 12:00:42 -0700 | [diff] [blame] | 69 | private final ModifiableBindingExpressions modifiableBindingExpressions; |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 70 | private final Map<BindingRequest, BindingExpression> expressions = new HashMap<>(); |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 71 | |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 72 | ComponentBindingExpressions( |
| 73 | BindingGraph graph, |
| 74 | GeneratedComponentModel generatedComponentModel, |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 75 | ComponentRequirementFields componentRequirementFields, |
| 76 | OptionalFactories optionalFactories, |
| 77 | DaggerTypes types, |
| dpb | e7b8958 | 2018-02-19 08:42:19 -0800 | [diff] [blame] | 78 | DaggerElements elements, |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 79 | CompilerOptions compilerOptions) { |
| 80 | this( |
| 81 | Optional.empty(), |
| 82 | graph, |
| 83 | generatedComponentModel, |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 84 | componentRequirementFields, |
| bcorso | cc739fe | 2018-04-23 09:16:12 -0700 | [diff] [blame] | 85 | new StaticSwitchingProviders(generatedComponentModel, types), |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 86 | optionalFactories, |
| 87 | types, |
| 88 | elements, |
| 89 | compilerOptions); |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 90 | } |
| 91 | |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 92 | private ComponentBindingExpressions( |
| 93 | Optional<ComponentBindingExpressions> parent, |
| 94 | BindingGraph graph, |
| 95 | GeneratedComponentModel generatedComponentModel, |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 96 | ComponentRequirementFields componentRequirementFields, |
| bcorso | cc739fe | 2018-04-23 09:16:12 -0700 | [diff] [blame] | 97 | StaticSwitchingProviders staticSwitchingProviders, |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 98 | OptionalFactories optionalFactories, |
| 99 | DaggerTypes types, |
| dpb | e7b8958 | 2018-02-19 08:42:19 -0800 | [diff] [blame] | 100 | DaggerElements elements, |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 101 | CompilerOptions compilerOptions) { |
| 102 | this.parent = parent; |
| 103 | this.graph = graph; |
| dpb | 02db213 | 2018-01-08 07:20:23 -0800 | [diff] [blame] | 104 | this.generatedComponentModel = generatedComponentModel; |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 105 | this.componentRequirementFields = checkNotNull(componentRequirementFields); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 106 | this.optionalFactories = checkNotNull(optionalFactories); |
| 107 | this.types = checkNotNull(types); |
| 108 | this.elements = checkNotNull(elements); |
| 109 | this.compilerOptions = checkNotNull(compilerOptions); |
| 110 | this.membersInjectionMethods = |
| 111 | new MembersInjectionMethods(generatedComponentModel, this, graph, elements, types); |
| bcorso | cc739fe | 2018-04-23 09:16:12 -0700 | [diff] [blame] | 112 | this.innerSwitchingProviders = |
| 113 | new InnerSwitchingProviders(generatedComponentModel, this, types); |
| 114 | this.staticSwitchingProviders = staticSwitchingProviders; |
| dstrasburg | f0f6dfb | 2018-09-27 12:00:42 -0700 | [diff] [blame] | 115 | this.modifiableBindingExpressions = |
| 116 | new ModifiableBindingExpressions( |
| 117 | parent.map(cbe -> cbe.modifiableBindingExpressions), |
| 118 | this, |
| 119 | graph, |
| 120 | generatedComponentModel, |
| 121 | compilerOptions); |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 122 | } |
| 123 | |
| 124 | /** |
| 125 | * Returns a new object representing the bindings available from a child component of this one. |
| 126 | */ |
| 127 | ComponentBindingExpressions forChildComponent( |
| 128 | BindingGraph childGraph, |
| 129 | GeneratedComponentModel childComponentModel, |
| 130 | ComponentRequirementFields childComponentRequirementFields) { |
| 131 | return new ComponentBindingExpressions( |
| 132 | Optional.of(this), |
| 133 | childGraph, |
| 134 | childComponentModel, |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 135 | childComponentRequirementFields, |
| bcorso | cc739fe | 2018-04-23 09:16:12 -0700 | [diff] [blame] | 136 | staticSwitchingProviders, |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 137 | optionalFactories, |
| 138 | types, |
| 139 | elements, |
| 140 | compilerOptions); |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 141 | } |
| 142 | |
| dstrasburg | f0f6dfb | 2018-09-27 12:00:42 -0700 | [diff] [blame] | 143 | /* Returns the {@link ModifiableBindingExpressions} for this component. */ |
| 144 | ModifiableBindingExpressions modifiableBindingExpressions() { |
| 145 | return modifiableBindingExpressions; |
| 146 | } |
| 147 | |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 148 | /** |
| dpb | 3379b95 | 2018-09-24 13:39:04 -0700 | [diff] [blame] | 149 | * Returns an expression that evaluates to the value of a binding request for a binding owned by |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 150 | * this component or an ancestor. |
| 151 | * |
| 152 | * @param requestingClass the class that will contain the expression |
| dpb | 3379b95 | 2018-09-24 13:39:04 -0700 | [diff] [blame] | 153 | * @throws IllegalStateException if there is no binding expression that satisfies the request |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 154 | */ |
| dpb | 3379b95 | 2018-09-24 13:39:04 -0700 | [diff] [blame] | 155 | Expression getDependencyExpression(BindingRequest request, ClassName requestingClass) { |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 156 | return getBindingExpression(request).getDependencyExpression(requestingClass); |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 157 | } |
| 158 | |
| 159 | /** |
| cgdecker | ea48dfd | 2018-10-02 10:37:46 -0700 | [diff] [blame] | 160 | * Equivalent to {@link #getDependencyExpression(BindingRequest, ClassName)} that is used only |
| 161 | * when the request is for implementation of a component method. |
| 162 | * |
| 163 | * @throws IllegalStateException if there is no binding expression that satisfies the request |
| 164 | */ |
| 165 | Expression getDependencyExpressionForComponentMethod( |
| 166 | BindingRequest request, |
| 167 | ComponentMethodDescriptor componentMethod, |
| 168 | GeneratedComponentModel componentModel) { |
| 169 | return getBindingExpression(request) |
| 170 | .getDependencyExpressionForComponentMethod(componentMethod, componentModel); |
| 171 | } |
| 172 | |
| 173 | /** |
| 174 | * Returns the {@link CodeBlock} for the method arguments used with the factory {@code create()} |
| bcorso | 5db065d | 2018-04-03 13:49:31 -0700 | [diff] [blame] | 175 | * method for the given {@link ContributionBinding binding}. |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 176 | */ |
| bcorso | 5db065d | 2018-04-03 13:49:31 -0700 | [diff] [blame] | 177 | CodeBlock getCreateMethodArgumentsCodeBlock(ContributionBinding binding) { |
| 178 | return makeParametersCodeBlock(getCreateMethodArgumentsCodeBlocks(binding)); |
| 179 | } |
| 180 | |
| 181 | private ImmutableList<CodeBlock> getCreateMethodArgumentsCodeBlocks(ContributionBinding binding) { |
| 182 | ImmutableList.Builder<CodeBlock> arguments = ImmutableList.builder(); |
| 183 | |
| 184 | if (binding.requiresModuleInstance()) { |
| 185 | arguments.add( |
| 186 | componentRequirementFields.getExpressionDuringInitialization( |
| 187 | ComponentRequirement.forModule(binding.contributingModule().get().asType()), |
| 188 | generatedComponentModel.name())); |
| 189 | } |
| 190 | |
| dpb | 3379b95 | 2018-09-24 13:39:04 -0700 | [diff] [blame] | 191 | binding.frameworkDependencies().stream() |
| 192 | .map(BindingRequest::bindingRequest) |
| 193 | .map( |
| 194 | request -> |
| 195 | getDependencyExpression(request, generatedComponentModel.name())) |
| bcorso | 5db065d | 2018-04-03 13:49:31 -0700 | [diff] [blame] | 196 | .map(Expression::codeBlock) |
| 197 | .forEach(arguments::add); |
| 198 | |
| 199 | return arguments.build(); |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 200 | } |
| 201 | |
| 202 | /** |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 203 | * Returns an expression that evaluates to the value of a dependency request, for passing to a |
| 204 | * binding method, an {@code @Inject}-annotated constructor or member, or a proxy for one. |
| 205 | * |
| 206 | * <p>If the method is a generated static {@link InjectionMethods injection method}, each |
| 207 | * parameter will be {@link Object} if the dependency's raw type is inaccessible. If that is the |
| 208 | * case for this dependency, the returned expression will use a cast to evaluate to the raw type. |
| 209 | * |
| 210 | * @param requestingClass the class that will contain the expression |
| 211 | */ |
| ronshapiro | ba79486 | 2017-09-28 11:39:34 -0700 | [diff] [blame] | 212 | Expression getDependencyArgumentExpression( |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 213 | DependencyRequest dependencyRequest, ClassName requestingClass) { |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 214 | |
| 215 | TypeMirror dependencyType = dependencyRequest.key().type(); |
| dpb | 3379b95 | 2018-09-24 13:39:04 -0700 | [diff] [blame] | 216 | Expression dependencyExpression = |
| 217 | getDependencyExpression(bindingRequest(dependencyRequest), requestingClass); |
| ronshapiro | ba79486 | 2017-09-28 11:39:34 -0700 | [diff] [blame] | 218 | |
| bcorso | aaffd2d | 2018-04-16 14:44:42 -0700 | [diff] [blame] | 219 | if (dependencyRequest.kind().equals(RequestKind.INSTANCE) |
| 220 | && !isTypeAccessibleFrom(dependencyType, requestingClass.packageName()) |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 221 | && isRawTypeAccessible(dependencyType, requestingClass.packageName())) { |
| ronshapiro | ba79486 | 2017-09-28 11:39:34 -0700 | [diff] [blame] | 222 | return dependencyExpression.castTo(types.erasure(dependencyType)); |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 223 | } |
| 224 | |
| ronshapiro | ba79486 | 2017-09-28 11:39:34 -0700 | [diff] [blame] | 225 | return dependencyExpression; |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 226 | } |
| 227 | |
| dstrasburg | f0f6dfb | 2018-09-27 12:00:42 -0700 | [diff] [blame] | 228 | /** Returns the implementation of a component method. */ |
| 229 | MethodSpec getComponentMethod(ComponentMethodDescriptor componentMethod) { |
| dpb | 02db213 | 2018-01-08 07:20:23 -0800 | [diff] [blame] | 230 | checkArgument(componentMethod.dependencyRequest().isPresent()); |
| dpb | 3379b95 | 2018-09-24 13:39:04 -0700 | [diff] [blame] | 231 | BindingRequest request = bindingRequest(componentMethod.dependencyRequest().get()); |
| dstrasburg | f0f6dfb | 2018-09-27 12:00:42 -0700 | [diff] [blame] | 232 | return MethodSpec.overriding( |
| 233 | componentMethod.methodElement(), |
| 234 | MoreTypes.asDeclared(graph.componentType().asType()), |
| 235 | types) |
| 236 | .addCode( |
| 237 | getBindingExpression(request) |
| 238 | .getComponentMethodImplementation(componentMethod, generatedComponentModel)) |
| 239 | .build(); |
| bcorso | 11f9b87 | 2017-10-09 16:18:55 -0700 | [diff] [blame] | 240 | } |
| 241 | |
| dstrasburg | f0f6dfb | 2018-09-27 12:00:42 -0700 | [diff] [blame] | 242 | /** Returns the {@link BindingExpression} for the given {@link BindingRequest}. */ |
| 243 | BindingExpression getBindingExpression(BindingRequest request) { |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 244 | if (expressions.containsKey(request)) { |
| 245 | return expressions.get(request); |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 246 | } |
| dstrasburg | f0f6dfb | 2018-09-27 12:00:42 -0700 | [diff] [blame] | 247 | Optional<BindingExpression> expression = |
| 248 | modifiableBindingExpressions.maybeCreateModifiableBindingExpression(request); |
| 249 | if (!expression.isPresent()) { |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 250 | ResolvedBindings resolvedBindings = graph.resolvedBindings(request); |
| dstrasburg | f0f6dfb | 2018-09-27 12:00:42 -0700 | [diff] [blame] | 251 | if (resolvedBindings != null && !resolvedBindings.ownedBindings().isEmpty()) { |
| 252 | expression = Optional.of(createBindingExpression(resolvedBindings, request)); |
| 253 | } |
| dstrasburg | 4f902cf | 2018-07-30 08:42:57 -0700 | [diff] [blame] | 254 | } |
| 255 | if (expression.isPresent()) { |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 256 | expressions.put(request, expression.get()); |
| dstrasburg | 4f902cf | 2018-07-30 08:42:57 -0700 | [diff] [blame] | 257 | return expression.get(); |
| 258 | } |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 259 | checkArgument(parent.isPresent(), "no expression found for %s", request); |
| 260 | return parent.get().getBindingExpression(request); |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 261 | } |
| 262 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 263 | /** Creates a binding expression. */ |
| dstrasburg | f0f6dfb | 2018-09-27 12:00:42 -0700 | [diff] [blame] | 264 | BindingExpression createBindingExpression( |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 265 | ResolvedBindings resolvedBindings, BindingRequest request) { |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 266 | switch (resolvedBindings.bindingType()) { |
| 267 | case MEMBERS_INJECTION: |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 268 | checkArgument(request.isRequestKind(RequestKind.MEMBERS_INJECTION)); |
| ronshapiro | 9288a97 | 2018-02-14 06:02:12 -0800 | [diff] [blame] | 269 | return new MembersInjectionBindingExpression(resolvedBindings, membersInjectionMethods); |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 270 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 271 | case PROVISION: |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 272 | return provisionBindingExpression(resolvedBindings, request); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 273 | |
| 274 | case PRODUCTION: |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 275 | return productionBindingExpression(resolvedBindings, request); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 276 | |
| 277 | default: |
| 278 | throw new AssertionError(resolvedBindings); |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 279 | } |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 280 | } |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 281 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 282 | /** |
| 283 | * Returns a binding expression that uses a {@link javax.inject.Provider} for provision bindings |
| 284 | * or a {@link dagger.producers.Producer} for production bindings. |
| 285 | */ |
| 286 | private FrameworkInstanceBindingExpression frameworkInstanceBindingExpression( |
| dpb | 5e03bd5 | 2018-08-10 14:21:15 -0700 | [diff] [blame] | 287 | ResolvedBindings resolvedBindings) { |
| bcorso | af9e004 | 2018-04-16 14:12:23 -0700 | [diff] [blame] | 288 | // TODO(user): Consider merging the static factory creation logic into CreationExpressions? |
| 289 | Optional<MemberSelect> staticMethod = |
| 290 | useStaticFactoryCreation(resolvedBindings.contributionBinding()) |
| 291 | ? staticFactoryCreation(resolvedBindings) |
| 292 | : Optional.empty(); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 293 | FrameworkInstanceCreationExpression frameworkInstanceCreationExpression = |
| 294 | resolvedBindings.scope().isPresent() |
| 295 | ? scope(resolvedBindings, frameworkInstanceCreationExpression(resolvedBindings)) |
| 296 | : frameworkInstanceCreationExpression(resolvedBindings); |
| cgdecker | 0bc05be | 2018-08-10 12:37:36 -0700 | [diff] [blame] | 297 | FrameworkInstanceSupplier frameworkInstanceSupplier = |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 298 | staticMethod.isPresent() |
| 299 | ? staticMethod::get |
| 300 | : new FrameworkFieldInitializer( |
| cgdecker | 0bc05be | 2018-08-10 12:37:36 -0700 | [diff] [blame] | 301 | generatedComponentModel, resolvedBindings, frameworkInstanceCreationExpression); |
| 302 | |
| dpb | db19750 | 2018-08-27 14:29:47 -0700 | [diff] [blame] | 303 | switch (resolvedBindings.bindingType()) { |
| 304 | case PROVISION: |
| cgdecker | 0bc05be | 2018-08-10 12:37:36 -0700 | [diff] [blame] | 305 | return new ProviderInstanceBindingExpression( |
| dpb | 5e03bd5 | 2018-08-10 14:21:15 -0700 | [diff] [blame] | 306 | resolvedBindings, frameworkInstanceSupplier, types, elements); |
| dpb | db19750 | 2018-08-27 14:29:47 -0700 | [diff] [blame] | 307 | case PRODUCTION: |
| cgdecker | ea48dfd | 2018-10-02 10:37:46 -0700 | [diff] [blame] | 308 | return new ProducerNodeInstanceBindingExpression( |
| 309 | resolvedBindings, frameworkInstanceSupplier, types, elements, generatedComponentModel); |
| cgdecker | 0bc05be | 2018-08-10 12:37:36 -0700 | [diff] [blame] | 310 | default: |
| dpb | db19750 | 2018-08-27 14:29:47 -0700 | [diff] [blame] | 311 | throw new AssertionError("invalid binding type: " + resolvedBindings.bindingType()); |
| cgdecker | 0bc05be | 2018-08-10 12:37:36 -0700 | [diff] [blame] | 312 | } |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 313 | } |
| dpb | 6486184 | 2017-12-12 08:17:18 -0800 | [diff] [blame] | 314 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 315 | private FrameworkInstanceCreationExpression scope( |
| 316 | ResolvedBindings resolvedBindings, FrameworkInstanceCreationExpression unscoped) { |
| ronshapiro | a72c342 | 2018-10-30 15:14:05 -0700 | [diff] [blame] | 317 | return () -> |
| 318 | CodeBlock.of( |
| 319 | "$T.provider($L)", |
| 320 | resolvedBindings.scope().get().isReusable() ? SINGLE_CHECK : DOUBLE_CHECK, |
| 321 | unscoped.creationExpression()); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 322 | } |
| dpb | 6486184 | 2017-12-12 08:17:18 -0800 | [diff] [blame] | 323 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 324 | /** |
| 325 | * Returns a creation expression for a {@link javax.inject.Provider} for provision bindings or a |
| 326 | * {@link dagger.producers.Producer} for production bindings. |
| 327 | */ |
| 328 | private FrameworkInstanceCreationExpression frameworkInstanceCreationExpression( |
| 329 | ResolvedBindings resolvedBindings) { |
| 330 | checkArgument(!resolvedBindings.bindingType().equals(MEMBERS_INJECTION)); |
| 331 | ContributionBinding binding = resolvedBindings.contributionBinding(); |
| 332 | switch (binding.kind()) { |
| 333 | case COMPONENT: |
| 334 | // The cast can be removed when we drop java 7 source support |
| 335 | return new InstanceFactoryCreationExpression( |
| 336 | () -> CodeBlock.of("($T) this", binding.key().type())); |
| dpb | 6486184 | 2017-12-12 08:17:18 -0800 | [diff] [blame] | 337 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 338 | case BOUND_INSTANCE: |
| 339 | return instanceFactoryCreationExpression( |
| 340 | binding, ComponentRequirement.forBoundInstance(binding)); |
| bcorso | f0a99fe | 2017-12-04 10:52:05 -0800 | [diff] [blame] | 341 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 342 | case COMPONENT_DEPENDENCY: |
| 343 | return instanceFactoryCreationExpression( |
| 344 | binding, ComponentRequirement.forDependency(binding.key().type())); |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 345 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 346 | case COMPONENT_PROVISION: |
| 347 | return new DependencyMethodProviderCreationExpression( |
| 348 | binding, generatedComponentModel, componentRequirementFields, compilerOptions, graph); |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 349 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 350 | case SUBCOMPONENT_BUILDER: |
| 351 | return new SubcomponentBuilderProviderCreationExpression( |
| dstrasburg | 61274ab | 2018-09-26 08:11:04 -0700 | [diff] [blame] | 352 | binding.key().type(), generatedComponentModel.getSubcomponentName(binding.key())); |
| dpb | 356a684 | 2018-02-07 07:45:50 -0800 | [diff] [blame] | 353 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 354 | case INJECTION: |
| 355 | case PROVISION: |
| bcorso | cc739fe | 2018-04-23 09:16:12 -0700 | [diff] [blame] | 356 | return compilerOptions.experimentalAndroidMode2() |
| 357 | ? staticSwitchingProviders.newCreationExpression(binding, this) |
| 358 | : new InjectionOrProvisionProviderCreationExpression(binding, this); |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 359 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 360 | case COMPONENT_PRODUCTION: |
| 361 | return new DependencyMethodProducerCreationExpression( |
| 362 | binding, generatedComponentModel, componentRequirementFields, graph); |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 363 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 364 | case PRODUCTION: |
| bcorso | 5db065d | 2018-04-03 13:49:31 -0700 | [diff] [blame] | 365 | return new ProducerCreationExpression(binding, this); |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 366 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 367 | case MULTIBOUND_SET: |
| 368 | return new SetFactoryCreationExpression(binding, generatedComponentModel, this, graph); |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 369 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 370 | case MULTIBOUND_MAP: |
| ronshapiro | 3a08964 | 2018-07-17 15:39:40 -0700 | [diff] [blame] | 371 | return new MapFactoryCreationExpression( |
| 372 | binding, generatedComponentModel, this, graph, elements); |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 373 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 374 | case DELEGATE: |
| 375 | return new DelegatingFrameworkInstanceCreationExpression( |
| 376 | binding, generatedComponentModel, this); |
| dpb | 3db68f0 | 2018-01-04 09:15:52 -0800 | [diff] [blame] | 377 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 378 | case OPTIONAL: |
| ronshapiro | e674076 | 2018-05-01 08:37:26 -0700 | [diff] [blame] | 379 | return new OptionalFactoryInstanceCreationExpression( |
| 380 | optionalFactories, binding, generatedComponentModel, this); |
| dpb | 356a684 | 2018-02-07 07:45:50 -0800 | [diff] [blame] | 381 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 382 | case MEMBERS_INJECTOR: |
| ronshapiro | e674076 | 2018-05-01 08:37:26 -0700 | [diff] [blame] | 383 | return new MembersInjectorProviderCreationExpression((ProvisionBinding) binding, this); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 384 | |
| 385 | default: |
| 386 | throw new AssertionError(binding); |
| 387 | } |
| 388 | } |
| 389 | |
| 390 | private InstanceFactoryCreationExpression instanceFactoryCreationExpression( |
| 391 | ContributionBinding binding, ComponentRequirement componentRequirement) { |
| 392 | return new InstanceFactoryCreationExpression( |
| 393 | binding.nullableType().isPresent(), |
| 394 | () -> |
| 395 | componentRequirementFields.getExpressionDuringInitialization( |
| 396 | componentRequirement, generatedComponentModel.name())); |
| 397 | } |
| 398 | |
| 399 | /** Returns a binding expression for a provision binding. */ |
| 400 | private BindingExpression provisionBindingExpression( |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 401 | ResolvedBindings resolvedBindings, BindingRequest request) { |
| cgdecker | ea48dfd | 2018-10-02 10:37:46 -0700 | [diff] [blame] | 402 | if (!request.requestKind().isPresent()) { |
| 403 | verify( |
| 404 | request.frameworkType().get().equals(FrameworkType.PRODUCER_NODE), |
| 405 | "expected a PRODUCER_NODE: %s", |
| 406 | request); |
| 407 | return producerFromProviderBindingExpression(resolvedBindings); |
| 408 | } |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 409 | RequestKind requestKind = request.requestKind().get(); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 410 | switch (requestKind) { |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 411 | case INSTANCE: |
| 412 | return instanceBindingExpression(resolvedBindings); |
| 413 | |
| ronshapiro | 62c8d5c | 2018-05-10 09:06:48 -0700 | [diff] [blame] | 414 | case PROVIDER: |
| 415 | return providerBindingExpression(resolvedBindings); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 416 | |
| 417 | case LAZY: |
| 418 | case PRODUCED: |
| 419 | case PROVIDER_OF_LAZY: |
| dpb | 5e03bd5 | 2018-08-10 14:21:15 -0700 | [diff] [blame] | 420 | return new DerivedFromFrameworkInstanceBindingExpression( |
| dpb | db19750 | 2018-08-27 14:29:47 -0700 | [diff] [blame] | 421 | resolvedBindings, FrameworkType.PROVIDER, requestKind, this, types); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 422 | |
| ronshapiro | 62c8d5c | 2018-05-10 09:06:48 -0700 | [diff] [blame] | 423 | case PRODUCER: |
| dpb | 5e03bd5 | 2018-08-10 14:21:15 -0700 | [diff] [blame] | 424 | return producerFromProviderBindingExpression(resolvedBindings); |
| ronshapiro | 62c8d5c | 2018-05-10 09:06:48 -0700 | [diff] [blame] | 425 | |
| 426 | case FUTURE: |
| 427 | return new ImmediateFutureBindingExpression(resolvedBindings, this, types); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 428 | |
| 429 | case MEMBERS_INJECTION: |
| 430 | throw new IllegalArgumentException(); |
| dpb | 356a684 | 2018-02-07 07:45:50 -0800 | [diff] [blame] | 431 | } |
| 432 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 433 | throw new AssertionError(); |
| 434 | } |
| dpb | 356a684 | 2018-02-07 07:45:50 -0800 | [diff] [blame] | 435 | |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 436 | /** Returns a binding expression for a production binding. */ |
| 437 | private BindingExpression productionBindingExpression( |
| 438 | ResolvedBindings resolvedBindings, BindingRequest request) { |
| 439 | if (request.frameworkType().isPresent()) { |
| 440 | return frameworkInstanceBindingExpression(resolvedBindings); |
| 441 | } else { |
| 442 | // If no FrameworkType is present, a RequestKind is guaranteed to be present. |
| 443 | return new DerivedFromFrameworkInstanceBindingExpression( |
| cgdecker | ea48dfd | 2018-10-02 10:37:46 -0700 | [diff] [blame] | 444 | resolvedBindings, FrameworkType.PRODUCER_NODE, request.requestKind().get(), this, types); |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 445 | } |
| 446 | } |
| 447 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 448 | /** |
| ronshapiro | 62c8d5c | 2018-05-10 09:06:48 -0700 | [diff] [blame] | 449 | * Returns a binding expression for {@link RequestKind#PROVIDER} requests. |
| 450 | * |
| 451 | * <p>{@code @Binds} bindings that don't {@linkplain #needsCaching(ResolvedBindings) need to be |
| 452 | * cached} can use a {@link DelegateBindingExpression}. |
| 453 | * |
| bcorso | d55c02d | 2018-06-06 15:02:34 -0700 | [diff] [blame] | 454 | * <p>In fastInit mode, use an {@link InnerSwitchingProviders inner switching provider} unless |
| 455 | * that provider's case statement will simply call {@code get()} on another {@link Provider} (in |
| 456 | * which case, just use that Provider directly). |
| ronshapiro | 62c8d5c | 2018-05-10 09:06:48 -0700 | [diff] [blame] | 457 | * |
| 458 | * <p>Otherwise, return a {@link FrameworkInstanceBindingExpression}. |
| 459 | */ |
| 460 | private BindingExpression providerBindingExpression(ResolvedBindings resolvedBindings) { |
| 461 | if (resolvedBindings.contributionBinding().kind().equals(DELEGATE) |
| 462 | && !needsCaching(resolvedBindings)) { |
| 463 | return new DelegateBindingExpression( |
| 464 | resolvedBindings, RequestKind.PROVIDER, this, types, elements); |
| bcorso | d55c02d | 2018-06-06 15:02:34 -0700 | [diff] [blame] | 465 | } else if (compilerOptions.fastInit() |
| ronshapiro | 62c8d5c | 2018-05-10 09:06:48 -0700 | [diff] [blame] | 466 | && frameworkInstanceCreationExpression(resolvedBindings).useInnerSwitchingProvider() |
| 467 | && !(instanceBindingExpression(resolvedBindings) |
| dpb | 5e03bd5 | 2018-08-10 14:21:15 -0700 | [diff] [blame] | 468 | instanceof DerivedFromFrameworkInstanceBindingExpression)) { |
| ronshapiro | 62c8d5c | 2018-05-10 09:06:48 -0700 | [diff] [blame] | 469 | return wrapInMethod( |
| 470 | resolvedBindings, |
| dpb | 3379b95 | 2018-09-24 13:39:04 -0700 | [diff] [blame] | 471 | bindingRequest(resolvedBindings.key(), RequestKind.PROVIDER), |
| ronshapiro | 62c8d5c | 2018-05-10 09:06:48 -0700 | [diff] [blame] | 472 | innerSwitchingProviders.newBindingExpression(resolvedBindings.contributionBinding())); |
| 473 | } |
| dpb | 5e03bd5 | 2018-08-10 14:21:15 -0700 | [diff] [blame] | 474 | return frameworkInstanceBindingExpression(resolvedBindings); |
| ronshapiro | 62c8d5c | 2018-05-10 09:06:48 -0700 | [diff] [blame] | 475 | } |
| 476 | |
| 477 | /** |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 478 | * Returns a binding expression that uses a {@link dagger.producers.Producer} field for a |
| 479 | * provision binding. |
| 480 | */ |
| 481 | private FrameworkInstanceBindingExpression producerFromProviderBindingExpression( |
| dpb | 5e03bd5 | 2018-08-10 14:21:15 -0700 | [diff] [blame] | 482 | ResolvedBindings resolvedBindings) { |
| dpb | db19750 | 2018-08-27 14:29:47 -0700 | [diff] [blame] | 483 | checkArgument(resolvedBindings.bindingType().equals(BindingType.PROVISION)); |
| cgdecker | ea48dfd | 2018-10-02 10:37:46 -0700 | [diff] [blame] | 484 | return new ProducerNodeInstanceBindingExpression( |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 485 | resolvedBindings, |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 486 | new FrameworkFieldInitializer( |
| 487 | generatedComponentModel, |
| 488 | resolvedBindings, |
| 489 | new ProducerFromProviderCreationExpression( |
| 490 | resolvedBindings.contributionBinding(), generatedComponentModel, this)), |
| 491 | types, |
| cgdecker | ea48dfd | 2018-10-02 10:37:46 -0700 | [diff] [blame] | 492 | elements, |
| 493 | generatedComponentModel); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 494 | } |
| dpb | 356a684 | 2018-02-07 07:45:50 -0800 | [diff] [blame] | 495 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 496 | /** |
| 497 | * Returns a binding expression for {@link RequestKind#INSTANCE} requests. |
| 498 | * |
| 499 | * <p>If there is a direct expression (not calling {@link Provider#get()}) we can use for an |
| 500 | * instance of this binding, return it, wrapped in a method if the binding {@linkplain |
| 501 | * #needsCaching(ResolvedBindings) needs to be cached} or the expression has dependencies. |
| 502 | * |
| bcorso | d55c02d | 2018-06-06 15:02:34 -0700 | [diff] [blame] | 503 | * <p>In fastInit mode, we can use direct expressions unless the binding needs to be cached. |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 504 | */ |
| 505 | private BindingExpression instanceBindingExpression(ResolvedBindings resolvedBindings) { |
| 506 | Optional<BindingExpression> maybeDirectInstanceExpression = |
| 507 | unscopedDirectInstanceExpression(resolvedBindings); |
| 508 | if (canUseDirectInstanceExpression(resolvedBindings) |
| 509 | && maybeDirectInstanceExpression.isPresent()) { |
| 510 | BindingExpression directInstanceExpression = maybeDirectInstanceExpression.get(); |
| 511 | return directInstanceExpression.requiresMethodEncapsulation() |
| 512 | || needsCaching(resolvedBindings) |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 513 | ? wrapInMethod( |
| 514 | resolvedBindings, |
| dpb | 3379b95 | 2018-09-24 13:39:04 -0700 | [diff] [blame] | 515 | bindingRequest(resolvedBindings.key(), RequestKind.INSTANCE), |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 516 | directInstanceExpression) |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 517 | : directInstanceExpression; |
| dpb | 356a684 | 2018-02-07 07:45:50 -0800 | [diff] [blame] | 518 | } |
| dpb | 5e03bd5 | 2018-08-10 14:21:15 -0700 | [diff] [blame] | 519 | return new DerivedFromFrameworkInstanceBindingExpression( |
| dpb | db19750 | 2018-08-27 14:29:47 -0700 | [diff] [blame] | 520 | resolvedBindings, FrameworkType.PROVIDER, RequestKind.INSTANCE, this, types); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 521 | } |
| dpb | 356a684 | 2018-02-07 07:45:50 -0800 | [diff] [blame] | 522 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 523 | /** |
| 524 | * Returns an unscoped binding expression for an {@link RequestKind#INSTANCE} that does not call |
| 525 | * {@code get()} on its provider, if there is one. |
| 526 | */ |
| 527 | private Optional<BindingExpression> unscopedDirectInstanceExpression( |
| 528 | ResolvedBindings resolvedBindings) { |
| 529 | switch (resolvedBindings.contributionBinding().kind()) { |
| 530 | case DELEGATE: |
| 531 | return Optional.of( |
| 532 | new DelegateBindingExpression( |
| 533 | resolvedBindings, RequestKind.INSTANCE, this, types, elements)); |
| 534 | |
| 535 | case COMPONENT: |
| 536 | return Optional.of( |
| 537 | new ComponentInstanceBindingExpression( |
| 538 | resolvedBindings, generatedComponentModel.name())); |
| 539 | |
| 540 | case COMPONENT_DEPENDENCY: |
| 541 | return Optional.of( |
| 542 | new ComponentRequirementBindingExpression( |
| 543 | resolvedBindings, |
| 544 | ComponentRequirement.forDependency(resolvedBindings.key().type()), |
| 545 | componentRequirementFields)); |
| 546 | |
| 547 | case COMPONENT_PROVISION: |
| 548 | return Optional.of( |
| 549 | new ComponentProvisionBindingExpression( |
| 550 | resolvedBindings, graph, componentRequirementFields, compilerOptions)); |
| 551 | |
| 552 | case SUBCOMPONENT_BUILDER: |
| 553 | return Optional.of( |
| 554 | new SubcomponentBuilderBindingExpression( |
| dstrasburg | 61274ab | 2018-09-26 08:11:04 -0700 | [diff] [blame] | 555 | resolvedBindings, |
| 556 | generatedComponentModel.getSubcomponentName(resolvedBindings.key()))); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 557 | |
| 558 | case MULTIBOUND_SET: |
| 559 | return Optional.of( |
| dstrasburg | 09adeae | 2018-09-07 12:11:06 -0700 | [diff] [blame] | 560 | new SetBindingExpression( |
| 561 | resolvedBindings, generatedComponentModel, graph, this, types, elements)); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 562 | |
| 563 | case MULTIBOUND_MAP: |
| 564 | return Optional.of( |
| dstrasburg | 09adeae | 2018-09-07 12:11:06 -0700 | [diff] [blame] | 565 | new MapBindingExpression( |
| 566 | resolvedBindings, generatedComponentModel, graph, this, types, elements)); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 567 | |
| 568 | case OPTIONAL: |
| 569 | return Optional.of(new OptionalBindingExpression(resolvedBindings, this, types)); |
| 570 | |
| 571 | case BOUND_INSTANCE: |
| 572 | return Optional.of( |
| 573 | new ComponentRequirementBindingExpression( |
| 574 | resolvedBindings, |
| 575 | ComponentRequirement.forBoundInstance(resolvedBindings.contributionBinding()), |
| 576 | componentRequirementFields)); |
| 577 | |
| 578 | case INJECTION: |
| 579 | case PROVISION: |
| 580 | return Optional.of( |
| 581 | new SimpleMethodBindingExpression( |
| 582 | resolvedBindings, |
| 583 | compilerOptions, |
| 584 | this, |
| 585 | membersInjectionMethods, |
| 586 | componentRequirementFields, |
| 587 | elements)); |
| 588 | |
| 589 | case MEMBERS_INJECTOR: |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 590 | return Optional.empty(); |
| 591 | |
| 592 | case MEMBERS_INJECTION: |
| 593 | case COMPONENT_PRODUCTION: |
| 594 | case PRODUCTION: |
| 595 | throw new IllegalArgumentException( |
| 596 | resolvedBindings.contributionBinding().kind().toString()); |
| 597 | } |
| 598 | throw new AssertionError(); |
| 599 | } |
| 600 | |
| 601 | /** |
| bcorso | af9e004 | 2018-04-16 14:12:23 -0700 | [diff] [blame] | 602 | * Returns {@code true} if the binding should use the static factory creation strategy. |
| 603 | * |
| dstrasburg | 6d2a7ad | 2018-09-05 08:05:51 -0700 | [diff] [blame] | 604 | * <p>In default mode, we always use the static factory creation strategy. In fastInit mode, we |
| bcorso | d55c02d | 2018-06-06 15:02:34 -0700 | [diff] [blame] | 605 | * prefer to use a SwitchingProvider instead of static factories in order to reduce class loading; |
| dstrasburg | 6d2a7ad | 2018-09-05 08:05:51 -0700 | [diff] [blame] | 606 | * however, we allow static factories that can reused across multiple bindings, e.g. {@code |
| 607 | * MapFactory} or {@code SetFactory}. |
| bcorso | af9e004 | 2018-04-16 14:12:23 -0700 | [diff] [blame] | 608 | */ |
| 609 | private boolean useStaticFactoryCreation(ContributionBinding binding) { |
| bcorso | d55c02d | 2018-06-06 15:02:34 -0700 | [diff] [blame] | 610 | return !(compilerOptions.experimentalAndroidMode2() || compilerOptions.fastInit()) |
| bcorso | af9e004 | 2018-04-16 14:12:23 -0700 | [diff] [blame] | 611 | || binding.kind().equals(MULTIBOUND_MAP) |
| 612 | || binding.kind().equals(MULTIBOUND_SET); |
| 613 | } |
| 614 | |
| 615 | /** |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 616 | * Returns {@code true} if we can use a direct (not {@code Provider.get()}) expression for this |
| 617 | * binding. If the binding doesn't {@linkplain #needsCaching(ResolvedBindings) need to be cached}, |
| 618 | * we can. |
| 619 | * |
| bcorso | d55c02d | 2018-06-06 15:02:34 -0700 | [diff] [blame] | 620 | * <p>In fastInit mode, we can use a direct expression even if the binding {@linkplain |
| ronshapiro | a72c342 | 2018-10-30 15:14:05 -0700 | [diff] [blame] | 621 | * #needsCaching(ResolvedBindings) needs to be cached}. |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 622 | */ |
| 623 | private boolean canUseDirectInstanceExpression(ResolvedBindings resolvedBindings) { |
| ronshapiro | a72c342 | 2018-10-30 15:14:05 -0700 | [diff] [blame] | 624 | return !needsCaching(resolvedBindings) || compilerOptions.fastInit(); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 625 | } |
| 626 | |
| 627 | /** |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 628 | * Returns a binding expression that uses a given one as the body of a method that users call. If |
| dstrasburg | 6d2a7ad | 2018-09-05 08:05:51 -0700 | [diff] [blame] | 629 | * a component provision method matches it, it will be the method implemented. If it does not |
| dpb | 10dcfba | 2018-09-20 09:08:38 -0700 | [diff] [blame] | 630 | * match a component provision method and the binding is modifiable, then a new public modifiable |
| 631 | * binding method will be written. If the binding doesn't match a component method and is not |
| dstrasburg | 6d2a7ad | 2018-09-05 08:05:51 -0700 | [diff] [blame] | 632 | * modifiable, then a new private method will be written. |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 633 | */ |
| dstrasburg | f0f6dfb | 2018-09-27 12:00:42 -0700 | [diff] [blame] | 634 | BindingExpression wrapInMethod( |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 635 | ResolvedBindings resolvedBindings, |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 636 | BindingRequest request, |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 637 | BindingExpression bindingExpression) { |
| dstrasburg | 09adeae | 2018-09-07 12:11:06 -0700 | [diff] [blame] | 638 | // If we've already wrapped the expression, then use the delegate. |
| 639 | if (bindingExpression instanceof MethodBindingExpression) { |
| 640 | return bindingExpression; |
| 641 | } |
| 642 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 643 | BindingMethodImplementation methodImplementation = |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 644 | methodImplementation(resolvedBindings, request, bindingExpression); |
| dstrasburg | 6d2a7ad | 2018-09-05 08:05:51 -0700 | [diff] [blame] | 645 | Optional<ComponentMethodDescriptor> matchingComponentMethod = |
| dstrasburg | f0f6dfb | 2018-09-27 12:00:42 -0700 | [diff] [blame] | 646 | graph.componentDescriptor().findMatchingComponentMethod(request); |
| dstrasburg | 9203183 | 2018-10-17 08:48:40 -0700 | [diff] [blame] | 647 | Optional<ModifiableBindingMethod> matchingModifiableBindingMethod = |
| 648 | generatedComponentModel.getModifiableBindingMethod(request); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 649 | |
| dstrasburg | f0f6dfb | 2018-09-27 12:00:42 -0700 | [diff] [blame] | 650 | Optional<BindingExpression> modifiableBindingExpression = |
| 651 | modifiableBindingExpressions.maybeWrapInModifiableMethodBindingExpression( |
| 652 | resolvedBindings, |
| 653 | request, |
| dstrasburg | f0f6dfb | 2018-09-27 12:00:42 -0700 | [diff] [blame] | 654 | methodImplementation, |
| dstrasburg | 9203183 | 2018-10-17 08:48:40 -0700 | [diff] [blame] | 655 | matchingComponentMethod, |
| 656 | matchingModifiableBindingMethod); |
| dstrasburg | f0f6dfb | 2018-09-27 12:00:42 -0700 | [diff] [blame] | 657 | if (modifiableBindingExpression.isPresent()) { |
| 658 | return modifiableBindingExpression.get(); |
| dstrasburg | 6d2a7ad | 2018-09-05 08:05:51 -0700 | [diff] [blame] | 659 | } |
| 660 | |
| 661 | return matchingComponentMethod |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 662 | .<BindingExpression>map( |
| 663 | componentMethod -> |
| 664 | new ComponentMethodBindingExpression( |
| dstrasburg | 9203183 | 2018-10-17 08:48:40 -0700 | [diff] [blame] | 665 | methodImplementation, |
| 666 | generatedComponentModel, |
| 667 | componentMethod, |
| 668 | matchingModifiableBindingMethod)) |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 669 | .orElseGet( |
| 670 | () -> |
| 671 | new PrivateMethodBindingExpression( |
| dstrasburg | 9203183 | 2018-10-17 08:48:40 -0700 | [diff] [blame] | 672 | resolvedBindings, |
| 673 | request, |
| 674 | methodImplementation, |
| 675 | generatedComponentModel, |
| 676 | matchingModifiableBindingMethod)); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 677 | } |
| 678 | |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 679 | private BindingMethodImplementation methodImplementation( |
| 680 | ResolvedBindings resolvedBindings, |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 681 | BindingRequest request, |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 682 | BindingExpression bindingExpression) { |
| bcorso | d55c02d | 2018-06-06 15:02:34 -0700 | [diff] [blame] | 683 | if (compilerOptions.fastInit()) { |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 684 | if (request.isRequestKind(RequestKind.PROVIDER)) { |
| bcorso | 567ff0e | 2018-03-21 13:49:09 -0700 | [diff] [blame] | 685 | return new SingleCheckedMethodImplementation( |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 686 | resolvedBindings, request, bindingExpression, types, generatedComponentModel); |
| 687 | } else if (request.isRequestKind(RequestKind.INSTANCE) && needsCaching(resolvedBindings)) { |
| bcorso | 567ff0e | 2018-03-21 13:49:09 -0700 | [diff] [blame] | 688 | return resolvedBindings.scope().get().isReusable() |
| 689 | ? new SingleCheckedMethodImplementation( |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 690 | resolvedBindings, request, bindingExpression, types, generatedComponentModel) |
| bcorso | 567ff0e | 2018-03-21 13:49:09 -0700 | [diff] [blame] | 691 | : new DoubleCheckedMethodImplementation( |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 692 | resolvedBindings, request, bindingExpression, types, generatedComponentModel); |
| bcorso | 567ff0e | 2018-03-21 13:49:09 -0700 | [diff] [blame] | 693 | } |
| 694 | } |
| 695 | |
| 696 | return new BindingMethodImplementation( |
| cgdecker | 60a5dde | 2018-09-07 08:44:34 -0700 | [diff] [blame] | 697 | resolvedBindings, request, bindingExpression, generatedComponentModel.name(), types); |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 698 | } |
| 699 | |
| 700 | /** |
| 701 | * Returns {@code true} if the component needs to make sure the provided value is cached. |
| 702 | * |
| 703 | * <p>The component needs to cache the value for scoped bindings except for {@code @Binds} |
| 704 | * bindings whose scope is no stronger than their delegate's. |
| 705 | */ |
| 706 | private boolean needsCaching(ResolvedBindings resolvedBindings) { |
| 707 | if (!resolvedBindings.scope().isPresent()) { |
| 708 | return false; |
| bcorso | 3828ca2 | 2018-01-29 10:14:12 -0800 | [diff] [blame] | 709 | } |
| dpb | 73afb30 | 2018-02-12 10:59:53 -0800 | [diff] [blame] | 710 | if (resolvedBindings.contributionBinding().kind().equals(DELEGATE)) { |
| 711 | return isBindsScopeStrongerThanDependencyScope(resolvedBindings, graph); |
| 712 | } |
| 713 | return true; |
| 714 | } |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 715 | } |