• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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 
19 import static com.google.common.base.Suppliers.memoize;
20 import static com.google.common.collect.Iterables.getOnlyElement;
21 import static dagger.internal.codegen.DaggerStreams.toImmutableList;
22 import static java.util.stream.Collectors.toSet;
23 import static javax.lang.model.element.Modifier.ABSTRACT;
24 import static javax.lang.model.element.Modifier.STATIC;
25 
26 import com.google.auto.value.AutoValue;
27 import com.google.common.base.Supplier;
28 import com.google.common.collect.ImmutableList;
29 import com.google.common.collect.ImmutableMap;
30 import com.google.common.collect.ImmutableSet;
31 import com.google.common.collect.ImmutableSetMultimap;
32 import com.google.common.collect.Lists;
33 import com.google.common.collect.Multimaps;
34 import com.google.common.collect.Sets;
35 import dagger.internal.codegen.langmodel.DaggerTypes;
36 import dagger.model.BindingKind;
37 import dagger.model.DependencyRequest;
38 import dagger.model.Key;
39 import dagger.model.Scope;
40 import java.util.Iterator;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Optional;
44 import java.util.Set;
45 import javax.lang.model.element.Element;
46 import javax.lang.model.element.Modifier;
47 import javax.lang.model.element.TypeElement;
48 import javax.lang.model.element.TypeParameterElement;
49 import javax.lang.model.type.DeclaredType;
50 import javax.lang.model.type.TypeMirror;
51 import javax.lang.model.util.SimpleTypeVisitor6;
52 
53 /**
54  * An abstract type for classes representing a Dagger binding. Particularly, contains the {@link
55  * Element} that generated the binding and the {@link DependencyRequest} instances that are required
56  * to satisfy the binding, but leaves the specifics of the <i>mechanism</i> of the binding to the
57  * subtypes.
58  */
59 abstract class Binding extends BindingDeclaration {
60 
61   /**
62    * Returns {@code true} if using this binding requires an instance of the {@link
63    * #contributingModule()}.
64    */
requiresModuleInstance()65   boolean requiresModuleInstance() {
66     if (!bindingElement().isPresent() || !contributingModule().isPresent()) {
67       return false;
68     }
69     Set<Modifier> modifiers = bindingElement().get().getModifiers();
70     return !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC);
71   }
72 
73   /**
74    * Returns {@code true} if this binding may provide {@code null} instead of an instance of {@link
75    * #key()}. Nullable bindings cannot be requested from {@linkplain DependencyRequest#isNullable()
76    * non-nullable dependency requests}.
77    */
isNullable()78   abstract boolean isNullable();
79 
80   /** The kind of binding this instance represents. */
kind()81   abstract BindingKind kind();
82 
83   /** The {@link BindingType} of this binding. */
bindingType()84   abstract BindingType bindingType();
85 
86   /** The {@link FrameworkType} of this binding. */
frameworkType()87   final FrameworkType frameworkType() {
88     return FrameworkType.forBindingType(bindingType());
89   }
90 
91   /**
92    * The explicit set of {@link DependencyRequest dependencies} required to satisfy this binding as
93    * defined by the user-defined injection sites.
94    */
explicitDependencies()95   abstract ImmutableSet<DependencyRequest> explicitDependencies();
96 
97   /**
98    * The set of {@link DependencyRequest dependencies} that are added by the framework rather than a
99    * user-defined injection site. This returns an unmodifiable set.
100    */
101   // TODO(gak): this will eventually get changed to return a set of FrameworkDependency
implicitDependencies()102   ImmutableSet<DependencyRequest> implicitDependencies() {
103     return ImmutableSet.of();
104   }
105 
106   private final Supplier<ImmutableSet<DependencyRequest>> dependencies =
107       memoize(
108           () -> {
109             ImmutableSet<DependencyRequest> implicitDependencies = implicitDependencies();
110             return ImmutableSet.copyOf(
111                 implicitDependencies.isEmpty()
112                     ? explicitDependencies()
113                     : Sets.union(implicitDependencies, explicitDependencies()));
114           });
115 
116   /**
117    * The set of {@link DependencyRequest dependencies} required to satisfy this binding. This is the
118    * union of {@link #explicitDependencies()} and {@link #implicitDependencies()}. This returns an
119    * unmodifiable set.
120    */
dependencies()121   final ImmutableSet<DependencyRequest> dependencies() {
122     return dependencies.get();
123   }
124 
125   private final Supplier<ImmutableList<FrameworkDependency>> frameworkDependencies =
126       memoize(
127           () ->
128               dependencyAssociations()
129                   .stream()
130                   .map(DependencyAssociation::frameworkDependency)
131                   .collect(toImmutableList()));
132 
133   /**
134    * The framework dependencies of {@code binding}. There will be one element for each different
135    * binding key in the <em>{@linkplain Binding#unresolved() unresolved}</em> version of {@code
136    * binding}.
137    *
138    * <p>For example, given the following modules:
139    *
140    * <pre><code>
141    *   {@literal @Module} abstract class {@literal BaseModule<T>} {
142    *     {@literal @Provides} Foo provideFoo(T t, String string) {
143    *       return …;
144    *     }
145    *   }
146    *
147    *   {@literal @Module} class StringModule extends {@literal BaseModule<String>} {}
148    * </code></pre>
149    *
150    * Both dependencies of {@code StringModule.provideFoo} have the same binding key: {@code String}.
151    * But there are still two dependencies, because in the unresolved binding they have different
152    * binding keys:
153    *
154    * <dl>
155    *   <dt>{@code T}
156    *   <dd>{@code String t}
157    *   <dt>{@code String}
158    *   <dd>{@code String string}
159    * </dl>
160    *
161    * <p>Note that the sets returned by this method when called on the same binding will be equal,
162    * and their elements will be in the same order.
163    */
164   /* TODO(dpb): The stable-order postcondition is actually hard to verify in code for two equal
165    * instances of Binding, because it really depends on the order of the binding's dependencies,
166    * and two equal instances of Binding may have the same dependencies in a different order. */
frameworkDependencies()167   final ImmutableList<FrameworkDependency> frameworkDependencies() {
168     return frameworkDependencies.get();
169   }
170 
171   /**
172    * Associates a {@link FrameworkDependency} with the set of {@link DependencyRequest} instances
173    * that correlate for a binding.
174    */
175   @AutoValue
176   abstract static class DependencyAssociation {
frameworkDependency()177     abstract FrameworkDependency frameworkDependency();
178 
dependencyRequests()179     abstract ImmutableSet<DependencyRequest> dependencyRequests();
180 
create( FrameworkDependency frameworkDependency, Iterable<DependencyRequest> dependencyRequests)181     static DependencyAssociation create(
182         FrameworkDependency frameworkDependency, Iterable<DependencyRequest> dependencyRequests) {
183       return new AutoValue_Binding_DependencyAssociation(
184           frameworkDependency, ImmutableSet.copyOf(dependencyRequests));
185     }
186   }
187 
188   private final Supplier<ImmutableList<DependencyAssociation>> dependencyAssociations =
189       memoize(
190           () -> {
191             FrameworkTypeMapper frameworkTypeMapper =
192                 FrameworkTypeMapper.forBindingType(bindingType());
193             ImmutableList.Builder<DependencyAssociation> list = ImmutableList.builder();
194             for (Set<DependencyRequest> requests : groupByUnresolvedKey()) {
195               list.add(
196                   DependencyAssociation.create(
197                       FrameworkDependency.create(
198                           getOnlyElement(
199                               requests.stream().map(DependencyRequest::key).collect(toSet())),
200                           frameworkTypeMapper.getFrameworkType(requests)),
201                       requests));
202             }
203             return list.build();
204           });
205 
206   /**
207    * Returns the same {@link FrameworkDependency} instances from {@link #frameworkDependencies}, but
208    * with the set of {@link DependencyRequest} instances with which each is associated.
209    *
210    * <p>Ths method returns a list of {@link Map.Entry entries} rather than a {@link Map} or {@link
211    * com.google.common.collect.Multimap} because any given {@link FrameworkDependency} may appear
212    * multiple times if the {@linkplain Binding#unresolved() unresolved} binding requires it. If that
213    * distinction is not important, the entries can be merged into a single mapping.
214    */
dependencyAssociations()215   final ImmutableList<DependencyAssociation> dependencyAssociations() {
216     return dependencyAssociations.get();
217   }
218 
219   private final Supplier<ImmutableMap<DependencyRequest, FrameworkDependency>>
220       frameworkDependenciesMap =
221           memoize(
222               () -> {
223                 ImmutableMap.Builder<DependencyRequest, FrameworkDependency> frameworkDependencies =
224                     ImmutableMap.builder();
225                 for (DependencyAssociation dependencyAssociation : dependencyAssociations()) {
226                   for (DependencyRequest dependencyRequest :
227                       dependencyAssociation.dependencyRequests()) {
228                     frameworkDependencies.put(
229                         dependencyRequest, dependencyAssociation.frameworkDependency());
230                   }
231                 }
232                 return frameworkDependencies.build();
233               });
234 
235   /**
236    * Returns the mapping from each {@linkplain #dependencies dependency} to its associated {@link
237    * FrameworkDependency}.
238    */
239   final ImmutableMap<DependencyRequest, FrameworkDependency>
dependenciesToFrameworkDependenciesMap()240       dependenciesToFrameworkDependenciesMap() {
241     return frameworkDependenciesMap.get();
242   }
243 
244   /**
245    * Groups {@code binding}'s implicit dependencies by their binding key, using the dependency keys
246    * from the {@link Binding#unresolved()} binding if it exists.
247    */
groupByUnresolvedKey()248   private ImmutableList<Set<DependencyRequest>> groupByUnresolvedKey() {
249     ImmutableSetMultimap.Builder<Key, DependencyRequest> dependenciesByKeyBuilder =
250         ImmutableSetMultimap.builder();
251     Iterator<DependencyRequest> dependencies = dependencies().iterator();
252     Binding unresolved = unresolved().isPresent() ? unresolved().get() : this;
253     Iterator<DependencyRequest> unresolvedDependencies = unresolved.dependencies().iterator();
254     while (dependencies.hasNext()) {
255       dependenciesByKeyBuilder.put(unresolvedDependencies.next().key(), dependencies.next());
256     }
257     return ImmutableList.copyOf(
258         Multimaps.asMap(
259                 dependenciesByKeyBuilder.orderValuesBy(SourceFiles.DEPENDENCY_ORDERING).build())
260             .values());
261   }
262 
263   /**
264    * If this binding's key's type parameters are different from those of the
265    * {@link #bindingTypeElement()}, this is the binding for the {@link #bindingTypeElement()}'s
266    * unresolved type.
267    */
unresolved()268   abstract Optional<? extends Binding> unresolved();
269 
scope()270   Optional<Scope> scope() {
271     return Optional.empty();
272   }
273 
274   // TODO(sameb): Remove the TypeElement parameter and pull it from the TypeMirror.
hasNonDefaultTypeParameters( TypeElement element, TypeMirror type, DaggerTypes types)275   static boolean hasNonDefaultTypeParameters(
276       TypeElement element, TypeMirror type, DaggerTypes types) {
277     // If the element has no type parameters, nothing can be wrong.
278     if (element.getTypeParameters().isEmpty()) {
279       return false;
280     }
281 
282     List<TypeMirror> defaultTypes = Lists.newArrayList();
283     for (TypeParameterElement parameter : element.getTypeParameters()) {
284       defaultTypes.add(parameter.asType());
285     }
286 
287     List<TypeMirror> actualTypes =
288         type.accept(
289             new SimpleTypeVisitor6<List<TypeMirror>, Void>() {
290               @Override
291               protected List<TypeMirror> defaultAction(TypeMirror e, Void p) {
292                 return ImmutableList.of();
293               }
294 
295               @Override
296               public List<TypeMirror> visitDeclared(DeclaredType t, Void p) {
297                 return ImmutableList.<TypeMirror>copyOf(t.getTypeArguments());
298               }
299             },
300             null);
301 
302     // The actual type parameter size can be different if the user is using a raw type.
303     if (defaultTypes.size() != actualTypes.size()) {
304       return true;
305     }
306 
307     for (int i = 0; i < defaultTypes.size(); i++) {
308       if (!types.isSameType(defaultTypes.get(i), actualTypes.get(i))) {
309         return true;
310       }
311     }
312     return false;
313   }
314 }
315