| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 The Dagger Authors. |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package dagger.internal.codegen; |
| 18 | |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 19 | import static com.google.common.base.Preconditions.checkNotNull; |
| erichang | 4377417 | 2017-08-04 10:42:07 -0700 | [diff] [blame] | 20 | import static dagger.internal.codegen.AnnotationSpecs.Suppression.RAWTYPES; |
| dpb | b5ae249 | 2017-08-18 14:58:23 -0700 | [diff] [blame] | 21 | import static dagger.internal.codegen.FrameworkInstanceBindingExpression.producerFromProviderBindingExpression; |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 22 | import static dagger.internal.codegen.MemberSelect.staticMemberSelect; |
| erichang | 4377417 | 2017-08-04 10:42:07 -0700 | [diff] [blame] | 23 | import static dagger.internal.codegen.TypeNames.PRODUCER; |
| 24 | import static javax.lang.model.element.Modifier.PRIVATE; |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 25 | |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 26 | import com.google.common.collect.ImmutableMap; |
| 27 | import com.squareup.javapoet.ClassName; |
| 28 | import com.squareup.javapoet.CodeBlock; |
| 29 | import com.squareup.javapoet.FieldSpec; |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 30 | import java.util.Optional; |
| ronshapiro | cb725da | 2017-07-04 15:14:48 -0700 | [diff] [blame] | 31 | import javax.lang.model.util.Elements; |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 32 | |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 33 | /** A factory of code expressions used to access a single binding in a component. */ |
| ronshapiro | 186d17a | 2017-08-11 08:18:07 -0700 | [diff] [blame] | 34 | abstract class BindingExpression { |
| dpb | b5ae249 | 2017-08-18 14:58:23 -0700 | [diff] [blame] | 35 | // TODO(dpb): Put the Binding or ResolvedBindings itself here. |
| ronshapiro | 186d17a | 2017-08-11 08:18:07 -0700 | [diff] [blame] | 36 | private final BindingKey bindingKey; |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 37 | |
| ronshapiro | 186d17a | 2017-08-11 08:18:07 -0700 | [diff] [blame] | 38 | BindingExpression(BindingKey bindingKey) { |
| 39 | this.bindingKey = checkNotNull(bindingKey); |
| dpb | 02dd23f | 2017-07-27 11:13:11 -0700 | [diff] [blame] | 40 | } |
| 41 | |
| ronshapiro | 186d17a | 2017-08-11 08:18:07 -0700 | [diff] [blame] | 42 | /** The key for which this instance can fulfill requests. */ |
| 43 | final BindingKey bindingKey() { |
| 44 | return bindingKey; |
| dpb | 02dd23f | 2017-07-27 11:13:11 -0700 | [diff] [blame] | 45 | } |
| 46 | |
| 47 | /** |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 48 | * Returns an expression that evaluates to the value of a request for a given kind of dependency |
| 49 | * on this binding. |
| dpb | a6ff6c1 | 2017-08-14 08:47:36 -0700 | [diff] [blame] | 50 | * |
| 51 | * @param requestingClass the class that will contain the expression |
| dpb | 02dd23f | 2017-07-27 11:13:11 -0700 | [diff] [blame] | 52 | */ |
| dpb | a6ff6c1 | 2017-08-14 08:47:36 -0700 | [diff] [blame] | 53 | abstract CodeBlock getDependencyExpression( |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 54 | DependencyRequest.Kind requestKind, ClassName requestingClass); |
| dpb | a6ff6c1 | 2017-08-14 08:47:36 -0700 | [diff] [blame] | 55 | |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 56 | /** Factory for building a {@link BindingExpression}. */ |
| 57 | static final class Factory { |
| dpb | c8c6c05 | 2017-07-28 10:48:06 -0700 | [diff] [blame] | 58 | private final CompilerOptions compilerOptions; |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 59 | private final ClassName componentName; |
| erichang | 4377417 | 2017-08-04 10:42:07 -0700 | [diff] [blame] | 60 | private final UniqueNameSet componentFieldNames; |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 61 | private final ComponentBindingExpressions componentBindingExpressions; |
| 62 | private final GeneratedComponentModel generatedComponentModel; |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 63 | private final ImmutableMap<BindingKey, String> subcomponentNames; |
| 64 | private final BindingGraph graph; |
| ronshapiro | cb725da | 2017-07-04 15:14:48 -0700 | [diff] [blame] | 65 | private final Elements elements; |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 66 | |
| 67 | Factory( |
| dpb | c8c6c05 | 2017-07-28 10:48:06 -0700 | [diff] [blame] | 68 | CompilerOptions compilerOptions, |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 69 | ClassName componentName, |
| erichang | 4377417 | 2017-08-04 10:42:07 -0700 | [diff] [blame] | 70 | UniqueNameSet componentFieldNames, |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 71 | ComponentBindingExpressions componentBindingExpressions, |
| 72 | GeneratedComponentModel generatedComponentModel, |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 73 | ImmutableMap<BindingKey, String> subcomponentNames, |
| ronshapiro | cb725da | 2017-07-04 15:14:48 -0700 | [diff] [blame] | 74 | BindingGraph graph, |
| 75 | Elements elements) { |
| dpb | c8c6c05 | 2017-07-28 10:48:06 -0700 | [diff] [blame] | 76 | this.compilerOptions = checkNotNull(compilerOptions); |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 77 | this.componentName = checkNotNull(componentName); |
| erichang | 4377417 | 2017-08-04 10:42:07 -0700 | [diff] [blame] | 78 | this.componentFieldNames = checkNotNull(componentFieldNames); |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 79 | this.componentBindingExpressions = checkNotNull(componentBindingExpressions); |
| 80 | this.generatedComponentModel = checkNotNull(generatedComponentModel); |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 81 | this.subcomponentNames = checkNotNull(subcomponentNames); |
| 82 | this.graph = checkNotNull(graph); |
| ronshapiro | e05f921 | 2017-08-08 11:22:11 -0700 | [diff] [blame] | 83 | this.elements = checkNotNull(elements); |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 84 | } |
| 85 | |
| 86 | /** Creates a binding expression for a field. */ |
| erichang | 4377417 | 2017-08-04 10:42:07 -0700 | [diff] [blame] | 87 | BindingExpression forField(ResolvedBindings resolvedBindings) { |
| 88 | FieldSpec fieldSpec = generateFrameworkField(resolvedBindings, Optional.empty()); |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 89 | MemberSelect memberSelect = MemberSelect.localField(componentName, fieldSpec.name); |
| ronshapiro | 186d17a | 2017-08-11 08:18:07 -0700 | [diff] [blame] | 90 | return create(resolvedBindings, Optional.of(fieldSpec), memberSelect); |
| erichang | 4377417 | 2017-08-04 10:42:07 -0700 | [diff] [blame] | 91 | } |
| 92 | |
| dpb | b5ae249 | 2017-08-18 14:58:23 -0700 | [diff] [blame] | 93 | FrameworkInstanceBindingExpression forProducerFromProviderField( |
| 94 | ResolvedBindings resolvedBindings) { |
| erichang | 4377417 | 2017-08-04 10:42:07 -0700 | [diff] [blame] | 95 | FieldSpec fieldSpec = generateFrameworkField(resolvedBindings, Optional.of(PRODUCER)); |
| 96 | MemberSelect memberSelect = MemberSelect.localField(componentName, fieldSpec.name); |
| dpb | b5ae249 | 2017-08-18 14:58:23 -0700 | [diff] [blame] | 97 | return producerFromProviderBindingExpression( |
| ronshapiro | 186d17a | 2017-08-11 08:18:07 -0700 | [diff] [blame] | 98 | resolvedBindings.bindingKey(), |
| erichang | 4377417 | 2017-08-04 10:42:07 -0700 | [diff] [blame] | 99 | Optional.of(fieldSpec), |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 100 | generatedComponentModel, |
| dpb | b5ae249 | 2017-08-18 14:58:23 -0700 | [diff] [blame] | 101 | memberSelect); |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 102 | } |
| 103 | |
| dpb | 68c77d8 | 2017-08-15 15:23:35 -0700 | [diff] [blame] | 104 | /** Creates a binding expression for a static method call. */ |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 105 | Optional<BindingExpression> forStaticMethod(ResolvedBindings resolvedBindings) { |
| ronshapiro | 186d17a | 2017-08-11 08:18:07 -0700 | [diff] [blame] | 106 | return staticMemberSelect(resolvedBindings) |
| 107 | .map(memberSelect -> create(resolvedBindings, Optional.empty(), memberSelect)); |
| erichang | 4377417 | 2017-08-04 10:42:07 -0700 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | /** |
| 111 | * Adds a field representing the resolved bindings, optionally forcing it to use a particular |
| 112 | * binding type (instead of the type the resolved bindings would typically use). |
| 113 | */ |
| 114 | private FieldSpec generateFrameworkField( |
| 115 | ResolvedBindings resolvedBindings, Optional<ClassName> frameworkClass) { |
| 116 | boolean useRawType = useRawType(resolvedBindings); |
| 117 | |
| 118 | FrameworkField contributionBindingField = |
| 119 | FrameworkField.forResolvedBindings(resolvedBindings, frameworkClass); |
| 120 | FieldSpec.Builder contributionField = |
| 121 | FieldSpec.builder( |
| 122 | useRawType |
| 123 | ? contributionBindingField.type().rawType |
| 124 | : contributionBindingField.type(), |
| 125 | componentFieldNames.getUniqueName(contributionBindingField.name())); |
| 126 | contributionField.addModifiers(PRIVATE); |
| 127 | if (useRawType) { |
| 128 | contributionField.addAnnotation(AnnotationSpecs.suppressWarnings(RAWTYPES)); |
| 129 | } |
| 130 | |
| 131 | return contributionField.build(); |
| 132 | } |
| 133 | |
| 134 | private boolean useRawType(ResolvedBindings resolvedBindings) { |
| 135 | Optional<String> bindingPackage = resolvedBindings.bindingPackage(); |
| 136 | return bindingPackage.isPresent() |
| 137 | && !bindingPackage.get().equals(componentName.packageName()); |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 138 | } |
| 139 | |
| ronshapiro | 186d17a | 2017-08-11 08:18:07 -0700 | [diff] [blame] | 140 | private BindingExpression create( |
| 141 | ResolvedBindings resolvedBindings, |
| 142 | Optional<FieldSpec> fieldSpec, |
| 143 | MemberSelect memberSelect) { |
| dpb | b5ae249 | 2017-08-18 14:58:23 -0700 | [diff] [blame] | 144 | FrameworkInstanceBindingExpression bindingExpression = |
| 145 | FrameworkInstanceBindingExpression.create( |
| 146 | resolvedBindings, fieldSpec, generatedComponentModel, memberSelect); |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 147 | |
| dpb | b5ae249 | 2017-08-18 14:58:23 -0700 | [diff] [blame] | 148 | if (!resolvedBindings.bindingType().equals(BindingType.PROVISION)) { |
| 149 | return bindingExpression; |
| 150 | } |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 151 | |
| dpb | b5ae249 | 2017-08-18 14:58:23 -0700 | [diff] [blame] | 152 | ProvisionBinding provisionBinding = (ProvisionBinding) resolvedBindings.contributionBinding(); |
| 153 | switch (provisionBinding.bindingKind()) { |
| 154 | case SUBCOMPONENT_BUILDER: |
| 155 | return new SubcomponentBuilderBindingExpression( |
| 156 | bindingExpression, subcomponentNames.get(resolvedBindings.bindingKey())); |
| 157 | case SYNTHETIC_MULTIBOUND_SET: |
| 158 | return new SetBindingExpression( |
| 159 | provisionBinding, graph, componentBindingExpressions, bindingExpression, elements); |
| 160 | case SYNTHETIC_OPTIONAL_BINDING: |
| 161 | return new OptionalBindingExpression( |
| 162 | provisionBinding, bindingExpression, componentBindingExpressions); |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 163 | case INJECTION: |
| dpb | b5ae249 | 2017-08-18 14:58:23 -0700 | [diff] [blame] | 164 | case PROVISION: |
| 165 | if (!provisionBinding.scope().isPresent() |
| 166 | && !provisionBinding.requiresModuleInstance() |
| 167 | && provisionBinding.bindingElement().isPresent()) { |
| 168 | return new SimpleMethodBindingExpression( |
| 169 | compilerOptions, |
| 170 | provisionBinding, |
| 171 | bindingExpression, |
| 172 | componentBindingExpressions, |
| 173 | generatedComponentModel); |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 174 | } |
| dpb | b5ae249 | 2017-08-18 14:58:23 -0700 | [diff] [blame] | 175 | // fall through |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 176 | default: |
| dpb | b5ae249 | 2017-08-18 14:58:23 -0700 | [diff] [blame] | 177 | return bindingExpression; |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 178 | } |
| 179 | } |
| 180 | } |
| erichang | 9dd6aed | 2017-06-15 15:54:00 -0700 | [diff] [blame] | 181 | } |