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